text:
/********************************************************************
 *                                                                  *
 * 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-2009             *
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
 *                                                                  *
 ********************************************************************

 function: bitrate tracking and management
 last mod: $Id: bitrate.c 16227 2009-07-08 06:58:46Z xiphmont $

 ********************************************************************/

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "../../ogg.h"
#include "../../codec.h"
#include "codec_internal.h"
#include "os.h"
#include "misc.h"
#include "bitrate.h"

/* compute bitrate tracking setup  */
void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){
  codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
  bitrate_manager_info *bi=&ci->bi;

  memset(bm,0,sizeof(*bm));

  if(bi && (bi->reservoir_bits>0)){
    long ratesamples=vi->rate;
    int  halfsamples=ci->blocksizes[0]>>1;

    bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0];
    bm->managed=1;

    bm->avg_bitsper= (int) rint(1.*bi->avg_rate*halfsamples/ratesamples);
    bm->min_bitsper= (int) rint(1.*bi->min_rate*halfsamples/ratesamples);
    bm->max_bitsper= (int) rint(1.*bi->max_rate*halfsamples/ratesamples);

    bm->avgfloat=PACKETBLOBS/2;

    /* not a necessary fix, but one that leads to a more balanced
       typical initialization */
    {
      long desired_fill = (long) (bi->reservoir_bits*bi->reservoir_bias);
      bm->minmax_reservoir=desired_fill;
      bm->avg_reservoir=desired_fill;
    }

  }
}

void vorbis_bitrate_clear(bitrate_manager_state *bm){
  memset(bm,0,sizeof(*bm));
  return;
}

int vorbis_bitrate_managed(vorbis_block *vb){
  vorbis_dsp_state      *vd=vb->vd;
  private_state         *b=(private_state*)vd->backend_state;
  bitrate_manager_state *bm=&b->bms;

  if(bm && bm->managed)return(1);
  return(0);
}

/* finish taking in the block we just processed */
int vorbis_bitrate_addblock(vorbis_block *vb){
  vorbis_block_internal *vbi=(vorbis_block_internal*)vb->internal;
  vorbis_dsp_state      *vd=vb->vd;
  private_state         *b=(private_state*)vd->backend_state;
  bitrate_manager_state *bm=&b->bms;
  vorbis_info           *vi=vd->vi;
  codec_setup_info      *ci=(codec_setup_info*)vi->codec_setup;
  bitrate_manager_info  *bi=&ci->bi;

  int  choice = (int) rint(bm->avgfloat);
  long this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
  long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper);
  long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper);
  int  samples=ci->blocksizes[vb->W]>>1;
  long desired_fill = (long) (bi->reservoir_bits*bi->reservoir_bias);
  if(!bm->managed){
    /* not a bitrate managed stream, but for API simplicity, we'll
       buffer the packet to keep the code path clean */

    if(bm->vb)return(-1); /* one has been submitted without
                             being claimed */
    bm->vb=vb;
    return(0);
  }

  bm->vb=vb;

  /* look ahead for avg floater */
  if(bm->avg_bitsper>0){
    double slew=0.;
    long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
    double slewlimit= 15./bi->slew_damp;

    /* choosing a new floater:
       if we're over target, we slew down
       if we're under target, we slew up

       choose slew as follows: look through packetblobs of this frame
       and set slew as the first in the appropriate direction that
       gives us the slew we want.  This may mean no slew if delta is
       already favorable.

       Then limit slew to slew max */

    if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
      while(choice>0 && this_bits>avg_target_bits &&
            bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){
        choice--;
        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
      }
    }else if(bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
      while(choice+1<PACKETBLOBS && this_bits<avg_target_bits &&
            bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){
        choice++;
        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
      }
    }

    slew=rint(choice-bm->avgfloat)/samples*vi->rate;
    if(slew<-slewlimit)slew=-slewlimit;
    if(slew>slewlimit)slew=slewlimit;
    choice = (int) rint(bm->avgfloat+= slew/vi->rate*samples);
    this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
  }

  /* enforce min(if used) on the current floater (if used) */
  if(bm->min_bitsper>0){
    /* do we need to force the bitrate up? */
    if(this_bits<min_target_bits){
      while(bm->minmax_reservoir-(min_target_bits-this_bits)<0){
        choice++;
        if(choice>=PACKETBLOBS)break;
        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
      }
    }
  }

  /* enforce max (if used) on the current floater (if used) */
  if(bm->max_bitsper>0){
    /* do we need to force the bitrate down? */
    if(this_bits>max_target_bits){
      while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){
        choice--;
        if(choice<0)break;
        this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
      }
    }
  }

  /* Choice of packetblobs now made based on floater, and min/max
     requirements. Now boundary check extreme choices */

  if(choice<0){
    /* choosing a smaller packetblob is insufficient to trim bitrate.
       frame will need to be truncated */
    long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8;
    bm->choice=choice=0;

    if(oggpack_bytes(vbi->packetblob[choice])>maxsize){

      oggpack_writetrunc(vbi->packetblob[choice],maxsize*8);
      this_bits=oggpack_bytes(vbi->packetblob[choice])*8;
    }
  }else{
    long minsize=(min_target_bits-bm->minmax_reservoir+7)/8;
    if(choice>=PACKETBLOBS)
      choice=PACKETBLOBS-1;

    bm->choice=choice;

    /* prop up bitrate according to demand. pad this frame out with zeroes */
    minsize-=oggpack_bytes(vbi->packetblob[choice]);
    while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8);
    this_bits=oggpack_bytes(vbi->packetblob[choice])*8;

  }

  /* now we have the final packet and the final packet size.  Update statistics */
  /* min and max reservoir */
  if(bm->min_bitsper>0 || bm->max_bitsper>0){

    if(max_target_bits>0 && this_bits>max_target_bits){
      bm->minmax_reservoir+=(this_bits-max_target_bits);
    }else if(min_target_bits>0 && this_bits<min_target_bits){
      bm->minmax_reservoir+=(this_bits-min_target_bits);
    }else{
      /* inbetween; we want to take reservoir toward but not past desired_fill */
      if(bm->minmax_reservoir>desired_fill){
        if(max_target_bits>0){ /* logical bulletproofing against initialization state */
          bm->minmax_reservoir+=(this_bits-max_target_bits);
          if(bm->minmax_reservoir<desired_fill)bm->minmax_reservoir=desired_fill;
        }else{
          bm->minmax_reservoir=desired_fill;
        }
      }else{
        if(min_target_bits>0){ /* logical bulletproofing against initialization state */
          bm->minmax_reservoir+=(this_bits-min_target_bits);
          if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill;
        }else{
          bm->minmax_reservoir=desired_fill;
        }
      }
    }
  }

  /* avg reservoir */
  if(bm->avg_bitsper>0){
    long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper);
    bm->avg_reservoir+=this_bits-avg_target_bits;
  }

  return(0);
}

