examples/sfexamples/oggvorbiscodec/src/libvorbis/lib/vorbisenc.c

00001 /********************************************************************
00002  *                                                                  *
00003  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
00004  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
00005  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
00006  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
00007  *                                                                  *
00008  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
00009  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
00010  *                                                                  *
00011  ********************************************************************
00012 
00013  function: simple programmatic interface for encoder mode setup
00014  last mod: $Id: vorbisenc.c 9033 2005-03-04 04:33:03Z msmith $
00015 
00016  ********************************************************************/
00017 
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #include <math.h>
00021 
00022 #include "vorbis/codec.h"
00023 #include "vorbis/vorbisenc.h"
00024 
00025 #include "codec_internal.h"
00026 
00027 #include "os.h"
00028 #include "misc.h"
00029 
00030 /* careful with this; it's using static array sizing to make managing
00031    all the modes a little less annoying.  If we use a residue backend
00032    with > 12 partition types, or a different division of iteration,
00033    this needs to be updated. */
00034 typedef struct {
00035   static_codebook *books[12][3];
00036 } static_bookblock;
00037 
00038 typedef struct {
00039   int res_type;
00040   int limit_type; /* 0 lowpass limited, 1 point stereo limited */
00041   vorbis_info_residue0 *res;
00042   static_codebook  *book_aux;
00043   static_codebook  *book_aux_managed;
00044   static_bookblock *books_base;
00045   static_bookblock *books_base_managed;
00046 } vorbis_residue_template;
00047 
00048 typedef struct {
00049   vorbis_info_mapping0    *map;
00050   vorbis_residue_template *res;
00051 } vorbis_mapping_template;
00052 
00053 typedef struct vp_adjblock{
00054   int block[P_BANDS];
00055 } vp_adjblock;
00056 
00057 typedef struct {
00058   int data[NOISE_COMPAND_LEVELS];
00059 } compandblock;
00060 
00061 /* high level configuration information for setting things up
00062    step-by-step with the detailed vorbis_encode_ctl interface.
00063    There's a fair amount of redundancy such that interactive setup
00064    does not directly deal with any vorbis_info or codec_setup_info
00065    initialization; it's all stored (until full init) in this highlevel
00066    setup, then flushed out to the real codec setup structs later. */
00067 
00068 typedef struct {
00069   int att[P_NOISECURVES];
00070   float boost;
00071   float decay;
00072 } att3;
00073 typedef struct { int data[P_NOISECURVES]; } adj3; 
00074 
00075 typedef struct {
00076   int   pre[PACKETBLOBS];
00077   int   post[PACKETBLOBS];
00078   float kHz[PACKETBLOBS];
00079   float lowpasskHz[PACKETBLOBS];
00080 } adj_stereo;
00081 
00082 typedef struct {
00083   int lo;
00084   int hi;
00085   int fixed;
00086 } noiseguard;
00087 typedef struct {
00088   int data[P_NOISECURVES][17];
00089 } noise3;
00090 
00091 typedef struct {
00092   int      mappings;
00093   double  *rate_mapping;
00094   double  *quality_mapping;
00095   int      coupling_restriction;
00096   long     samplerate_min_restriction;
00097   long     samplerate_max_restriction;
00098 
00099 
00100   int     *blocksize_short;
00101   int     *blocksize_long;
00102 
00103   att3    *psy_tone_masteratt;
00104   int     *psy_tone_0dB;
00105   int     *psy_tone_dBsuppress;
00106 
00107   vp_adjblock *psy_tone_adj_impulse;
00108   vp_adjblock *psy_tone_adj_long;
00109   vp_adjblock *psy_tone_adj_other;
00110 
00111   noiseguard  *psy_noiseguards;
00112   noise3      *psy_noise_bias_impulse;
00113   noise3      *psy_noise_bias_padding;
00114   noise3      *psy_noise_bias_trans;
00115   noise3      *psy_noise_bias_long;
00116   int         *psy_noise_dBsuppress;
00117 
00118   compandblock  *psy_noise_compand;
00119   double        *psy_noise_compand_short_mapping;
00120   double        *psy_noise_compand_long_mapping;
00121 
00122   int      *psy_noise_normal_start[2];
00123   int      *psy_noise_normal_partition[2];
00124   double   *psy_noise_normal_thresh;
00125 
00126   int      *psy_ath_float;
00127   int      *psy_ath_abs;
00128 
00129   double   *psy_lowpass;
00130 
00131   vorbis_info_psy_global *global_params;
00132   double     *global_mapping;
00133   adj_stereo *stereo_modes;
00134 
00135   static_codebook ***floor_books;
00136   vorbis_info_floor1 *floor_params;
00137   int *floor_short_mapping;
00138   int *floor_long_mapping;
00139 
00140   vorbis_mapping_template *maps;
00141 } ve_setup_data_template;
00142 
00143 /* a few static coder conventions */
00144 static vorbis_info_mode _mode_template[2]={
00145   {0,0,0,0},
00146   {1,0,0,1}
00147 };
00148 
00149 static vorbis_info_mapping0 _map_nominal[2]={
00150   {1, {0,0}, {0}, {0}, 1,{0},{1}},
00151   {1, {0,0}, {1}, {1}, 1,{0},{1}}
00152 };
00153 
00154 #include "modes/setup_44.h"
00155 #include "modes/setup_44u.h"
00156 #include "modes/setup_32.h"
00157 #include "modes/setup_8.h"
00158 #include "modes/setup_11.h"
00159 #include "modes/setup_16.h"
00160 #include "modes/setup_22.h"
00161 #include "modes/setup_X.h"
00162 
00163 static ve_setup_data_template *setup_list[]={
00164   &ve_setup_44_stereo,
00165   &ve_setup_44_uncoupled,
00166 
00167   &ve_setup_32_stereo,
00168   &ve_setup_32_uncoupled,
00169 
00170   &ve_setup_22_stereo,
00171   &ve_setup_22_uncoupled,
00172   &ve_setup_16_stereo,
00173   &ve_setup_16_uncoupled,
00174 
00175   &ve_setup_11_stereo,
00176   &ve_setup_11_uncoupled,
00177   &ve_setup_8_stereo,
00178   &ve_setup_8_uncoupled,
00179 
00180   &ve_setup_X_stereo,
00181   &ve_setup_X_uncoupled,
00182   &ve_setup_XX_stereo,
00183   &ve_setup_XX_uncoupled,
00184   0
00185 };
00186 
00187 static int vorbis_encode_toplevel_setup(vorbis_info *vi,int ch,long rate){
00188   if(vi && vi->codec_setup){
00189 
00190     vi->version=0;
00191     vi->channels=ch;
00192     vi->rate=rate;
00193 
00194     return(0);
00195   }
00196   return(OV_EINVAL);
00197 }
00198 
00199 static void vorbis_encode_floor_setup(vorbis_info *vi,double s,int block,
00200                                      static_codebook    ***books, 
00201                                      vorbis_info_floor1 *in, 
00202                                      int *x){
00203   int i,k,is=s;
00204   vorbis_info_floor1 *f=(vorbis_info_floor1*)_ogg_calloc(1,sizeof(*f));
00205   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00206 
00207   memcpy(f,in+x[is],sizeof(*f));
00208   /* fill in the lowpass field, even if it's temporary */
00209   f->n=ci->blocksizes[block]>>1;
00210 
00211   /* books */
00212   {
00213     int partitions=f->partitions;
00214     int maxclass=-1;
00215     int maxbook=-1;
00216     for(i=0;i<partitions;i++)
00217       if(f->partitionclass[i]>maxclass)maxclass=f->partitionclass[i];
00218     for(i=0;i<=maxclass;i++){
00219       if(f->class_book[i]>maxbook)maxbook=f->class_book[i];
00220       f->class_book[i]+=ci->books;
00221       for(k=0;k<(1<<f->class_subs[i]);k++){
00222         if(f->class_subbook[i][k]>maxbook)maxbook=f->class_subbook[i][k];
00223         if(f->class_subbook[i][k]>=0)f->class_subbook[i][k]+=ci->books;
00224       }
00225     }
00226 
00227     for(i=0;i<=maxbook;i++)
00228       ci->book_param[ci->books++]=books[x[is]][i];
00229   }
00230 
00231   /* for now, we're only using floor 1 */
00232   ci->floor_type[ci->floors]=1;
00233   ci->floor_param[ci->floors]=f;
00234   ci->floors++;
00235 
00236   return;
00237 }
00238 
00239 static void vorbis_encode_global_psych_setup(vorbis_info *vi,double s,
00240                                             vorbis_info_psy_global *in, 
00241                                             double *x){
00242   int i,is=s;
00243   double ds=s-is;
00244   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00245   vorbis_info_psy_global *g=&ci->psy_g_param;
00246   
00247   memcpy(g,in+(int)x[is],sizeof(*g));
00248   
00249   ds=x[is]*(1.-ds)+x[is+1]*ds;
00250   is=(int)ds;
00251   ds-=is;
00252   if(ds==0 && is>0){
00253     is--;
00254     ds=1.;
00255   }
00256   
00257   /* interpolate the trigger threshholds */
00258   for(i=0;i<4;i++){
00259     g->preecho_thresh[i]=in[is].preecho_thresh[i]*(1.-ds)+in[is+1].preecho_thresh[i]*ds;
00260     g->postecho_thresh[i]=in[is].postecho_thresh[i]*(1.-ds)+in[is+1].postecho_thresh[i]*ds;
00261   }
00262   g->ampmax_att_per_sec=ci->hi.amplitude_track_dBpersec;
00263   return;
00264 }
00265 
00266 static void vorbis_encode_global_stereo(vorbis_info *vi,
00267                                        highlevel_encode_setup *hi,
00268                                        adj_stereo *p){
00269   float s=hi->stereo_point_setting;
00270   int i,is=s;
00271   double ds=s-is;
00272   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00273   vorbis_info_psy_global *g=&ci->psy_g_param;
00274 
00275   if(p){
00276     memcpy(g->coupling_prepointamp,p[is].pre,sizeof(*p[is].pre)*PACKETBLOBS);
00277     memcpy(g->coupling_postpointamp,p[is].post,sizeof(*p[is].post)*PACKETBLOBS);
00278 
00279     if(hi->managed){
00280       /* interpolate the kHz threshholds */
00281       for(i=0;i<PACKETBLOBS;i++){
00282         float kHz=p[is].kHz[i]*(1.-ds)+p[is+1].kHz[i]*ds;
00283         g->coupling_pointlimit[0][i]=kHz*1000./vi->rate*ci->blocksizes[0];
00284         g->coupling_pointlimit[1][i]=kHz*1000./vi->rate*ci->blocksizes[1];
00285         g->coupling_pkHz[i]=kHz;
00286         
00287         kHz=p[is].lowpasskHz[i]*(1.-ds)+p[is+1].lowpasskHz[i]*ds;
00288         g->sliding_lowpass[0][i]=kHz*1000./vi->rate*ci->blocksizes[0];
00289         g->sliding_lowpass[1][i]=kHz*1000./vi->rate*ci->blocksizes[1];
00290         
00291       }
00292     }else{
00293       float kHz=p[is].kHz[PACKETBLOBS/2]*(1.-ds)+p[is+1].kHz[PACKETBLOBS/2]*ds;
00294       for(i=0;i<PACKETBLOBS;i++){
00295         g->coupling_pointlimit[0][i]=kHz*1000./vi->rate*ci->blocksizes[0];
00296         g->coupling_pointlimit[1][i]=kHz*1000./vi->rate*ci->blocksizes[1];
00297         g->coupling_pkHz[i]=kHz;
00298       }
00299       
00300       kHz=p[is].lowpasskHz[PACKETBLOBS/2]*(1.-ds)+p[is+1].lowpasskHz[PACKETBLOBS/2]*ds;
00301       for(i=0;i<PACKETBLOBS;i++){
00302         g->sliding_lowpass[0][i]=kHz*1000./vi->rate*ci->blocksizes[0];
00303         g->sliding_lowpass[1][i]=kHz*1000./vi->rate*ci->blocksizes[1];
00304       }
00305     }
00306   }else{
00307     for(i=0;i<PACKETBLOBS;i++){
00308       g->sliding_lowpass[0][i]=ci->blocksizes[0];
00309       g->sliding_lowpass[1][i]=ci->blocksizes[1];
00310     }
00311   }
00312   return;
00313 }
00314 
00315 static void vorbis_encode_psyset_setup(vorbis_info *vi,double s,
00316                                       int *nn_start,
00317                                       int *nn_partition,
00318                                       double *nn_thresh,
00319                                       int block){
00320   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00321   vorbis_info_psy *p=ci->psy_param[block];
00322   highlevel_encode_setup *hi=&ci->hi;
00323   int is=s;
00324   
00325   if(block>=ci->psys)
00326     ci->psys=block+1;
00327   if(!p){
00328     p=(vorbis_info_psy*)_ogg_calloc(1,sizeof(*p));
00329     ci->psy_param[block]=p;
00330   }
00331   
00332   memcpy(p,&_psy_info_template,sizeof(*p));
00333   p->blockflag=block>>1;
00334 
00335   if(hi->noise_normalize_p){
00336     p->normal_channel_p=1;
00337     p->normal_point_p=1;
00338     p->normal_start=nn_start[is];
00339     p->normal_partition=nn_partition[is];
00340     p->normal_thresh=nn_thresh[is];
00341   }
00342     
00343   return;
00344 }
00345 
00346 static void vorbis_encode_tonemask_setup(vorbis_info *vi,double s,int block,
00347                                          att3 *att,
00348                                          int  *max,
00349                                          vp_adjblock *in){
00350   int i,is=s;
00351   double ds=s-is;
00352   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00353   vorbis_info_psy *p=ci->psy_param[block];
00354 
00355   /* 0 and 2 are only used by bitmanagement, but there's no harm to always
00356      filling the values in here */
00357   p->tone_masteratt[0]=att[is].att[0]*(1.-ds)+att[is+1].att[0]*ds;
00358   p->tone_masteratt[1]=att[is].att[1]*(1.-ds)+att[is+1].att[1]*ds;
00359   p->tone_masteratt[2]=att[is].att[2]*(1.-ds)+att[is+1].att[2]*ds;
00360   p->tone_centerboost=att[is].boost*(1.-ds)+att[is+1].boost*ds;
00361   p->tone_decay=att[is].decay*(1.-ds)+att[is+1].decay*ds;
00362 
00363   p->max_curve_dB=max[is]*(1.-ds)+max[is+1]*ds;
00364 
00365   for(i=0;i<P_BANDS;i++)
00366     p->toneatt[i]=in[is].block[i]*(1.-ds)+in[is+1].block[i]*ds;
00367   return;
00368 }
00369 
00370 
00371 static void vorbis_encode_compand_setup(vorbis_info *vi,double s,int block,
00372                                        compandblock *in, double *x){
00373   int i,is=s;
00374   double ds=s-is;
00375   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00376   vorbis_info_psy *p=ci->psy_param[block];
00377 
00378   ds=x[is]*(1.-ds)+x[is+1]*ds;
00379   is=(int)ds;
00380   ds-=is;
00381   if(ds==0 && is>0){
00382     is--;
00383     ds=1.;
00384   }
00385 
00386   /* interpolate the compander settings */
00387   for(i=0;i<NOISE_COMPAND_LEVELS;i++)
00388     p->noisecompand[i]=in[is].data[i]*(1.-ds)+in[is+1].data[i]*ds;
00389   return;
00390 }
00391 
00392 static void vorbis_encode_peak_setup(vorbis_info *vi,double s,int block,
00393                                     int *suppress){
00394   int is=s;
00395   double ds=s-is;
00396   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00397   vorbis_info_psy *p=ci->psy_param[block];
00398 
00399   p->tone_abs_limit=suppress[is]*(1.-ds)+suppress[is+1]*ds;
00400 
00401   return;
00402 }
00403 
00404 static void vorbis_encode_noisebias_setup(vorbis_info *vi,double s,int block,
00405                                          int *suppress,
00406                                          noise3 *in,
00407                                          noiseguard *guard,
00408                                          double userbias){
00409   int i,is=s,j;
00410   double ds=s-is;
00411   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00412   vorbis_info_psy *p=ci->psy_param[block];
00413 
00414   p->noisemaxsupp=suppress[is]*(1.-ds)+suppress[is+1]*ds;
00415   p->noisewindowlomin=guard[block].lo;
00416   p->noisewindowhimin=guard[block].hi;
00417   p->noisewindowfixed=guard[block].fixed;
00418 
00419   for(j=0;j<P_NOISECURVES;j++)
00420     for(i=0;i<P_BANDS;i++)
00421       p->noiseoff[j][i]=in[is].data[j][i]*(1.-ds)+in[is+1].data[j][i]*ds;
00422 
00423   /* impulse blocks may take a user specified bias to boost the
00424      nominal/high noise encoding depth */
00425   for(j=0;j<P_NOISECURVES;j++){
00426     float min=p->noiseoff[j][0]+6; /* the lowest it can go */
00427     for(i=0;i<P_BANDS;i++){
00428       p->noiseoff[j][i]+=userbias;
00429       if(p->noiseoff[j][i]<min)p->noiseoff[j][i]=min;
00430     }
00431   }
00432 
00433   return;
00434 }
00435 
00436 static void vorbis_encode_ath_setup(vorbis_info *vi,int block){
00437   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00438   vorbis_info_psy *p=ci->psy_param[block];
00439 
00440   p->ath_adjatt=ci->hi.ath_floating_dB;
00441   p->ath_maxatt=ci->hi.ath_absolute_dB;
00442   return;
00443 }
00444 
00445 
00446 static int book_dup_or_new(codec_setup_info *ci,static_codebook *book){
00447   int i;
00448   for(i=0;i<ci->books;i++)
00449     if(ci->book_param[i]==book)return(i);
00450   
00451   return(ci->books++);
00452 }
00453 
00454 static void vorbis_encode_blocksize_setup(vorbis_info *vi,double s,
00455                                          int *shortb,int *longb){
00456 
00457   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00458   int is=s;
00459   
00460   int blockshort=shortb[is];
00461   int blocklong=longb[is];
00462   ci->blocksizes[0]=blockshort;
00463   ci->blocksizes[1]=blocklong;
00464 
00465 }
00466 
00467 static void vorbis_encode_residue_setup(vorbis_info *vi,
00468                                        int number, int block,
00469                                        vorbis_residue_template *res){
00470 
00471   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00472   int i/*,n*/;
00473   vorbis_info_residue0 *r = NULL;
00474   ci->residue_param[number] = _ogg_malloc(sizeof(*r));
00475   r=(vorbis_info_residue0*)ci->residue_param[number];
00476   
00477   memcpy(r,res->res,sizeof(*r));
00478   if(ci->residues<=number)ci->residues=number+1;
00479 
00480   switch(ci->blocksizes[block]){
00481   case 64:case 128:case 256:
00482     r->grouping=16;
00483     break;
00484   default:
00485     r->grouping=32;
00486     break;
00487   }
00488   ci->residue_type[number]=res->res_type;
00489 
00490   /* to be adjusted by lowpass/pointlimit later */
00491 /* n=r->end=ci->blocksizes[block]>>1; 
00492   if(res->res_type==2)
00493     n=r->end*=vi->channels;*///warning
00494   
00495   /* fill in all the books */
00496   {
00497     int booklist=0,k;
00498     
00499     if(ci->hi.managed){
00500       for(i=0;i<r->partitions;i++)
00501         for(k=0;k<3;k++)
00502           if(res->books_base_managed->books[i][k])
00503             r->secondstages[i]|=(1<<k);
00504 
00505       r->groupbook=book_dup_or_new(ci,res->book_aux_managed);
00506       ci->book_param[r->groupbook]=res->book_aux_managed;      
00507     
00508       for(i=0;i<r->partitions;i++){
00509         for(k=0;k<3;k++){
00510           if(res->books_base_managed->books[i][k]){
00511             int bookid=book_dup_or_new(ci,res->books_base_managed->books[i][k]);
00512             r->booklist[booklist++]=bookid;
00513             ci->book_param[bookid]=res->books_base_managed->books[i][k];
00514           }
00515         }
00516       }
00517 
00518     }else{
00519 
00520       for(i=0;i<r->partitions;i++)
00521         for(k=0;k<3;k++)
00522           if(res->books_base->books[i][k])
00523             r->secondstages[i]|=(1<<k);
00524   
00525       r->groupbook=book_dup_or_new(ci,res->book_aux);
00526       ci->book_param[r->groupbook]=res->book_aux;
00527       
00528       for(i=0;i<r->partitions;i++){
00529         for(k=0;k<3;k++){
00530           if(res->books_base->books[i][k]){
00531             int bookid=book_dup_or_new(ci,res->books_base->books[i][k]);
00532             r->booklist[booklist++]=bookid;
00533             ci->book_param[bookid]=res->books_base->books[i][k];
00534           }
00535         }
00536       }
00537     }
00538   }
00539   
00540   /* lowpass setup/pointlimit */
00541   {
00542     double freq=ci->hi.lowpass_kHz*1000.;
00543     vorbis_info_floor1 *f=(vorbis_info_floor1*)ci->floor_param[block]; /* by convention */
00544     double nyq=vi->rate/2.;
00545     long blocksize=ci->blocksizes[block]>>1;
00546 
00547     /* lowpass needs to be set in the floor and the residue. */    
00548     if(freq>nyq)freq=nyq;
00549     /* in the floor, the granularity can be very fine; it doesn't alter
00550        the encoding structure, only the samples used to fit the floor
00551        approximation */
00552     f->n=freq/nyq*blocksize; 
00553 
00554     /* this res may by limited by the maximum pointlimit of the mode,
00555        not the lowpass. the floor is always lowpass limited. */
00556     if(res->limit_type){
00557       if(ci->hi.managed)
00558         freq=ci->psy_g_param.coupling_pkHz[PACKETBLOBS-1]*1000.;
00559       else
00560         freq=ci->psy_g_param.coupling_pkHz[PACKETBLOBS/2]*1000.;
00561       if(freq>nyq)freq=nyq;
00562     }
00563     
00564     /* in the residue, we're constrained, physically, by partition
00565        boundaries.  We still lowpass 'wherever', but we have to round up
00566        here to next boundary, or the vorbis spec will round it *down* to
00567        previous boundary in encode/decode */
00568     if(ci->residue_type[block]==2)
00569       r->end=(int)((freq/nyq*blocksize*2)/r->grouping+.9)* /* round up only if we're well past */
00570         r->grouping;
00571     else
00572       r->end=(int)((freq/nyq*blocksize)/r->grouping+.9)* /* round up only if we're well past */
00573         r->grouping;
00574   }
00575 }      
00576 
00577 /* we assume two maps in this encoder */
00578 static void vorbis_encode_map_n_res_setup(vorbis_info *vi,double s,
00579                                           vorbis_mapping_template *maps){
00580 
00581   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00582   int i,j,is=s,modes=2;
00583   vorbis_info_mapping0 *map=maps[is].map;
00584   vorbis_info_mode *mode=_mode_template;
00585   vorbis_residue_template *res=maps[is].res;
00586 
00587   if(ci->blocksizes[0]==ci->blocksizes[1])modes=1;
00588 
00589   for(i=0;i<modes;i++){
00590 
00591     ci->map_param[i]=_ogg_calloc(1,sizeof(*map));
00592     ci->mode_param[i]=(vorbis_info_mode*)_ogg_calloc(1,sizeof(*mode));
00593   
00594     memcpy(ci->mode_param[i],mode+i,sizeof(*_mode_template));
00595     if(i>=ci->modes)ci->modes=i+1;
00596 
00597     ci->map_type[i]=0;
00598     memcpy(ci->map_param[i],map+i,sizeof(*map));
00599     if(i>=ci->maps)ci->maps=i+1;
00600     
00601     for(j=0;j<map[i].submaps;j++)
00602       vorbis_encode_residue_setup(vi,map[i].residuesubmap[j],i
00603                                   ,res+map[i].residuesubmap[j]);
00604   }
00605 }
00606 
00607 static double setting_to_approx_bitrate(vorbis_info *vi){
00608   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00609   highlevel_encode_setup *hi=&ci->hi;
00610   ve_setup_data_template *setup=(ve_setup_data_template *)hi->setup;
00611   int is=hi->base_setting;
00612   double ds=hi->base_setting-is;
00613   int ch=vi->channels;
00614   double *r=setup->rate_mapping;
00615 
00616   if(r==NULL)
00617     return(-1);
00618   
00619   return((r[is]*(1.-ds)+r[is+1]*ds)*ch);  
00620 }
00621 
00622 static void get_setup_template(vorbis_info *vi,
00623                                long ch,long srate,
00624                                double req,int q_or_bitrate){
00625   int i=0,j;
00626   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00627   highlevel_encode_setup *hi=&ci->hi;
00628   if(q_or_bitrate)req/=ch;
00629 
00630   while(setup_list[i]){
00631     if(setup_list[i]->coupling_restriction==-1 ||
00632        setup_list[i]->coupling_restriction==ch){
00633       if(srate>=setup_list[i]->samplerate_min_restriction &&
00634          srate<=setup_list[i]->samplerate_max_restriction){
00635         int mappings=setup_list[i]->mappings;
00636         double *map=(q_or_bitrate?
00637                      setup_list[i]->rate_mapping:
00638                      setup_list[i]->quality_mapping);
00639 
00640         /* the template matches.  Does the requested quality mode
00641            fall within this template's modes? */
00642         if(req<map[0]){++i;continue;}
00643         if(req>map[setup_list[i]->mappings]){++i;continue;}
00644         for(j=0;j<mappings;j++)
00645           if(req>=map[j] && req<map[j+1])break;
00646         /* an all-points match */
00647         hi->setup=setup_list[i];
00648         if(j==mappings)
00649           hi->base_setting=j-.001;
00650         else{
00651           float low=map[j];
00652           float high=map[j+1];
00653           float del=(req-low)/(high-low);
00654           hi->base_setting=j+del;
00655         }
00656 
00657         return;
00658       }
00659     }
00660     i++;
00661   }
00662   
00663   hi->setup=NULL;
00664 }
00665 
00666 /* encoders will need to use vorbis_info_init beforehand and call
00667    vorbis_info clear when all done */
00668 
00669 /* two interfaces; this, more detailed one, and later a convenience
00670    layer on top */
00671 
00672 /* the final setup call */
00673 int vorbis_encode_setup_init(vorbis_info *vi){
00674   int i0=0,singleblock=0;
00675   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00676   ve_setup_data_template *setup=NULL;
00677   highlevel_encode_setup *hi=&ci->hi;
00678 
00679   if(ci==NULL)return(OV_EINVAL);
00680   if(!hi->impulse_block_p)i0=1;
00681 
00682   /* too low/high an ATH floater is nonsensical, but doesn't break anything */
00683   if(hi->ath_floating_dB>-80)hi->ath_floating_dB=-80;
00684   if(hi->ath_floating_dB<-200)hi->ath_floating_dB=-200;
00685 
00686   /* again, bound this to avoid the app shooting itself int he foot
00687      too badly */
00688   if(hi->amplitude_track_dBpersec>0.)hi->amplitude_track_dBpersec=0.;
00689   if(hi->amplitude_track_dBpersec<-99999.)hi->amplitude_track_dBpersec=-99999.;
00690   
00691   /* get the appropriate setup template; matches the fetch in previous
00692      stages */
00693   setup=(ve_setup_data_template *)hi->setup;
00694   if(setup==NULL)return(OV_EINVAL);
00695 
00696   hi->set_in_stone=1;
00697   /* choose block sizes from configured sizes as well as paying
00698      attention to long_block_p and short_block_p.  If the configured
00699      short and long blocks are the same length, we set long_block_p
00700      and unset short_block_p */
00701   vorbis_encode_blocksize_setup(vi,hi->base_setting,
00702                                 setup->blocksize_short,
00703                                 setup->blocksize_long);
00704   if(ci->blocksizes[0]==ci->blocksizes[1])singleblock=1;
00705   
00706   /* floor setup; choose proper floor params.  Allocated on the floor
00707      stack in order; if we alloc only long floor, it's 0 */
00708   vorbis_encode_floor_setup(vi,hi->short_setting,0,
00709                             setup->floor_books,
00710                             setup->floor_params,
00711                             setup->floor_short_mapping);
00712   if(!singleblock)
00713     vorbis_encode_floor_setup(vi,hi->long_setting,1,
00714                               setup->floor_books,
00715                               setup->floor_params,
00716                               setup->floor_long_mapping);
00717   
00718   /* setup of [mostly] short block detection and stereo*/
00719   vorbis_encode_global_psych_setup(vi,hi->trigger_setting,
00720                                    setup->global_params,
00721                                    setup->global_mapping);
00722   vorbis_encode_global_stereo(vi,hi,setup->stereo_modes);
00723 
00724   /* basic psych setup and noise normalization */
00725   vorbis_encode_psyset_setup(vi,hi->short_setting,
00726                              setup->psy_noise_normal_start[0],
00727                              setup->psy_noise_normal_partition[0],  
00728                              setup->psy_noise_normal_thresh,  
00729                              0);
00730   vorbis_encode_psyset_setup(vi,hi->short_setting,
00731                              setup->psy_noise_normal_start[0],
00732                              setup->psy_noise_normal_partition[0],  
00733                              setup->psy_noise_normal_thresh,  
00734                              1);
00735   if(!singleblock){
00736     vorbis_encode_psyset_setup(vi,hi->long_setting,
00737                                setup->psy_noise_normal_start[1],
00738                                setup->psy_noise_normal_partition[1],  
00739                                     setup->psy_noise_normal_thresh,  
00740                                2);
00741     vorbis_encode_psyset_setup(vi,hi->long_setting,
00742                                setup->psy_noise_normal_start[1],
00743                                setup->psy_noise_normal_partition[1],  
00744                                setup->psy_noise_normal_thresh,  
00745                                3);
00746   }
00747 
00748   /* tone masking setup */
00749   vorbis_encode_tonemask_setup(vi,hi->block[i0].tone_mask_setting,0,
00750                                setup->psy_tone_masteratt,
00751                                setup->psy_tone_0dB,
00752                                setup->psy_tone_adj_impulse);
00753   vorbis_encode_tonemask_setup(vi,hi->block[1].tone_mask_setting,1,
00754                                setup->psy_tone_masteratt,
00755                                setup->psy_tone_0dB,
00756                                setup->psy_tone_adj_other);
00757   if(!singleblock){
00758     vorbis_encode_tonemask_setup(vi,hi->block[2].tone_mask_setting,2,
00759                                  setup->psy_tone_masteratt,
00760                                  setup->psy_tone_0dB,
00761                                  setup->psy_tone_adj_other);
00762     vorbis_encode_tonemask_setup(vi,hi->block[3].tone_mask_setting,3,
00763                                  setup->psy_tone_masteratt,
00764                                  setup->psy_tone_0dB,
00765                                  setup->psy_tone_adj_long);
00766   }
00767 
00768   /* noise companding setup */
00769   vorbis_encode_compand_setup(vi,hi->block[i0].noise_compand_setting,0,
00770                               setup->psy_noise_compand,
00771                               setup->psy_noise_compand_short_mapping);
00772   vorbis_encode_compand_setup(vi,hi->block[1].noise_compand_setting,1,
00773                               setup->psy_noise_compand,
00774                               setup->psy_noise_compand_short_mapping);
00775   if(!singleblock){
00776     vorbis_encode_compand_setup(vi,hi->block[2].noise_compand_setting,2,
00777                                 setup->psy_noise_compand,
00778                                 setup->psy_noise_compand_long_mapping);
00779     vorbis_encode_compand_setup(vi,hi->block[3].noise_compand_setting,3,
00780                                 setup->psy_noise_compand,
00781                                 setup->psy_noise_compand_long_mapping);
00782   }
00783 
00784   /* peak guarding setup  */
00785   vorbis_encode_peak_setup(vi,hi->block[i0].tone_peaklimit_setting,0,
00786                            setup->psy_tone_dBsuppress);
00787   vorbis_encode_peak_setup(vi,hi->block[1].tone_peaklimit_setting,1,
00788                            setup->psy_tone_dBsuppress);
00789   if(!singleblock){
00790     vorbis_encode_peak_setup(vi,hi->block[2].tone_peaklimit_setting,2,
00791                              setup->psy_tone_dBsuppress);
00792     vorbis_encode_peak_setup(vi,hi->block[3].tone_peaklimit_setting,3,
00793                              setup->psy_tone_dBsuppress);
00794   }
00795 
00796   /* noise bias setup */
00797   vorbis_encode_noisebias_setup(vi,hi->block[i0].noise_bias_setting,0,
00798                                 setup->psy_noise_dBsuppress,
00799                                 setup->psy_noise_bias_impulse,
00800                                 setup->psy_noiseguards,
00801                                 (i0==0?hi->impulse_noisetune:0.));
00802   vorbis_encode_noisebias_setup(vi,hi->block[1].noise_bias_setting,1,
00803                                 setup->psy_noise_dBsuppress,
00804                                 setup->psy_noise_bias_padding,
00805                                 setup->psy_noiseguards,0.);
00806   if(!singleblock){
00807     vorbis_encode_noisebias_setup(vi,hi->block[2].noise_bias_setting,2,
00808                                   setup->psy_noise_dBsuppress,
00809                                   setup->psy_noise_bias_trans,
00810                                   setup->psy_noiseguards,0.);
00811     vorbis_encode_noisebias_setup(vi,hi->block[3].noise_bias_setting,3,
00812                                   setup->psy_noise_dBsuppress,
00813                                   setup->psy_noise_bias_long,
00814                                   setup->psy_noiseguards,0.);
00815   }
00816 
00817   vorbis_encode_ath_setup(vi,0);
00818   vorbis_encode_ath_setup(vi,1);
00819   if(!singleblock){
00820     vorbis_encode_ath_setup(vi,2);
00821     vorbis_encode_ath_setup(vi,3);
00822   }
00823 
00824   vorbis_encode_map_n_res_setup(vi,hi->base_setting,setup->maps);
00825 
00826   /* set bitrate readonlies and management */
00827   if(hi->bitrate_av>0)
00828     vi->bitrate_nominal=hi->bitrate_av;
00829   else{
00830     vi->bitrate_nominal=setting_to_approx_bitrate(vi);
00831   }
00832 
00833   vi->bitrate_lower=hi->bitrate_min;
00834   vi->bitrate_upper=hi->bitrate_max;
00835   if(hi->bitrate_av)
00836     vi->bitrate_window=(double)hi->bitrate_reservoir/hi->bitrate_av;
00837   else
00838     vi->bitrate_window=0.;
00839 
00840   if(hi->managed){
00841     ci->bi.avg_rate=hi->bitrate_av;
00842     ci->bi.min_rate=hi->bitrate_min;
00843     ci->bi.max_rate=hi->bitrate_max;
00844 
00845     ci->bi.reservoir_bits=hi->bitrate_reservoir;
00846     ci->bi.reservoir_bias=
00847       hi->bitrate_reservoir_bias;
00848     
00849     ci->bi.slew_damp=hi->bitrate_av_damp;
00850 
00851   }
00852 
00853   return(0);
00854   
00855 }
00856 
00857 static int vorbis_encode_setup_setting(vorbis_info *vi,
00858                                        long  channels,
00859                                        long  rate){
00860   int ret=0,i,is;
00861   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00862   highlevel_encode_setup *hi=&ci->hi;
00863   ve_setup_data_template *setup=(ve_setup_data_template*)hi->setup;
00864   double ds;
00865 
00866   ret=vorbis_encode_toplevel_setup(vi,channels,rate);
00867   if(ret)return(ret);
00868 
00869   is=hi->base_setting;
00870   ds=hi->base_setting-is;
00871 
00872   hi->short_setting=hi->base_setting;
00873   hi->long_setting=hi->base_setting;
00874 
00875   hi->managed=0;
00876 
00877   hi->impulse_block_p=1;
00878   hi->noise_normalize_p=1;
00879 
00880   hi->stereo_point_setting=hi->base_setting;
00881   hi->lowpass_kHz=
00882     setup->psy_lowpass[is]*(1.-ds)+setup->psy_lowpass[is+1]*ds;  
00883   
00884   hi->ath_floating_dB=setup->psy_ath_float[is]*(1.-ds)+
00885     setup->psy_ath_float[is+1]*ds;
00886   hi->ath_absolute_dB=setup->psy_ath_abs[is]*(1.-ds)+
00887     setup->psy_ath_abs[is+1]*ds;
00888 
00889   hi->amplitude_track_dBpersec=-6.;
00890   hi->trigger_setting=hi->base_setting;
00891 
00892   for(i=0;i<4;i++){
00893     hi->block[i].tone_mask_setting=hi->base_setting;
00894     hi->block[i].tone_peaklimit_setting=hi->base_setting;
00895     hi->block[i].noise_bias_setting=hi->base_setting;
00896     hi->block[i].noise_compand_setting=hi->base_setting;
00897   }
00898 
00899   return(ret);
00900 }
00901 
00902 int vorbis_encode_setup_vbr(vorbis_info *vi,
00903                             long  channels,
00904                             long  rate,                     
00905                             float quality){
00906   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00907   highlevel_encode_setup *hi=&ci->hi;
00908 
00909   quality+=.0000001;
00910   if(quality>=1.)quality=.9999;
00911 
00912   get_setup_template(vi,channels,rate,quality,0);
00913   if(!hi->setup)return OV_EIMPL;
00914   
00915   return vorbis_encode_setup_setting(vi,channels,rate);
00916 }
00917 
00918 int vorbis_encode_init_vbr(vorbis_info *vi,
00919                            long channels,
00920                            long rate,
00921                            
00922                            float base_quality /* 0. to 1. */
00923                            ){
00924   int ret=0;
00925 
00926   ret=vorbis_encode_setup_vbr(vi,channels,rate,base_quality);
00927   
00928   if(ret){
00929     vorbis_info_clear(vi);
00930     return ret; 
00931   }
00932   ret=vorbis_encode_setup_init(vi);
00933   if(ret)
00934     vorbis_info_clear(vi);
00935   return(ret);
00936 }
00937 
00938 int vorbis_encode_setup_managed(vorbis_info *vi,
00939                                 long channels,
00940                                 long rate,
00941                                 
00942                                 long max_bitrate,
00943                                 long nominal_bitrate,
00944                                 long min_bitrate){
00945 
00946   codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
00947   highlevel_encode_setup *hi=&ci->hi;
00948   double tnominal=nominal_bitrate;
00949   int ret=0;
00950 
00951   if(nominal_bitrate<=0.){
00952     if(max_bitrate>0.){
00953       if(min_bitrate>0.)
00954         nominal_bitrate=(max_bitrate+min_bitrate)*.5;
00955       else
00956         nominal_bitrate=max_bitrate*.875;
00957     }else{
00958       if(min_bitrate>0.){
00959         nominal_bitrate=min_bitrate;
00960       }else{
00961         return(OV_EINVAL);
00962       }
00963     }
00964   }
00965 
00966   get_setup_template(vi,channels,rate,nominal_bitrate,1);
00967   if(!hi->setup)return OV_EIMPL;
00968   
00969   ret=vorbis_encode_setup_setting(vi,channels,rate);
00970   if(ret){
00971     vorbis_info_clear(vi);
00972     return ret; 
00973   }
00974 
00975   /* initialize management with sane defaults */
00976   hi->managed=1;
00977   hi->bitrate_min=min_bitrate;
00978   hi->bitrate_max=max_bitrate;
00979   hi->bitrate_av=tnominal;
00980   hi->bitrate_av_damp=1.5f; /* full range in no less than 1.5 second */
00981   hi->bitrate_reservoir=nominal_bitrate*2;
00982   hi->bitrate_reservoir_bias=.1; /* bias toward hoarding bits */
00983 
00984   return(ret);
00985 
00986 }
00987 
00988 int vorbis_encode_init(vorbis_info *vi,
00989                        long channels,
00990                        long rate,
00991 
00992                        long max_bitrate,
00993                        long nominal_bitrate,
00994                        long min_bitrate){
00995 
00996   int ret=vorbis_encode_setup_managed(vi,channels,rate,
00997                                       max_bitrate,
00998                                       nominal_bitrate,
00999                                       min_bitrate);
01000   if(ret){
01001     vorbis_info_clear(vi);
01002     return(ret);
01003   }
01004 
01005   ret=vorbis_encode_setup_init(vi);
01006   if(ret)
01007     vorbis_info_clear(vi);
01008   return(ret);
01009 }
01010 
01011 int vorbis_encode_ctl(vorbis_info *vi,int number,void *arg){
01012   if(vi){
01013     codec_setup_info *ci=(codec_setup_info*)vi->codec_setup;
01014     highlevel_encode_setup *hi=&ci->hi;
01015     int setp=(number&0xf); /* a read request has a low nibble of 0 */
01016 
01017     if(setp && hi->set_in_stone)return(OV_EINVAL);
01018     
01019     switch(number){
01020       
01021     /* now deprecated *****************/
01022     case OV_ECTL_RATEMANAGE_GET:
01023       {
01024         
01025         struct ovectl_ratemanage_arg *ai=
01026           (struct ovectl_ratemanage_arg *)arg;
01027         
01028         ai->management_active=hi->managed;
01029         ai->bitrate_hard_window=ai->bitrate_av_window=
01030           (double)hi->bitrate_reservoir/vi->rate;
01031         ai->bitrate_av_window_center=1.;
01032         ai->bitrate_hard_min=hi->bitrate_min;
01033         ai->bitrate_hard_max=hi->bitrate_max;
01034         ai->bitrate_av_lo=hi->bitrate_av;
01035         ai->bitrate_av_hi=hi->bitrate_av;
01036         
01037       }
01038       return(0);
01039     
01040     /* now deprecated *****************/
01041     case OV_ECTL_RATEMANAGE_SET:
01042       {
01043         struct ovectl_ratemanage_arg *ai=
01044           (struct ovectl_ratemanage_arg *)arg;
01045         if(ai==NULL){
01046           hi->managed=0;
01047         }else{
01048           hi->managed=ai->management_active;
01049           vorbis_encode_ctl(vi,OV_ECTL_RATEMANAGE_AVG,arg);
01050           vorbis_encode_ctl(vi,OV_ECTL_RATEMANAGE_HARD,arg);
01051         }
01052       }
01053       return 0;
01054 
01055     /* now deprecated *****************/
01056     case OV_ECTL_RATEMANAGE_AVG:
01057       {
01058         struct ovectl_ratemanage_arg *ai=
01059           (struct ovectl_ratemanage_arg *)arg;
01060         if(ai==NULL){
01061           hi->bitrate_av=0;
01062         }else{
01063           hi->bitrate_av=(ai->bitrate_av_lo+ai->bitrate_av_hi)*.5;
01064         }
01065       }
01066       return(0);
01067     /* now deprecated *****************/
01068     case OV_ECTL_RATEMANAGE_HARD:
01069       {
01070         struct ovectl_ratemanage_arg *ai=
01071           (struct ovectl_ratemanage_arg *)arg;
01072         if(ai==NULL){
01073           hi->bitrate_min=0;
01074           hi->bitrate_max=0;
01075         }else{
01076           hi->bitrate_min=ai->bitrate_hard_min;
01077           hi->bitrate_max=ai->bitrate_hard_max;
01078           hi->bitrate_reservoir=ai->bitrate_hard_window*
01079             (hi->bitrate_max+hi->bitrate_min)*.5;
01080         }
01081         if(hi->bitrate_reservoir<128.)
01082           hi->bitrate_reservoir=128.;
01083       }   
01084       return(0);
01085 
01086       /* replacement ratemanage interface */
01087     case OV_ECTL_RATEMANAGE2_GET:
01088       {
01089         struct ovectl_ratemanage2_arg *ai=
01090           (struct ovectl_ratemanage2_arg *)arg;
01091         if(ai==NULL)return OV_EINVAL;
01092         
01093         ai->management_active=hi->managed;
01094         ai->bitrate_limit_min_kbps=hi->bitrate_min/1000;
01095         ai->bitrate_limit_max_kbps=hi->bitrate_max/1000;
01096         ai->bitrate_average_kbps=hi->bitrate_av/1000;
01097         ai->bitrate_average_damping=hi->bitrate_av_damp;
01098         ai->bitrate_limit_reservoir_bits=hi->bitrate_reservoir;
01099         ai->bitrate_limit_reservoir_bias=hi->bitrate_reservoir_bias;
01100       }
01101       return (0);
01102     case OV_ECTL_RATEMANAGE2_SET:
01103       {
01104         struct ovectl_ratemanage2_arg *ai=
01105           (struct ovectl_ratemanage2_arg *)arg;
01106         if(ai==NULL){
01107           hi->managed=0;
01108         }else{
01109           /* sanity check; only catch invariant violations */
01110           if(ai->bitrate_limit_min_kbps>0 &&
01111              ai->bitrate_average_kbps>0 &&
01112              ai->bitrate_limit_min_kbps>ai->bitrate_average_kbps)
01113             return OV_EINVAL;
01114 
01115           if(ai->bitrate_limit_max_kbps>0 &&
01116              ai->bitrate_average_kbps>0 &&
01117              ai->bitrate_limit_max_kbps<ai->bitrate_average_kbps)
01118             return OV_EINVAL;
01119 
01120           if(ai->bitrate_limit_min_kbps>0 &&
01121              ai->bitrate_limit_max_kbps>0 &&
01122              ai->bitrate_limit_min_kbps>ai->bitrate_limit_max_kbps)
01123             return OV_EINVAL;
01124 
01125           if(ai->bitrate_average_damping <= 0.)
01126             return OV_EINVAL;
01127 
01128           if(ai->bitrate_limit_reservoir_bits < 0)
01129             return OV_EINVAL;
01130 
01131           if(ai->bitrate_limit_reservoir_bias < 0.)
01132             return OV_EINVAL;
01133 
01134           if(ai->bitrate_limit_reservoir_bias > 1.)
01135             return OV_EINVAL;
01136 
01137           hi->managed=ai->management_active;
01138           hi->bitrate_min=ai->bitrate_limit_min_kbps * 1000;
01139           hi->bitrate_max=ai->bitrate_limit_max_kbps * 1000;
01140           hi->bitrate_av=ai->bitrate_average_kbps * 1000;
01141           hi->bitrate_av_damp=ai->bitrate_average_damping;
01142           hi->bitrate_reservoir=ai->bitrate_limit_reservoir_bits;
01143           hi->bitrate_reservoir_bias=ai->bitrate_limit_reservoir_bias;
01144         }
01145       }
01146       return 0;
01147       
01148     case OV_ECTL_LOWPASS_GET:
01149       {
01150         double *farg=(double *)arg;
01151         *farg=hi->lowpass_kHz;
01152       }
01153       return(0);
01154     case OV_ECTL_LOWPASS_SET:
01155       {
01156         double *farg=(double *)arg;
01157         hi->lowpass_kHz=*farg;
01158 
01159         if(hi->lowpass_kHz<2.)hi->lowpass_kHz=2.;
01160         if(hi->lowpass_kHz>99.)hi->lowpass_kHz=99.;
01161       }
01162       return(0);
01163     case OV_ECTL_IBLOCK_GET:
01164       {
01165         double *farg=(double *)arg;
01166         *farg=hi->impulse_noisetune;
01167       }
01168       return(0);
01169     case OV_ECTL_IBLOCK_SET:
01170       {
01171         double *farg=(double *)arg;
01172         hi->impulse_noisetune=*farg;
01173 
01174         if(hi->impulse_noisetune>0.)hi->impulse_noisetune=0.;
01175         if(hi->impulse_noisetune<-15.)hi->impulse_noisetune=-15.;
01176       }
01177       return(0);      
01178     }
01179 
01180 
01181     return(OV_EIMPL);
01182   }
01183   return(OV_EINVAL);
01184 }

Generated by  doxygen 1.6.2