int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){
  private_state         *b=(private_state*)vd->backend_state;
  bitrate_manager_state *bm=&b->bms;
  vorbis_block          *vb=bm->vb;
  int                    choice=PACKETBLOBS/2;
  if(!vb)return 0;

  if(op){
    vorbis_block_internal *vbi=(vorbis_block_internal*)vb->internal;

    if(vorbis_bitrate_managed(vb))
      choice=bm->choice;

    op->packet=oggpack_get_buffer(vbi->packetblob[choice]);
    op->bytes=oggpack_bytes(vbi->packetblob[choice]);
    op->b_o_s=0;
    op->e_o_s=vb->eofflag;
    op->granulepos=vb->granulepos;
    op->packetno=vb->sequence; /* for sake of completeness */
  }

  bm->vb=0;
  return(1);
}


text:
/********************************************************************
 *                                                                  *
 * 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-2007             *
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
 *                                                                  *
 ********************************************************************

  function: lookup data; generated by lookups.pl; edit there
  last mod: $Id: lookup_data.h 16037 2009-05-26 21:10:58Z xiphmont $

 ********************************************************************/

#ifndef _V_LOOKUP_DATA_H_

#ifdef FLOAT_LOOKUP
#define COS_LOOKUP_SZ 128
static const float COS_LOOKUP[COS_LOOKUP_SZ+1]={
        +1.0000000000000f,+0.9996988186962f,+0.9987954562052f,+0.9972904566787f,
        +0.9951847266722f,+0.9924795345987f,+0.9891765099648f,+0.9852776423889f,
        +0.9807852804032f,+0.9757021300385f,+0.9700312531945f,+0.9637760657954f,
        +0.9569403357322f,+0.9495281805930f,+0.9415440651830f,+0.9329927988347f,
        +0.9238795325113f,+0.9142097557035f,+0.9039892931234f,+0.8932243011955f,
        +0.8819212643484f,+0.8700869911087f,+0.8577286100003f,+0.8448535652497f,
        +0.8314696123025f,+0.8175848131516f,+0.8032075314806f,+0.7883464276266f,
        +0.7730104533627f,+0.7572088465065f,+0.7409511253550f,+0.7242470829515f,
        +0.7071067811865f,+0.6895405447371f,+0.6715589548470f,+0.6531728429538f,
        +0.6343932841636f,+0.6152315905806f,+0.5956993044924f,+0.5758081914178f,
        +0.5555702330196f,+0.5349976198871f,+0.5141027441932f,+0.4928981922298f,
        +0.4713967368260f,+0.4496113296546f,+0.4275550934303f,+0.4052413140050f,
        +0.3826834323651f,+0.3598950365350f,+0.3368898533922f,+0.3136817403989f,
        +0.2902846772545f,+0.2667127574749f,+0.2429801799033f,+0.2191012401569f,
        +0.1950903220161f,+0.1709618887603f,+0.1467304744554f,+0.1224106751992f,
        +0.0980171403296f,+0.0735645635997f,+0.0490676743274f,+0.0245412285229f,
        +0.0000000000000f,-0.0245412285229f,-0.0490676743274f,-0.0735645635997f,
        -0.0980171403296f,-0.1224106751992f,-0.1467304744554f,-0.1709618887603f,
        -0.1950903220161f,-0.2191012401569f,-0.2429801799033f,-0.2667127574749f,
        -0.2902846772545f,-0.3136817403989f,-0.3368898533922f,-0.3598950365350f,
        -0.3826834323651f,-0.4052413140050f,-0.4275550934303f,-0.4496113296546f,
        -0.4713967368260f,-0.4928981922298f,-0.5141027441932f,-0.5349976198871f,
        -0.5555702330196f,-0.5758081914178f,-0.5956993044924f,-0.6152315905806f,
        -0.6343932841636f,-0.6531728429538f,-0.6715589548470f,-0.6895405447371f,
        -0.7071067811865f,-0.7242470829515f,-0.7409511253550f,-0.7572088465065f,
        -0.7730104533627f,-0.7883464276266f,-0.8032075314806f,-0.8175848131516f,
        -0.8314696123025f,-0.8448535652497f,-0.8577286100003f,-0.8700869911087f,
        -0.8819212643484f,-0.8932243011955f,-0.9039892931234f,-0.9142097557035f,
        -0.9238795325113f,-0.9329927988347f,-0.9415440651830f,-0.9495281805930f,
        -0.9569403357322f,-0.9637760657954f,-0.9700312531945f,-0.9757021300385f,
        -0.9807852804032f,-0.9852776423889f,-0.9891765099648f,-0.9924795345987f,
        -0.9951847266722f,-0.9972904566787f,-0.9987954562052f,-0.9996988186962f,
        -1.0000000000000f,
};

#define INVSQ_LOOKUP_SZ 32
static const float INVSQ_LOOKUP[INVSQ_LOOKUP_SZ+1]={
        1.414213562373f,1.392621247646f,1.371988681140f,1.352246807566f,
        1.333333333333f,1.315191898443f,1.297771369046f,1.281025230441f,
        1.264911064067f,1.249390095109f,1.234426799697f,1.219988562661f,
        1.206045378311f,1.192569588000f,1.179535649239f,1.166919931983f,
        1.154700538379f,1.142857142857f,1.131370849898f,1.120224067222f,
        1.109400392450f,1.098884511590f,1.088662107904f,1.078719779941f,
        1.069044967650f,1.059625885652f,1.050451462878f,1.041511287847f,
        1.032795558989f,1.024295039463f,1.016001016002f,1.007905261358f,
        1.000000000000f,
};

#define INVSQ2EXP_LOOKUP_MIN (-32)
#define INVSQ2EXP_LOOKUP_MAX 32
static const float INVSQ2EXP_LOOKUP[INVSQ2EXP_LOOKUP_MAX-\
                              INVSQ2EXP_LOOKUP_MIN+1]={
                 65536.f,    46340.95001f,         32768.f,    23170.47501f,
                 16384.f,     11585.2375f,          8192.f,    5792.618751f,
                  4096.f,    2896.309376f,          2048.f,    1448.154688f,
                  1024.f,    724.0773439f,           512.f,     362.038672f,
                   256.f,     181.019336f,           128.f,    90.50966799f,
                    64.f,      45.254834f,            32.f,      22.627417f,
                    16.f,     11.3137085f,             8.f,    5.656854249f,
                     4.f,    2.828427125f,             2.f,    1.414213562f,
                     1.f,   0.7071067812f,            0.5f,   0.3535533906f,
                   0.25f,   0.1767766953f,          0.125f,  0.08838834765f,
                 0.0625f,  0.04419417382f,        0.03125f,  0.02209708691f,
               0.015625f,  0.01104854346f,      0.0078125f, 0.005524271728f,
             0.00390625f, 0.002762135864f,    0.001953125f, 0.001381067932f,
           0.0009765625f, 0.000690533966f,  0.00048828125f, 0.000345266983f,
         0.000244140625f,0.0001726334915f,0.0001220703125f,8.631674575e-05f,
        6.103515625e-05f,4.315837288e-05f,3.051757812e-05f,2.157918644e-05f,
        1.525878906e-05f,
};

#endif

#define FROMdB_LOOKUP_SZ 35
#define FROMdB2_LOOKUP_SZ 32
#define FROMdB_SHIFT 5
#define FROMdB2_SHIFT 3
#define FROMdB2_MASK 31

#ifdef FLOAT_LOOKUP
static const float FROMdB_LOOKUP[FROMdB_LOOKUP_SZ]={
                     1.f,   0.6309573445f,   0.3981071706f,   0.2511886432f,
           0.1584893192f,            0.1f,  0.06309573445f,  0.03981071706f,
          0.02511886432f,  0.01584893192f,           0.01f, 0.006309573445f,
         0.003981071706f, 0.002511886432f, 0.001584893192f,          0.001f,
        0.0006309573445f,0.0003981071706f,0.0002511886432f,0.0001584893192f,
                 0.0001f,6.309573445e-05f,3.981071706e-05f,2.511886432e-05f,
        1.584893192e-05f,          1e-05f,6.309573445e-06f,3.981071706e-06f,
        2.511886432e-06f,1.584893192e-06f,          1e-06f,6.309573445e-07f,
        3.981071706e-07f,2.511886432e-07f,1.584893192e-07f,
};

static const float FROMdB2_LOOKUP[FROMdB2_LOOKUP_SZ]={
           0.9928302478f,   0.9786445908f,   0.9646616199f,   0.9508784391f,
           0.9372921937f,     0.92390007f,   0.9106992942f,   0.8976871324f,
           0.8848608897f,   0.8722179097f,   0.8597555737f,   0.8474713009f,
            0.835362547f,   0.8234268041f,   0.8116616003f,   0.8000644989f,
           0.7886330981f,   0.7773650302f,   0.7662579617f,    0.755309592f,
           0.7445176537f,   0.7338799116f,   0.7233941627f,   0.7130582353f,
           0.7028699885f,   0.6928273125f,   0.6829281272f,   0.6731703824f,
           0.6635520573f,   0.6540711597f,   0.6447257262f,   0.6355138211f,
};
#endif

#ifdef INT_LOOKUP

#define INVSQ_LOOKUP_I_SHIFT 10
#define INVSQ_LOOKUP_I_MASK 1023
static const long INVSQ_LOOKUP_I[64+1]={
           92682l,   91966l,   91267l,   90583l,
           89915l,   89261l,   88621l,   87995l,
           87381l,   86781l,   86192l,   85616l,
           85051l,   84497l,   83953l,   83420l,
           82897l,   82384l,   81880l,   81385l,
           80899l,   80422l,   79953l,   79492l,
           79039l,   78594l,   78156l,   77726l,
           77302l,   76885l,   76475l,   76072l,
           75674l,   75283l,   74898l,   74519l,
           74146l,   73778l,   73415l,   73058l,
           72706l,   72359l,   72016l,   71679l,
           71347l,   71019l,   70695l,   70376l,
           70061l,   69750l,   69444l,   69141l,
           68842l,   68548l,   68256l,   67969l,
           67685l,   67405l,   67128l,   66855l,
           66585l,   66318l,   66054l,   65794l,
           65536l,
};

#define COS_LOOKUP_I_SHIFT 9
#define COS_LOOKUP_I_MASK 511
#define COS_LOOKUP_I_SZ 128
static const long COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={
           16384l,   16379l,   16364l,   16340l,
           16305l,   16261l,   16207l,   16143l,
           16069l,   15986l,   15893l,   15791l,
           15679l,   15557l,   15426l,   15286l,
           15137l,   14978l,   14811l,   14635l,
           14449l,   14256l,   14053l,   13842l,
           13623l,   13395l,   13160l,   12916l,
           12665l,   12406l,   12140l,   11866l,
           11585l,   11297l,   11003l,   10702l,
           10394l,   10080l,    9760l,    9434l,
            9102l,    8765l,    8423l,    8076l,
            7723l,    7366l,    7005l,    6639l,
            6270l,    5897l,    5520l,    5139l,
            4756l,    4370l,    3981l,    3590l,
            3196l,    2801l,    2404l,    2006l,
            1606l,    1205l,     804l,     402l,
               0l,    -401l,    -803l,   -1204l,
           -1605l,   -2005l,   -2403l,   -2800l,
           -3195l,   -3589l,   -3980l,   -4369l,
           -4755l,   -5138l,   -5519l,   -5896l,
           -6269l,   -6638l,   -7004l,   -7365l,
           -7722l,   -8075l,   -8422l,   -8764l,
           -9101l,   -9433l,   -9759l,  -10079l,
          -10393l,  -10701l,  -11002l,  -11296l,
          -11584l,  -11865l,  -12139l,  -12405l,
          -12664l,  -12915l,  -13159l,  -13394l,
          -13622l,  -13841l,  -14052l,  -14255l,
          -14448l,  -14634l,  -14810l,  -14977l,
          -15136l,  -15285l,  -15425l,  -15556l,
          -15678l,  -15790l,  -15892l,  -15985l,
          -16068l,  -16142l,  -16206l,  -16260l,
          -16304l,  -16339l,  -16363l,  -16378l,
          -16383l,
};

#endif

#endif

repo_name: fedden/RenderMan

mime_type: text/x-c++


text:
/********************************************************************
 *                                                                  *
 * 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-2009             *
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
 *                                                                  *
 ********************************************************************

 function: random psychoacoustics (not including preecho)
 last mod: $Id: psy.h 16946 2010-03-03 16:12:40Z xiphmont $

 ********************************************************************/

#ifndef _V_PSY_H_
#define _V_PSY_H_
#include "smallft.h"

#include "backends.h"
#include "envelope.h"

#ifndef EHMER_MAX
#define EHMER_MAX 56
#endif

/* psychoacoustic setup ********************************************/
#define P_BANDS 17      /* 62Hz to 16kHz */
#define P_LEVELS 8      /* 30dB to 100dB */
#define P_LEVEL_0 30.    /* 30 dB */
#define P_NOISECURVES 3

#define NOISE_COMPAND_LEVELS 40
typedef struct vorbis_info_psy{
  int   blockflag;

  float ath_adjatt;
  float ath_maxatt;

  float tone_masteratt[P_NOISECURVES];
  float tone_centerboost;
  float tone_decay;
  float tone_abs_limit;
  float toneatt[P_BANDS];

  int noisemaskp;
  float noisemaxsupp;
  float noisewindowlo;
  float noisewindowhi;
  int   noisewindowlomin;
  int   noisewindowhimin;
  int   noisewindowfixed;
  float noiseoff[P_NOISECURVES][P_BANDS];
  float noisecompand[NOISE_COMPAND_LEVELS];

  float max_curve_dB;

  int normal_p;
  int normal_start;
  int normal_partition;
  double normal_thresh;
} vorbis_info_psy;

typedef struct{
  int   eighth_octave_lines;

  /* for block long/short tuning; encode only */
  float preecho_thresh[VE_BANDS];
  float postecho_thresh[VE_BANDS];
  float stretch_penalty;
  float preecho_minenergy;

  float ampmax_att_per_sec;

  /* channel coupling config */
  int   coupling_pkHz[PACKETBLOBS];
  int   coupling_pointlimit[2][PACKETBLOBS];
  int   coupling_prepointamp[PACKETBLOBS];
  int   coupling_postpointamp[PACKETBLOBS];
  int   sliding_lowpass[2][PACKETBLOBS];

} vorbis_info_psy_global;

typedef struct {
  float ampmax;
  int   channels;

  vorbis_info_psy_global *gi;
  int   coupling_pointlimit[2][P_NOISECURVES];
} vorbis_look_psy_global;

typedef struct {
  int n;
  struct vorbis_info_psy *vi;

  float ***tonecurves;
  float **noiseoffset;

  float *ath;
  long  *octave;             /* in n.ocshift format */
  long  *bark;

  long  firstoc;
  long  shiftoc;
  int   eighth_octave_lines; /* power of two, please */
  int   total_octave_lines;
  long  rate; /* cache it */

  float m_val; /* Masking compensation value */

} vorbis_look_psy;

extern void   _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi,
                           vorbis_info_psy_global *gi,int n,long rate);
extern void   _vp_psy_clear(vorbis_look_psy *p);
extern void  *_vi_psy_dup(void *source);

extern void   _vi_psy_free(vorbis_info_psy *i);
extern vorbis_info_psy *_vi_psy_copy(vorbis_info_psy *i);

extern void _vp_noisemask(vorbis_look_psy *p,
                          float *logmdct,
                          float *logmask);

extern void _vp_tonemask(vorbis_look_psy *p,
                         float *logfft,
                         float *logmask,
                         float global_specmax,
                         float local_specmax);

extern void _vp_offset_and_mix(vorbis_look_psy *p,
                               float *noise,
                               float *tone,
                               int offset_select,
                               float *logmask,
                               float *mdct,
                               float *logmdct);

extern float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd);

extern void _vp_couple_quantize_normalize(int blobno,
                                          vorbis_info_psy_global *g,
                                          vorbis_look_psy *p,
                                          vorbis_info_mapping0 *vi,
                                          float **mdct,
                                          int   **iwork,
                                          int    *nonzero,
                                          int     sliding_lowpass,
                                          int     ch);

#endif


text:
/********************************************************************
 *                                                                  *
 * 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-2009             *
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
 *                                                                  *
 ********************************************************************

 function: registry for time, floor, res backends and channel mappings
 last mod: $Id: registry.c 16227 2009-07-08 06:58:46Z xiphmont $

 ********************************************************************/

#include "../../codec.h"
#include "codec_internal.h"
#include "registry.h"
#include "misc.h"
/* seems like major overkill now; the backend numbers will grow into
   the infrastructure soon enough */

extern const vorbis_func_floor     floor0_exportbundle;
extern const vorbis_func_floor     floor1_exportbundle;
extern const vorbis_func_residue   residue0_exportbundle;
extern const vorbis_func_residue   residue1_exportbundle;
extern const vorbis_func_residue   residue2_exportbundle;
extern const vorbis_func_mapping   mapping0_exportbundle;

const vorbis_func_floor     *const _floor_P[]={
  &floor0_exportbundle,
  &floor1_exportbundle,
};

const vorbis_func_residue   *const _residue_P[]={
  &residue0_exportbundle,
  &residue1_exportbundle,
  &residue2_exportbundle,
};

const vorbis_func_mapping   *const _mapping_P[]={
  &mapping0_exportbundle,
};


text:
/********************************************************************
 *                                                                  *
 * 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-2010             *
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
 *                                                                  *
 ********************************************************************

 function: maintain the info structure, info <-> header packets
 last mod: $Id: info.c 17584 2010-11-01 19:26:16Z xiphmont $

 ********************************************************************/

/* general handling of the header and the vorbis_info structure (and
   substructures) */

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "../../ogg.h"
#include "../../codec.h"
#include "codec_internal.h"
#include "codebook.h"
#include "registry.h"
#include "window.h"
#include "psy.h"
#include "misc.h"
#include "os.h"

#define GENERAL_VENDOR_STRING "Xiph.Org libVorbis 1.3.2"
#define ENCODE_VENDOR_STRING "Xiph.Org libVorbis I 20101101 (Schaufenugget)"

/* helpers */

static void _v_writestring(oggpack_buffer *o,const char *s, int bytes){

  while(bytes--){
    oggpack_write(o,*s++,8);
  }
}

static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
  while(bytes--){
    *buf++=oggpack_read(o,8);
  }
}

void vorbis_comment_init(vorbis_comment *vc){
  memset(vc,0,sizeof(*vc));
}

void vorbis_comment_add(vorbis_comment *vc,const char *comment){
  vc->user_comments=(char**)_ogg_realloc(vc->user_comments,
                            (vc->comments+2)*sizeof(*vc->user_comments));
  vc->comment_lengths=(int*)_ogg_realloc(vc->comment_lengths,
                                  (vc->comments+2)*sizeof(*vc->comment_lengths));
  vc->comment_lengths[vc->comments]=strlen(comment);
  vc->user_comments[vc->comments]=(char*)_ogg_malloc(vc->comment_lengths[vc->comments]+1);
  strcpy(vc->user_comments[vc->comments], comment);
  vc->comments++;
  vc->user_comments[vc->comments]=NULL;
}

void vorbis_comment_add_tag(vorbis_comment *vc, const char *tag, const char *contents){
  char *comment=(char*)alloca(strlen(tag)+strlen(contents)+2); /* +2 for = and \0 */
  strcpy(comment, tag);
  strcat(comment, "=");
  strcat(comment, contents);
  vorbis_comment_add(vc, comment);
}

/* This is more or less the same as strncasecmp - but that doesn't exist
 * everywhere, and this is a fairly trivial function, so we include it */
static int tagcompare(const char *s1, const char *s2, int n){
  int c=0;
  while(c < n){
    if(toupper(s1[c]) != toupper(s2[c]))
      return !0;
    c++;
  }
  return 0;
}

char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count){
  long i;
  int found = 0;
  int taglen = strlen(tag)+1; /* +1 for the = we append */
  char *fulltag = (char*)alloca(taglen+ 1);

  strcpy(fulltag, tag);
  strcat(fulltag, "=");

  for(i=0;i<vc->comments;i++){
    if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
      if(count == found)
        /* We return a pointer to the data, not a copy */
              return vc->user_comments[i] + taglen;
      else
        found++;
    }
  }
  return NULL; /* didn't find anything */
}

int vorbis_comment_query_count(vorbis_comment *vc, const char *tag){
  int i,count=0;
  int taglen = strlen(tag)+1; /* +1 for the = we append */
  char *fulltag = (char*)alloca(taglen+1);
  strcpy(fulltag,tag);
  strcat(fulltag, "=");

  for(i=0;i<vc->comments;i++){
    if(!tagcompare(vc->user_comments[i], fulltag, taglen))
      count++;
  }

  return count;
}

void vorbis_comment_clear(vorbis_comment *vc){
  if(vc){
    long i;
    if(vc->user_comments){
      for(i=0;i<vc->comments;i++)
        if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
      _ogg_free(vc->user_comments);
    }
    if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
    if(vc->vendor)_ogg_free(vc->vendor);
    memset(vc,0,sizeof(*vc));
  }
}

/* blocksize 0 is guaranteed to be short, 1 is guaranteed to be long.
   They may be equal, but short will never ge greater than long */
int vorbis_info_blocksize(vorbis_info *vi,int zo){
  codec_setup_info *ci = (codec_setup_info*)vi->codec_setup;
  return ci ? ci->blocksizes[zo] : -1;
}

/* used by synthesis, which has a full, alloced vi */
void vorbis_info_init(vorbis_info *vi){
  memset(vi,0,sizeof(*vi));
  vi->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info));
}

void vorbis_info_clear(vorbis_info *vi){
  codec_setup_info     *ci=(codec_setup_info*)vi->codec_setup;
  int i;

  if(ci){

    for(i=0;i<ci->modes;i++)
      if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);

    for(i=0;i<ci->maps;i++) /* unpack does the range checking */
      if(ci->map_param[i]) /* this may be cleaning up an aborted
                              unpack, in which case the below type
                              cannot be trusted */
        _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);

    for(i=0;i<ci->floors;i++) /* unpack does the range checking */
      if(ci->floor_param[i]) /* this may be cleaning up an aborted
                                unpack, in which case the below type
                                cannot be trusted */
        _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);

    for(i=0;i<ci->residues;i++) /* unpack does the range checking */
      if(ci->residue_param[i]) /* this may be cleaning up an aborted
                                  unpack, in which case the below type
                                  cannot be trusted */
        _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);

    for(i=0;i<ci->books;i++){
      if(ci->book_param[i]){
        /* knows if the book was not alloced */
        vorbis_staticbook_destroy(ci->book_param[i]);
      }
      if(ci->fullbooks)
        vorbis_book_clear(ci->fullbooks+i);
    }
    if(ci->fullbooks)
        _ogg_free(ci->fullbooks);

    for(i=0;i<ci->psys;i++)
      _vi_psy_free(ci->psy_param[i]);

    _ogg_free(ci);
  }

  memset(vi,0,sizeof(*vi));
}

/* Header packing/unpacking ********************************************/

static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
  codec_setup_info     *ci=(codec_setup_info*)vi->codec_setup;
  if(!ci)return(OV_EFAULT);

  vi->version=oggpack_read(opb,32);
  if(vi->version!=0)return(OV_EVERSION);

  vi->channels=oggpack_read(opb,8);
  vi->rate=oggpack_read(opb,32);

  vi->bitrate_upper=oggpack_read(opb,32);
  vi->bitrate_nominal=oggpack_read(opb,32);
  vi->bitrate_lower=oggpack_read(opb,32);

  ci->blocksizes[0]=1<<oggpack_read(opb,4);
  ci->blocksizes[1]=1<<oggpack_read(opb,4);

  if(vi->rate<1)goto err_out;
  if(vi->channels<1)goto err_out;
  if(ci->blocksizes[0]<64)goto err_out;
  if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
  if(ci->blocksizes[1]>8192)goto err_out;

  if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */

  return(0);
 err_out:
  vorbis_info_clear(vi);
  return(OV_EBADHEADER);
}

static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
  int i;
  int vendorlen=oggpack_read(opb,32);
  if(vendorlen<0)goto err_out;
  if(vendorlen>opb->storage-8)goto err_out;
  vc->vendor=(char*)_ogg_calloc(vendorlen+1,1);
  _v_readstring(opb,vc->vendor,vendorlen);
  i=oggpack_read(opb,32);
  if(i<0)goto err_out;
  if(i>((opb->storage-oggpack_bytes(opb))>>2))goto err_out;
  vc->comments=i;
  vc->user_comments=(char**)_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
  vc->comment_lengths=(int*)_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));

  for(i=0;i<vc->comments;i++){
    int len=oggpack_read(opb,32);
    if(len<0)goto err_out;
    if(len>opb->storage-oggpack_bytes(opb))goto err_out;
    vc->comment_lengths[i]=len;
    vc->user_comments[i]=(char*)_ogg_calloc(len+1,1);
    _v_readstring(opb,vc->user_comments[i],len);
  }
  if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */

  return(0);
 err_out:
  vorbis_comment_clear(vc);
  return(OV_EBADHEADER);
}

/* all of the real encoding details are here.  The modes, books,
   everything */
static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
  codec_setup_info     *ci=(codec_setup_info*)vi->codec_setup;
  int i;
  if(!ci)return(OV_EFAULT);

  /* codebooks */
  ci->books=oggpack_read(opb,8)+1;
  if(ci->books<=0)goto err_out;
  for(i=0;i<ci->books;i++){
    ci->book_param[i]=vorbis_staticbook_unpack(opb);
    if(!ci->book_param[i])goto err_out;
  }

  /* time backend settings; hooks are unused */
  {
    int times=oggpack_read(opb,6)+1;
    if(times<=0)goto err_out;
    for(i=0;i<times;i++){
      int test=oggpack_read(opb,16);
      if(test<0 || test>=VI_TIMEB)goto err_out;
    }
  }

  /* floor backend settings */
  ci->floors=oggpack_read(opb,6)+1;
  if(ci->floors<=0)goto err_out;
  for(i=0;i<ci->floors;i++){
    ci->floor_type[i]=oggpack_read(opb,16);
    if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
    ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
    if(!ci->floor_param[i])goto err_out;
  }

  /* residue backend settings */
  ci->residues=oggpack_read(opb,6)+1;
  if(ci->residues<=0)goto err_out;
  for(i=0;i<ci->residues;i++){
    ci->residue_type[i]=oggpack_read(opb,16);
    if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
    ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
    if(!ci->residue_param[i])goto err_out;
  }

  /* map backend settings */
  ci->maps=oggpack_read(opb,6)+1;
  if(ci->maps<=0)goto err_out;
  for(i=0;i<ci->maps;i++){
    ci->map_type[i]=oggpack_read(opb,16);
    if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
    ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
    if(!ci->map_param[i])goto err_out;
  }

  /* mode settings */
  ci->modes=oggpack_read(opb,6)+1;
  if(ci->modes<=0)goto err_out;
  for(i=0;i<ci->modes;i++){
    ci->mode_param[i]=(vorbis_info_mode*)_ogg_calloc(1,sizeof(*ci->mode_param[i]));
    ci->mode_param[i]->blockflag=oggpack_read(opb,1);
    ci->mode_param[i]->windowtype=oggpack_read(opb,16);
    ci->mode_param[i]->transformtype=oggpack_read(opb,16);
    ci->mode_param[i]->mapping=oggpack_read(opb,8);

    if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
    if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
    if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
    if(ci->mode_param[i]->mapping<0)goto err_out;
  }

  if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */

  return(0);
 err_out:
  vorbis_info_clear(vi);
  return(OV_EBADHEADER);
}

/* Is this packet a vorbis ID header? */
int vorbis_synthesis_idheader(ogg_packet *op){
  oggpack_buffer opb;
  char buffer[6];

  if(op){
    oggpack_readinit(&opb,op->packet,op->bytes);

    if(!op->b_o_s)
      return(0); /* Not the initial packet */

    if(oggpack_read(&opb,8) != 1)
      return 0; /* not an ID header */

    memset(buffer,0,6);
    _v_readstring(&opb,buffer,6);
    if(memcmp(buffer,"vorbis",6))
      return 0; /* not vorbis */

    return 1;
  }

  return 0;
}

/* The Vorbis header is in three packets; the initial small packet in
   the first page that identifies basic parameters, a second packet
   with bitstream comments and a third packet that holds the
   codebook. */

int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
  oggpack_buffer opb;

  if(op){
    oggpack_readinit(&opb,op->packet,op->bytes);

    /* Which of the three types of header is this? */
    /* Also verify header-ness, vorbis */
    {
      char buffer[6];
      int packtype=oggpack_read(&opb,8);
      memset(buffer,0,6);
      _v_readstring(&opb,buffer,6);
      if(memcmp(buffer,"vorbis",6)){
        /* not a vorbis header */
        return(OV_ENOTVORBIS);
      }
      switch(packtype){
      case 0x01: /* least significant *bit* is read first */
        if(!op->b_o_s){
          /* Not the initial packet */
          return(OV_EBADHEADER);
        }
        if(vi->rate!=0){
          /* previously initialized info header */
          return(OV_EBADHEADER);
        }

        return(_vorbis_unpack_info(vi,&opb));

      case 0x03: /* least significant *bit* is read first */
        if(vi->rate==0){
          /* um... we didn't get the initial header */
          return(OV_EBADHEADER);
        }

        return(_vorbis_unpack_comment(vc,&opb));

      case 0x05: /* least significant *bit* is read first */
        if(vi->rate==0 || vc->vendor==NULL){
          /* um... we didn;t get the initial header or comments yet */
          return(OV_EBADHEADER);
        }

        return(_vorbis_unpack_books(vi,&opb));

      default:
        /* Not a valid vorbis header type */
        return(OV_EBADHEADER);
        break;
      }
    }
  }
  return(OV_EBADHEADER);
}

/* pack side **********************************************************/

static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){
  codec_setup_info     *ci=(codec_setup_info*)vi->codec_setup;
  if(!ci)return(OV_EFAULT);

  /* preamble */
  oggpack_write(opb,0x01,8);
  _v_writestring(opb,"vorbis", 6);

  /* basic information about the stream */
  oggpack_write(opb,0x00,32);
  oggpack_write(opb,vi->channels,8);
  oggpack_write(opb,vi->rate,32);

  oggpack_write(opb,vi->bitrate_upper,32);
  oggpack_write(opb,vi->bitrate_nominal,32);
  oggpack_write(opb,vi->bitrate_lower,32);

  oggpack_write(opb,ilog2(ci->blocksizes[0]),4);
  oggpack_write(opb,ilog2(ci->blocksizes[1]),4);
  oggpack_write(opb,1,1);

  return(0);
}

static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){
  int bytes = strlen(ENCODE_VENDOR_STRING);

  /* preamble */
  oggpack_write(opb,0x03,8);
  _v_writestring(opb,"vorbis", 6);

  /* vendor */
  oggpack_write(opb,bytes,32);
  _v_writestring(opb,ENCODE_VENDOR_STRING, bytes);

  /* comments */

  oggpack_write(opb,vc->comments,32);
  if(vc->comments){
    int i;
    for(i=0;i<vc->comments;i++){
      if(vc->user_comments[i]){
        oggpack_write(opb,vc->comment_lengths[i],32);
        _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]);
      }else{
        oggpack_write(opb,0,32);
      }
    }
  }
  oggpack_write(opb,1,1);

  return(0);
}

static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){
  codec_setup_info     *ci=(codec_setup_info*)vi->codec_setup;
  int i;
  if(!ci)return(OV_EFAULT);

  oggpack_write(opb,0x05,8);
  _v_writestring(opb,"vorbis", 6);

  /* books */
  oggpack_write(opb,ci->books-1,8);
  for(i=0;i<ci->books;i++)
    if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out;

  /* times; hook placeholders */
  oggpack_write(opb,0,6);
  oggpack_write(opb,0,16);

  /* floors */
  oggpack_write(opb,ci->floors-1,6);
  for(i=0;i<ci->floors;i++){
    oggpack_write(opb,ci->floor_type[i],16);
    if(_floor_P[ci->floor_type[i]]->pack)
      _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb);
    else
      goto err_out;
  }

  /* residues */
  oggpack_write(opb,ci->residues-1,6);
  for(i=0;i<ci->residues;i++){
    oggpack_write(opb,ci->residue_type[i],16);
    _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb);
  }

  /* maps */
  oggpack_write(opb,ci->maps-1,6);
  for(i=0;i<ci->maps;i++){
    oggpack_write(opb,ci->map_type[i],16);
    _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb);
  }

  /* modes */
  oggpack_write(opb,ci->modes-1,6);
  for(i=0;i<ci->modes;i++){
    oggpack_write(opb,ci->mode_param[i]->blockflag,1);
    oggpack_write(opb,ci->mode_param[i]->windowtype,16);
    oggpack_write(opb,ci->mode_param[i]->transformtype,16);
    oggpack_write(opb,ci->mode_param[i]->mapping,8);
  }
  oggpack_write(opb,1,1);

  return(0);
err_out:
  return(-1);
}

int vorbis_commentheader_out(vorbis_comment *vc,
                                          ogg_packet *op){

  oggpack_buffer opb;

  oggpack_writeinit(&opb);
  if(_vorbis_pack_comment(&opb,vc)) return OV_EIMPL;

  op->packet = (unsigned char*) _ogg_malloc(oggpack_bytes(&opb));
  memcpy(op->packet, opb.buffer, oggpack_bytes(&opb));

  op->bytes=oggpack_bytes(&opb);
  op->b_o_s=0;
  op->e_o_s=0;
  op->granulepos=0;
  op->packetno=1;

  return 0;
}

int vorbis_analysis_headerout(vorbis_dsp_state *v,
                              vorbis_comment *vc,
                              ogg_packet *op,
                              ogg_packet *op_comm,
                              ogg_packet *op_code){
  int ret=OV_EIMPL;
  vorbis_info *vi=v->vi;
  oggpack_buffer opb;
  private_state *b=(private_state*)v->backend_state;

  if(!b){
    ret=OV_EFAULT;
    goto err_out;
  }

  /* first header packet **********************************************/

  oggpack_writeinit(&opb);
  if(_vorbis_pack_info(&opb,vi))goto err_out;

  /* build the packet */
  if(b->header)_ogg_free(b->header);
  b->header=(unsigned char*) _ogg_malloc(oggpack_bytes(&opb));
  memcpy(b->header,opb.buffer,oggpack_bytes(&opb));
  op->packet=b->header;
  op->bytes=oggpack_bytes(&opb);
  op->b_o_s=1;
  op->e_o_s=0;
  op->granulepos=0;
  op->packetno=0;

  /* second header packet (comments) **********************************/

  oggpack_reset(&opb);
  if(_vorbis_pack_comment(&opb,vc))goto err_out;

  if(b->header1)_ogg_free(b->header1);
  b->header1=(unsigned char*) _ogg_malloc(oggpack_bytes(&opb));
  memcpy(b->header1,opb.buffer,oggpack_bytes(&opb));
  op_comm->packet=b->header1;
  op_comm->bytes=oggpack_bytes(&opb);
  op_comm->b_o_s=0;
  op_comm->e_o_s=0;
  op_comm->granulepos=0;
  op_comm->packetno=1;

  /* third header packet (modes/codebooks) ****************************/

  oggpack_reset(&opb);
  if(_vorbis_pack_books(&opb,vi))goto err_out;

  if(b->header2)_ogg_free(b->header2);
  b->header2=(unsigned char*) _ogg_malloc(oggpack_bytes(&opb));
  memcpy(b->header2,opb.buffer,oggpack_bytes(&opb));
  op_code->packet=b->header2;
  op_code->bytes=oggpack_bytes(&opb);
  op_code->b_o_s=0;
  op_code->e_o_s=0;
  op_code->granulepos=0;
  op_code->packetno=2;

  oggpack_writeclear(&opb);
  return(0);
 err_out:
  memset(op,0,sizeof(*op));
  memset(op_comm,0,sizeof(*op_comm));
  memset(op_code,0,sizeof(*op_code));

  if(b){
    oggpack_writeclear(&opb);
    if(b->header)_ogg_free(b->header);
    if(b->header1)_ogg_free(b->header1);
    if(b->header2)_ogg_free(b->header2);
    b->header=NULL;
    b->header1=NULL;
    b->header2=NULL;
  }
  return(ret);
}

double vorbis_granule_time(vorbis_dsp_state *v,ogg_int64_t granulepos){
  if(granulepos == -1) return -1;

  /* We're not guaranteed a 64 bit unsigned type everywhere, so we
     have to put the unsigned granpo in a signed type. */
  if(granulepos>=0){
    return((double)granulepos/v->vi->rate);
  }else{
    ogg_int64_t granuleoff=0xffffffff;
    granuleoff<<=31;

#ifdef __GNUC__
    granuleoff |= 0x7ffffffffLL;
#else
    granuleoff |= 0x7ffffffff;
#endif
    return(((double)granulepos+2+granuleoff+granuleoff)/v->vi->rate);
  }
}

const char *vorbis_version_string(void){
  return GENERAL_VENDOR_STRING;
}