Blame lib/block.c

Packit 06404a
/********************************************************************
Packit 06404a
 *                                                                  *
Packit 06404a
 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
Packit 06404a
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
Packit 06404a
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
Packit 06404a
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
Packit 06404a
 *                                                                  *
Packit 06404a
 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015             *
Packit 06404a
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
Packit 06404a
 *                                                                  *
Packit 06404a
 ********************************************************************
Packit 06404a
Packit 06404a
 function: PCM data vector blocking, windowing and dis/reassembly
Packit 06404a
 last mod: $Id: block.c 19457 2015-03-03 00:15:29Z giles $
Packit 06404a
Packit 06404a
 Handle windowing, overlap-add, etc of the PCM vectors.  This is made
Packit 06404a
 more amusing by Vorbis' current two allowed block sizes.
Packit 06404a
Packit 06404a
 ********************************************************************/
Packit 06404a
Packit 06404a
#include <stdio.h>
Packit 06404a
#include <stdlib.h>
Packit 06404a
#include <string.h>
Packit 06404a
#include <ogg/ogg.h>
Packit 06404a
#include "vorbis/codec.h"
Packit 06404a
#include "codec_internal.h"
Packit 06404a
Packit 06404a
#include "window.h"
Packit 06404a
#include "mdct.h"
Packit 06404a
#include "lpc.h"
Packit 06404a
#include "registry.h"
Packit 06404a
#include "misc.h"
Packit 06404a
Packit 06404a
/* pcm accumulator examples (not exhaustive):
Packit 06404a
Packit 06404a
 <-------------- lW ---------------->
Packit 06404a
                   <--------------- W ---------------->
Packit 06404a
:            .....|.....       _______________         |
Packit 06404a
:        .'''     |     '''_---      |       |\        |
Packit 06404a
:.....'''         |_____--- '''......|       | \_______|
Packit 06404a
:.................|__________________|_______|__|______|
Packit 06404a
                  |<------ Sl ------>|      > Sr <     |endW
Packit 06404a
                  |beginSl           |endSl  |  |endSr
Packit 06404a
                  |beginW            |endlW  |beginSr
Packit 06404a
Packit 06404a
Packit 06404a
                      |< lW >|
Packit 06404a
                   <--------------- W ---------------->
Packit 06404a
                  |   |  ..  ______________            |
Packit 06404a
                  |   | '  `/        |     ---_        |
Packit 06404a
                  |___.'___/`.       |         ---_____|
Packit 06404a
                  |_______|__|_______|_________________|
Packit 06404a
                  |      >|Sl|<      |<------ Sr ----->|endW
Packit 06404a
                  |       |  |endSl  |beginSr          |endSr
Packit 06404a
                  |beginW |  |endlW
Packit 06404a
                  mult[0] |beginSl                     mult[n]
Packit 06404a
Packit 06404a
 <-------------- lW ----------------->
Packit 06404a
                          |<--W-->|
Packit 06404a
:            ..............  ___  |   |
Packit 06404a
:        .'''             |`/   \ |   |
Packit 06404a
:.....'''                 |/`....\|...|
Packit 06404a
:.........................|___|___|___|
Packit 06404a
                          |Sl |Sr |endW
Packit 06404a
                          |   |   |endSr
Packit 06404a
                          |   |beginSr
Packit 06404a
                          |   |endSl
Packit 06404a
                          |beginSl
Packit 06404a
                          |beginW
Packit 06404a
*/
Packit 06404a
Packit 06404a
/* block abstraction setup *********************************************/
Packit 06404a
Packit 06404a
#ifndef WORD_ALIGN
Packit 06404a
#define WORD_ALIGN 8
Packit 06404a
#endif
Packit 06404a
Packit 06404a
int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
Packit 06404a
  int i;
Packit 06404a
  memset(vb,0,sizeof(*vb));
Packit 06404a
  vb->vd=v;
Packit 06404a
  vb->localalloc=0;
Packit 06404a
  vb->localstore=NULL;
Packit 06404a
  if(v->analysisp){
Packit 06404a
    vorbis_block_internal *vbi=
Packit 06404a
      vb->internal=_ogg_calloc(1,sizeof(vorbis_block_internal));
Packit 06404a
    vbi->ampmax=-9999;
Packit 06404a
Packit 06404a
    for(i=0;i
Packit 06404a
      if(i==PACKETBLOBS/2){
Packit 06404a
        vbi->packetblob[i]=&vb->opb;
Packit 06404a
      }else{
Packit 06404a
        vbi->packetblob[i]=
Packit 06404a
          _ogg_calloc(1,sizeof(oggpack_buffer));
Packit 06404a
      }
Packit 06404a
      oggpack_writeinit(vbi->packetblob[i]);
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
Packit 06404a
  bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
Packit 06404a
  if(bytes+vb->localtop>vb->localalloc){
Packit 06404a
    /* can't just _ogg_realloc... there are outstanding pointers */
Packit 06404a
    if(vb->localstore){
Packit 06404a
      struct alloc_chain *link=_ogg_malloc(sizeof(*link));
Packit 06404a
      vb->totaluse+=vb->localtop;
Packit 06404a
      link->next=vb->reap;
Packit 06404a
      link->ptr=vb->localstore;
Packit 06404a
      vb->reap=link;
Packit 06404a
    }
Packit 06404a
    /* highly conservative */
Packit 06404a
    vb->localalloc=bytes;
Packit 06404a
    vb->localstore=_ogg_malloc(vb->localalloc);
Packit 06404a
    vb->localtop=0;
Packit 06404a
  }
Packit 06404a
  {
Packit 06404a
    void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
Packit 06404a
    vb->localtop+=bytes;
Packit 06404a
    return ret;
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
/* reap the chain, pull the ripcord */
Packit 06404a
void _vorbis_block_ripcord(vorbis_block *vb){
Packit 06404a
  /* reap the chain */
Packit 06404a
  struct alloc_chain *reap=vb->reap;
Packit 06404a
  while(reap){
Packit 06404a
    struct alloc_chain *next=reap->next;
Packit 06404a
    _ogg_free(reap->ptr);
Packit 06404a
    memset(reap,0,sizeof(*reap));
Packit 06404a
    _ogg_free(reap);
Packit 06404a
    reap=next;
Packit 06404a
  }
Packit 06404a
  /* consolidate storage */
Packit 06404a
  if(vb->totaluse){
Packit 06404a
    vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
Packit 06404a
    vb->localalloc+=vb->totaluse;
Packit 06404a
    vb->totaluse=0;
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* pull the ripcord */
Packit 06404a
  vb->localtop=0;
Packit 06404a
  vb->reap=NULL;
Packit 06404a
}
Packit 06404a
Packit 06404a
int vorbis_block_clear(vorbis_block *vb){
Packit 06404a
  int i;
Packit 06404a
  vorbis_block_internal *vbi=vb->internal;
Packit 06404a
Packit 06404a
  _vorbis_block_ripcord(vb);
Packit 06404a
  if(vb->localstore)_ogg_free(vb->localstore);
Packit 06404a
Packit 06404a
  if(vbi){
Packit 06404a
    for(i=0;i
Packit 06404a
      oggpack_writeclear(vbi->packetblob[i]);
Packit 06404a
      if(i!=PACKETBLOBS/2)_ogg_free(vbi->packetblob[i]);
Packit 06404a
    }
Packit 06404a
    _ogg_free(vbi);
Packit 06404a
  }
Packit 06404a
  memset(vb,0,sizeof(*vb));
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
/* Analysis side code, but directly related to blocking.  Thus it's
Packit 06404a
   here and not in analysis.c (which is for analysis transforms only).
Packit 06404a
   The init is here because some of it is shared */
Packit 06404a
Packit 06404a
static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi,int encp){
Packit 06404a
  int i;
Packit 06404a
  codec_setup_info *ci=vi->codec_setup;
Packit 06404a
  private_state *b=NULL;
Packit 06404a
  int hs;
Packit 06404a
Packit 06404a
  if(ci==NULL||
Packit 06404a
     ci->modes<=0||
Packit 06404a
     ci->blocksizes[0]<64||
Packit 06404a
     ci->blocksizes[1]<ci->blocksizes[0]){
Packit 06404a
    return 1;
Packit 06404a
  }
Packit 06404a
  hs=ci->halfrate_flag;
Packit 06404a
Packit 06404a
  memset(v,0,sizeof(*v));
Packit 06404a
  b=v->backend_state=_ogg_calloc(1,sizeof(*b));
Packit 06404a
Packit 06404a
  v->vi=vi;
Packit 06404a
  b->modebits=ov_ilog(ci->modes-1);
Packit 06404a
Packit 06404a
  b->transform[0]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[0]));
Packit 06404a
  b->transform[1]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[1]));
Packit 06404a
Packit 06404a
  /* MDCT is tranform 0 */
Packit 06404a
Packit 06404a
  b->transform[0][0]=_ogg_calloc(1,sizeof(mdct_lookup));
Packit 06404a
  b->transform[1][0]=_ogg_calloc(1,sizeof(mdct_lookup));
Packit 06404a
  mdct_init(b->transform[0][0],ci->blocksizes[0]>>hs);
Packit 06404a
  mdct_init(b->transform[1][0],ci->blocksizes[1]>>hs);
Packit 06404a
Packit 06404a
  /* Vorbis I uses only window type 0 */
Packit 06404a
  /* note that the correct computation below is technically:
Packit 06404a
       b->window[0]=ov_ilog(ci->blocksizes[0]-1)-6;
Packit 06404a
       b->window[1]=ov_ilog(ci->blocksizes[1]-1)-6;
Packit 06404a
    but since blocksizes are always powers of two,
Packit 06404a
    the below is equivalent.
Packit 06404a
   */
Packit 06404a
  b->window[0]=ov_ilog(ci->blocksizes[0])-7;
Packit 06404a
  b->window[1]=ov_ilog(ci->blocksizes[1])-7;
Packit 06404a
Packit 06404a
  if(encp){ /* encode/decode differ here */
Packit 06404a
Packit 06404a
    /* analysis always needs an fft */
Packit 06404a
    drft_init(&b->fft_look[0],ci->blocksizes[0]);
Packit 06404a
    drft_init(&b->fft_look[1],ci->blocksizes[1]);
Packit 06404a
Packit 06404a
    /* finish the codebooks */
Packit 06404a
    if(!ci->fullbooks){
Packit 06404a
      ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
Packit 06404a
      for(i=0;i<ci->books;i++)
Packit 06404a
        vorbis_book_init_encode(ci->fullbooks+i,ci->book_param[i]);
Packit 06404a
    }
Packit 06404a
Packit 06404a
    b->psy=_ogg_calloc(ci->psys,sizeof(*b->psy));
Packit 06404a
    for(i=0;i<ci->psys;i++){
Packit 06404a
      _vp_psy_init(b->psy+i,
Packit 06404a
                   ci->psy_param[i],
Packit 06404a
                   &ci->psy_g_param,
Packit 06404a
                   ci->blocksizes[ci->psy_param[i]->blockflag]/2,
Packit 06404a
                   vi->rate);
Packit 06404a
    }
Packit 06404a
Packit 06404a
    v->analysisp=1;
Packit 06404a
  }else{
Packit 06404a
    /* finish the codebooks */
Packit 06404a
    if(!ci->fullbooks){
Packit 06404a
      ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
Packit 06404a
      for(i=0;i<ci->books;i++){
Packit 06404a
        if(ci->book_param[i]==NULL)
Packit 06404a
          goto abort_books;
Packit 06404a
        if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
Packit 06404a
          goto abort_books;
Packit 06404a
        /* decode codebooks are now standalone after init */
Packit 06404a
        vorbis_staticbook_destroy(ci->book_param[i]);
Packit 06404a
        ci->book_param[i]=NULL;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* initialize the storage vectors. blocksize[1] is small for encode,
Packit 06404a
     but the correct size for decode */
Packit 06404a
  v->pcm_storage=ci->blocksizes[1];
Packit 06404a
  v->pcm=_ogg_malloc(vi->channels*sizeof(*v->pcm));
Packit 06404a
  v->pcmret=_ogg_malloc(vi->channels*sizeof(*v->pcmret));
Packit 06404a
  {
Packit 06404a
    int i;
Packit 06404a
    for(i=0;i<vi->channels;i++)
Packit 06404a
      v->pcm[i]=_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* all 1 (large block) or 0 (small block) */
Packit 06404a
  /* explicitly set for the sake of clarity */
Packit 06404a
  v->lW=0; /* previous window size */
Packit 06404a
  v->W=0;  /* current window size */
Packit 06404a
Packit 06404a
  /* all vector indexes */
Packit 06404a
  v->centerW=ci->blocksizes[1]/2;
Packit 06404a
Packit 06404a
  v->pcm_current=v->centerW;
Packit 06404a
Packit 06404a
  /* initialize all the backend lookups */
Packit 06404a
  b->flr=_ogg_calloc(ci->floors,sizeof(*b->flr));
Packit 06404a
  b->residue=_ogg_calloc(ci->residues,sizeof(*b->residue));
Packit 06404a
Packit 06404a
  for(i=0;i<ci->floors;i++)
Packit 06404a
    b->flr[i]=_floor_P[ci->floor_type[i]]->
Packit 06404a
      look(v,ci->floor_param[i]);
Packit 06404a
Packit 06404a
  for(i=0;i<ci->residues;i++)
Packit 06404a
    b->residue[i]=_residue_P[ci->residue_type[i]]->
Packit 06404a
      look(v,ci->residue_param[i]);
Packit 06404a
Packit 06404a
  return 0;
Packit 06404a
 abort_books:
Packit 06404a
  for(i=0;i<ci->books;i++){
Packit 06404a
    if(ci->book_param[i]!=NULL){
Packit 06404a
      vorbis_staticbook_destroy(ci->book_param[i]);
Packit 06404a
      ci->book_param[i]=NULL;
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
  vorbis_dsp_clear(v);
Packit 06404a
  return -1;
Packit 06404a
}
Packit 06404a
Packit 06404a
/* arbitrary settings and spec-mandated numbers get filled in here */
Packit 06404a
int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
Packit 06404a
  private_state *b=NULL;
Packit 06404a
Packit 06404a
  if(_vds_shared_init(v,vi,1))return 1;
Packit 06404a
  b=v->backend_state;
Packit 06404a
  b->psy_g_look=_vp_global_look(vi);
Packit 06404a
Packit 06404a
  /* Initialize the envelope state storage */
Packit 06404a
  b->ve=_ogg_calloc(1,sizeof(*b->ve));
Packit 06404a
  _ve_envelope_init(b->ve,vi);
Packit 06404a
Packit 06404a
  vorbis_bitrate_init(vi,&b->bms);
Packit 06404a
Packit 06404a
  /* compressed audio packets start after the headers
Packit 06404a
     with sequence number 3 */
Packit 06404a
  v->sequence=3;
Packit 06404a
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
void vorbis_dsp_clear(vorbis_dsp_state *v){
Packit 06404a
  int i;
Packit 06404a
  if(v){
Packit 06404a
    vorbis_info *vi=v->vi;
Packit 06404a
    codec_setup_info *ci=(vi?vi->codec_setup:NULL);
Packit 06404a
    private_state *b=v->backend_state;
Packit 06404a
Packit 06404a
    if(b){
Packit 06404a
Packit 06404a
      if(b->ve){
Packit 06404a
        _ve_envelope_clear(b->ve);
Packit 06404a
        _ogg_free(b->ve);
Packit 06404a
      }
Packit 06404a
Packit 06404a
      if(b->transform[0]){
Packit 06404a
        mdct_clear(b->transform[0][0]);
Packit 06404a
        _ogg_free(b->transform[0][0]);
Packit 06404a
        _ogg_free(b->transform[0]);
Packit 06404a
      }
Packit 06404a
      if(b->transform[1]){
Packit 06404a
        mdct_clear(b->transform[1][0]);
Packit 06404a
        _ogg_free(b->transform[1][0]);
Packit 06404a
        _ogg_free(b->transform[1]);
Packit 06404a
      }
Packit 06404a
Packit 06404a
      if(b->flr){
Packit 06404a
        if(ci)
Packit 06404a
          for(i=0;i<ci->floors;i++)
Packit 06404a
            _floor_P[ci->floor_type[i]]->
Packit 06404a
              free_look(b->flr[i]);
Packit 06404a
        _ogg_free(b->flr);
Packit 06404a
      }
Packit 06404a
      if(b->residue){
Packit 06404a
        if(ci)
Packit 06404a
          for(i=0;i<ci->residues;i++)
Packit 06404a
            _residue_P[ci->residue_type[i]]->
Packit 06404a
              free_look(b->residue[i]);
Packit 06404a
        _ogg_free(b->residue);
Packit 06404a
      }
Packit 06404a
      if(b->psy){
Packit 06404a
        if(ci)
Packit 06404a
          for(i=0;i<ci->psys;i++)
Packit 06404a
            _vp_psy_clear(b->psy+i);
Packit 06404a
        _ogg_free(b->psy);
Packit 06404a
      }
Packit 06404a
Packit 06404a
      if(b->psy_g_look)_vp_global_free(b->psy_g_look);
Packit 06404a
      vorbis_bitrate_clear(&b->bms);
Packit 06404a
Packit 06404a
      drft_clear(&b->fft_look[0]);
Packit 06404a
      drft_clear(&b->fft_look[1]);
Packit 06404a
Packit 06404a
    }
Packit 06404a
Packit 06404a
    if(v->pcm){
Packit 06404a
      if(vi)
Packit 06404a
        for(i=0;i<vi->channels;i++)
Packit 06404a
          if(v->pcm[i])_ogg_free(v->pcm[i]);
Packit 06404a
      _ogg_free(v->pcm);
Packit 06404a
      if(v->pcmret)_ogg_free(v->pcmret);
Packit 06404a
    }
Packit 06404a
Packit 06404a
    if(b){
Packit 06404a
      /* free header, header1, header2 */
Packit 06404a
      if(b->header)_ogg_free(b->header);
Packit 06404a
      if(b->header1)_ogg_free(b->header1);
Packit 06404a
      if(b->header2)_ogg_free(b->header2);
Packit 06404a
      _ogg_free(b);
Packit 06404a
    }
Packit 06404a
Packit 06404a
    memset(v,0,sizeof(*v));
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
float **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){
Packit 06404a
  int i;
Packit 06404a
  vorbis_info *vi=v->vi;
Packit 06404a
  private_state *b=v->backend_state;
Packit 06404a
Packit 06404a
  /* free header, header1, header2 */
Packit 06404a
  if(b->header)_ogg_free(b->header);b->header=NULL;
Packit 06404a
  if(b->header1)_ogg_free(b->header1);b->header1=NULL;
Packit 06404a
  if(b->header2)_ogg_free(b->header2);b->header2=NULL;
Packit 06404a
Packit 06404a
  /* Do we have enough storage space for the requested buffer? If not,
Packit 06404a
     expand the PCM (and envelope) storage */
Packit 06404a
Packit 06404a
  if(v->pcm_current+vals>=v->pcm_storage){
Packit 06404a
    v->pcm_storage=v->pcm_current+vals*2;
Packit 06404a
Packit 06404a
    for(i=0;i<vi->channels;i++){
Packit 06404a
      v->pcm[i]=_ogg_realloc(v->pcm[i],v->pcm_storage*sizeof(*v->pcm[i]));
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  for(i=0;i<vi->channels;i++)
Packit 06404a
    v->pcmret[i]=v->pcm[i]+v->pcm_current;
Packit 06404a
Packit 06404a
  return(v->pcmret);
Packit 06404a
}
Packit 06404a
Packit 06404a
static void _preextrapolate_helper(vorbis_dsp_state *v){
Packit 06404a
  int i;
Packit 06404a
  int order=16;
Packit 06404a
  float *lpc=alloca(order*sizeof(*lpc));
Packit 06404a
  float *work=alloca(v->pcm_current*sizeof(*work));
Packit 06404a
  long j;
Packit 06404a
  v->preextrapolate=1;
Packit 06404a
Packit 06404a
  if(v->pcm_current-v->centerW>order*2){ /* safety */
Packit 06404a
    for(i=0;i<v->vi->channels;i++){
Packit 06404a
      /* need to run the extrapolation in reverse! */
Packit 06404a
      for(j=0;j<v->pcm_current;j++)
Packit 06404a
        work[j]=v->pcm[i][v->pcm_current-j-1];
Packit 06404a
Packit 06404a
      /* prime as above */
Packit 06404a
      vorbis_lpc_from_data(work,lpc,v->pcm_current-v->centerW,order);
Packit 06404a
Packit 06404a
#if 0
Packit 06404a
      if(v->vi->channels==2){
Packit 06404a
        if(i==0)
Packit 06404a
          _analysis_output("predataL",0,work,v->pcm_current-v->centerW,0,0,0);
Packit 06404a
        else
Packit 06404a
          _analysis_output("predataR",0,work,v->pcm_current-v->centerW,0,0,0);
Packit 06404a
      }else{
Packit 06404a
        _analysis_output("predata",0,work,v->pcm_current-v->centerW,0,0,0);
Packit 06404a
      }
Packit 06404a
#endif
Packit 06404a
Packit 06404a
      /* run the predictor filter */
Packit 06404a
      vorbis_lpc_predict(lpc,work+v->pcm_current-v->centerW-order,
Packit 06404a
                         order,
Packit 06404a
                         work+v->pcm_current-v->centerW,
Packit 06404a
                         v->centerW);
Packit 06404a
Packit 06404a
      for(j=0;j<v->pcm_current;j++)
Packit 06404a
        v->pcm[i][v->pcm_current-j-1]=work[j];
Packit 06404a
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
Packit 06404a
/* call with val<=0 to set eof */
Packit 06404a
Packit 06404a
int vorbis_analysis_wrote(vorbis_dsp_state *v, int vals){
Packit 06404a
  vorbis_info *vi=v->vi;
Packit 06404a
  codec_setup_info *ci=vi->codec_setup;
Packit 06404a
Packit 06404a
  if(vals<=0){
Packit 06404a
    int order=32;
Packit 06404a
    int i;
Packit 06404a
    float *lpc=alloca(order*sizeof(*lpc));
Packit 06404a
Packit 06404a
    /* if it wasn't done earlier (very short sample) */
Packit 06404a
    if(!v->preextrapolate)
Packit 06404a
      _preextrapolate_helper(v);
Packit 06404a
Packit 06404a
    /* We're encoding the end of the stream.  Just make sure we have
Packit 06404a
       [at least] a few full blocks of zeroes at the end. */
Packit 06404a
    /* actually, we don't want zeroes; that could drop a large
Packit 06404a
       amplitude off a cliff, creating spread spectrum noise that will
Packit 06404a
       suck to encode.  Extrapolate for the sake of cleanliness. */
Packit 06404a
Packit 06404a
    vorbis_analysis_buffer(v,ci->blocksizes[1]*3);
Packit 06404a
    v->eofflag=v->pcm_current;
Packit 06404a
    v->pcm_current+=ci->blocksizes[1]*3;
Packit 06404a
Packit 06404a
    for(i=0;i<vi->channels;i++){
Packit 06404a
      if(v->eofflag>order*2){
Packit 06404a
        /* extrapolate with LPC to fill in */
Packit 06404a
        long n;
Packit 06404a
Packit 06404a
        /* make a predictor filter */
Packit 06404a
        n=v->eofflag;
Packit 06404a
        if(n>ci->blocksizes[1])n=ci->blocksizes[1];
Packit 06404a
        vorbis_lpc_from_data(v->pcm[i]+v->eofflag-n,lpc,n,order);
Packit 06404a
Packit 06404a
        /* run the predictor filter */
Packit 06404a
        vorbis_lpc_predict(lpc,v->pcm[i]+v->eofflag-order,order,
Packit 06404a
                           v->pcm[i]+v->eofflag,v->pcm_current-v->eofflag);
Packit 06404a
      }else{
Packit 06404a
        /* not enough data to extrapolate (unlikely to happen due to
Packit 06404a
           guarding the overlap, but bulletproof in case that
Packit 06404a
           assumtion goes away). zeroes will do. */
Packit 06404a
        memset(v->pcm[i]+v->eofflag,0,
Packit 06404a
               (v->pcm_current-v->eofflag)*sizeof(*v->pcm[i]));
Packit 06404a
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
  }else{
Packit 06404a
Packit 06404a
    if(v->pcm_current+vals>v->pcm_storage)
Packit 06404a
      return(OV_EINVAL);
Packit 06404a
Packit 06404a
    v->pcm_current+=vals;
Packit 06404a
Packit 06404a
    /* we may want to reverse extrapolate the beginning of a stream
Packit 06404a
       too... in case we're beginning on a cliff! */
Packit 06404a
    /* clumsy, but simple.  It only runs once, so simple is good. */
Packit 06404a
    if(!v->preextrapolate && v->pcm_current-v->centerW>ci->blocksizes[1])
Packit 06404a
      _preextrapolate_helper(v);
Packit 06404a
Packit 06404a
  }
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
/* do the deltas, envelope shaping, pre-echo and determine the size of
Packit 06404a
   the next block on which to continue analysis */
Packit 06404a
int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
Packit 06404a
  int i;
Packit 06404a
  vorbis_info *vi=v->vi;
Packit 06404a
  codec_setup_info *ci=vi->codec_setup;
Packit 06404a
  private_state *b=v->backend_state;
Packit 06404a
  vorbis_look_psy_global *g=b->psy_g_look;
Packit 06404a
  long beginW=v->centerW-ci->blocksizes[v->W]/2,centerNext;
Packit 06404a
  vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal;
Packit 06404a
Packit 06404a
  /* check to see if we're started... */
Packit 06404a
  if(!v->preextrapolate)return(0);
Packit 06404a
Packit 06404a
  /* check to see if we're done... */
Packit 06404a
  if(v->eofflag==-1)return(0);
Packit 06404a
Packit 06404a
  /* By our invariant, we have lW, W and centerW set.  Search for
Packit 06404a
     the next boundary so we can determine nW (the next window size)
Packit 06404a
     which lets us compute the shape of the current block's window */
Packit 06404a
Packit 06404a
  /* we do an envelope search even on a single blocksize; we may still
Packit 06404a
     be throwing more bits at impulses, and envelope search handles
Packit 06404a
     marking impulses too. */
Packit 06404a
  {
Packit 06404a
    long bp=_ve_envelope_search(v);
Packit 06404a
    if(bp==-1){
Packit 06404a
Packit 06404a
      if(v->eofflag==0)return(0); /* not enough data currently to search for a
Packit 06404a
                                     full long block */
Packit 06404a
      v->nW=0;
Packit 06404a
    }else{
Packit 06404a
Packit 06404a
      if(ci->blocksizes[0]==ci->blocksizes[1])
Packit 06404a
        v->nW=0;
Packit 06404a
      else
Packit 06404a
        v->nW=bp;
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  centerNext=v->centerW+ci->blocksizes[v->W]/4+ci->blocksizes[v->nW]/4;
Packit 06404a
Packit 06404a
  {
Packit 06404a
    /* center of next block + next block maximum right side. */
Packit 06404a
Packit 06404a
    long blockbound=centerNext+ci->blocksizes[v->nW]/2;
Packit 06404a
    if(v->pcm_current
Packit 06404a
                                               although this check is
Packit 06404a
                                               less strict that the
Packit 06404a
                                               _ve_envelope_search,
Packit 06404a
                                               the search is not run
Packit 06404a
                                               if we only use one
Packit 06404a
                                               block size */
Packit 06404a
Packit 06404a
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* fill in the block.  Note that for a short window, lW and nW are *short*
Packit 06404a
     regardless of actual settings in the stream */
Packit 06404a
Packit 06404a
  _vorbis_block_ripcord(vb);
Packit 06404a
  vb->lW=v->lW;
Packit 06404a
  vb->W=v->W;
Packit 06404a
  vb->nW=v->nW;
Packit 06404a
Packit 06404a
  if(v->W){
Packit 06404a
    if(!v->lW || !v->nW){
Packit 06404a
      vbi->blocktype=BLOCKTYPE_TRANSITION;
Packit 06404a
      /*fprintf(stderr,"-");*/
Packit 06404a
    }else{
Packit 06404a
      vbi->blocktype=BLOCKTYPE_LONG;
Packit 06404a
      /*fprintf(stderr,"_");*/
Packit 06404a
    }
Packit 06404a
  }else{
Packit 06404a
    if(_ve_envelope_mark(v)){
Packit 06404a
      vbi->blocktype=BLOCKTYPE_IMPULSE;
Packit 06404a
      /*fprintf(stderr,"|");*/
Packit 06404a
Packit 06404a
    }else{
Packit 06404a
      vbi->blocktype=BLOCKTYPE_PADDING;
Packit 06404a
      /*fprintf(stderr,".");*/
Packit 06404a
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  vb->vd=v;
Packit 06404a
  vb->sequence=v->sequence++;
Packit 06404a
  vb->granulepos=v->granulepos;
Packit 06404a
  vb->pcmend=ci->blocksizes[v->W];
Packit 06404a
Packit 06404a
  /* copy the vectors; this uses the local storage in vb */
Packit 06404a
Packit 06404a
  /* this tracks 'strongest peak' for later psychoacoustics */
Packit 06404a
  /* moved to the global psy state; clean this mess up */
Packit 06404a
  if(vbi->ampmax>g->ampmax)g->ampmax=vbi->ampmax;
Packit 06404a
  g->ampmax=_vp_ampmax_decay(g->ampmax,v);
Packit 06404a
  vbi->ampmax=g->ampmax;
Packit 06404a
Packit 06404a
  vb->pcm=_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
Packit 06404a
  vbi->pcmdelay=_vorbis_block_alloc(vb,sizeof(*vbi->pcmdelay)*vi->channels);
Packit 06404a
  for(i=0;i<vi->channels;i++){
Packit 06404a
    vbi->pcmdelay[i]=
Packit 06404a
      _vorbis_block_alloc(vb,(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i]));
Packit 06404a
    memcpy(vbi->pcmdelay[i],v->pcm[i],(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i]));
Packit 06404a
    vb->pcm[i]=vbi->pcmdelay[i]+beginW;
Packit 06404a
Packit 06404a
    /* before we added the delay
Packit 06404a
       vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
Packit 06404a
       memcpy(vb->pcm[i],v->pcm[i]+beginW,ci->blocksizes[v->W]*sizeof(*vb->pcm[i]));
Packit 06404a
    */
Packit 06404a
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* handle eof detection: eof==0 means that we've not yet received EOF
Packit 06404a
                           eof>0  marks the last 'real' sample in pcm[]
Packit 06404a
                           eof<0  'no more to do'; doesn't get here */
Packit 06404a
Packit 06404a
  if(v->eofflag){
Packit 06404a
    if(v->centerW>=v->eofflag){
Packit 06404a
      v->eofflag=-1;
Packit 06404a
      vb->eofflag=1;
Packit 06404a
      return(1);
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* advance storage vectors and clean up */
Packit 06404a
  {
Packit 06404a
    int new_centerNext=ci->blocksizes[1]/2;
Packit 06404a
    int movementW=centerNext-new_centerNext;
Packit 06404a
Packit 06404a
    if(movementW>0){
Packit 06404a
Packit 06404a
      _ve_envelope_shift(b->ve,movementW);
Packit 06404a
      v->pcm_current-=movementW;
Packit 06404a
Packit 06404a
      for(i=0;i<vi->channels;i++)
Packit 06404a
        memmove(v->pcm[i],v->pcm[i]+movementW,
Packit 06404a
                v->pcm_current*sizeof(*v->pcm[i]));
Packit 06404a
Packit 06404a
Packit 06404a
      v->lW=v->W;
Packit 06404a
      v->W=v->nW;
Packit 06404a
      v->centerW=new_centerNext;
Packit 06404a
Packit 06404a
      if(v->eofflag){
Packit 06404a
        v->eofflag-=movementW;
Packit 06404a
        if(v->eofflag<=0)v->eofflag=-1;
Packit 06404a
        /* do not add padding to end of stream! */
Packit 06404a
        if(v->centerW>=v->eofflag){
Packit 06404a
          v->granulepos+=movementW-(v->centerW-v->eofflag);
Packit 06404a
        }else{
Packit 06404a
          v->granulepos+=movementW;
Packit 06404a
        }
Packit 06404a
      }else{
Packit 06404a
        v->granulepos+=movementW;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* done */
Packit 06404a
  return(1);
Packit 06404a
}
Packit 06404a
Packit 06404a
int vorbis_synthesis_restart(vorbis_dsp_state *v){
Packit 06404a
  vorbis_info *vi=v->vi;
Packit 06404a
  codec_setup_info *ci;
Packit 06404a
  int hs;
Packit 06404a
Packit 06404a
  if(!v->backend_state)return -1;
Packit 06404a
  if(!vi)return -1;
Packit 06404a
  ci=vi->codec_setup;
Packit 06404a
  if(!ci)return -1;
Packit 06404a
  hs=ci->halfrate_flag;
Packit 06404a
Packit 06404a
  v->centerW=ci->blocksizes[1]>>(hs+1);
Packit 06404a
  v->pcm_current=v->centerW>>hs;
Packit 06404a
Packit 06404a
  v->pcm_returned=-1;
Packit 06404a
  v->granulepos=-1;
Packit 06404a
  v->sequence=-1;
Packit 06404a
  v->eofflag=0;
Packit 06404a
  ((private_state *)(v->backend_state))->sample_count=-1;
Packit 06404a
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
Packit 06404a
  if(_vds_shared_init(v,vi,0)){
Packit 06404a
    vorbis_dsp_clear(v);
Packit 06404a
    return 1;
Packit 06404a
  }
Packit 06404a
  vorbis_synthesis_restart(v);
Packit 06404a
  return 0;
Packit 06404a
}
Packit 06404a
Packit 06404a
/* Unlike in analysis, the window is only partially applied for each
Packit 06404a
   block.  The time domain envelope is not yet handled at the point of
Packit 06404a
   calling (as it relies on the previous block). */
Packit 06404a
Packit 06404a
int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
Packit 06404a
  vorbis_info *vi=v->vi;
Packit 06404a
  codec_setup_info *ci=vi->codec_setup;
Packit 06404a
  private_state *b=v->backend_state;
Packit 06404a
  int hs=ci->halfrate_flag;
Packit 06404a
  int i,j;
Packit 06404a
Packit 06404a
  if(!vb)return(OV_EINVAL);
Packit 06404a
  if(v->pcm_current>v->pcm_returned  && v->pcm_returned!=-1)return(OV_EINVAL);
Packit 06404a
Packit 06404a
  v->lW=v->W;
Packit 06404a
  v->W=vb->W;
Packit 06404a
  v->nW=-1;
Packit 06404a
Packit 06404a
  if((v->sequence==-1)||
Packit 06404a
     (v->sequence+1 != vb->sequence)){
Packit 06404a
    v->granulepos=-1; /* out of sequence; lose count */
Packit 06404a
    b->sample_count=-1;
Packit 06404a
  }
Packit 06404a
Packit 06404a
  v->sequence=vb->sequence;
Packit 06404a
Packit 06404a
  if(vb->pcm){  /* no pcm to process if vorbis_synthesis_trackonly
Packit 06404a
                   was called on block */
Packit 06404a
    int n=ci->blocksizes[v->W]>>(hs+1);
Packit 06404a
    int n0=ci->blocksizes[0]>>(hs+1);
Packit 06404a
    int n1=ci->blocksizes[1]>>(hs+1);
Packit 06404a
Packit 06404a
    int thisCenter;
Packit 06404a
    int prevCenter;
Packit 06404a
Packit 06404a
    v->glue_bits+=vb->glue_bits;
Packit 06404a
    v->time_bits+=vb->time_bits;
Packit 06404a
    v->floor_bits+=vb->floor_bits;
Packit 06404a
    v->res_bits+=vb->res_bits;
Packit 06404a
Packit 06404a
    if(v->centerW){
Packit 06404a
      thisCenter=n1;
Packit 06404a
      prevCenter=0;
Packit 06404a
    }else{
Packit 06404a
      thisCenter=0;
Packit 06404a
      prevCenter=n1;
Packit 06404a
    }
Packit 06404a
Packit 06404a
    /* v->pcm is now used like a two-stage double buffer.  We don't want
Packit 06404a
       to have to constantly shift *or* adjust memory usage.  Don't
Packit 06404a
       accept a new block until the old is shifted out */
Packit 06404a
Packit 06404a
    for(j=0;j<vi->channels;j++){
Packit 06404a
      /* the overlap/add section */
Packit 06404a
      if(v->lW){
Packit 06404a
        if(v->W){
Packit 06404a
          /* large/large */
Packit 06404a
          const float *w=_vorbis_window_get(b->window[1]-hs);
Packit 06404a
          float *pcm=v->pcm[j]+prevCenter;
Packit 06404a
          float *p=vb->pcm[j];
Packit 06404a
          for(i=0;i
Packit 06404a
            pcm[i]=pcm[i]*w[n1-i-1] + p[i]*w[i];
Packit 06404a
        }else{
Packit 06404a
          /* large/small */
Packit 06404a
          const float *w=_vorbis_window_get(b->window[0]-hs);
Packit 06404a
          float *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
Packit 06404a
          float *p=vb->pcm[j];
Packit 06404a
          for(i=0;i
Packit 06404a
            pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
Packit 06404a
        }
Packit 06404a
      }else{
Packit 06404a
        if(v->W){
Packit 06404a
          /* small/large */
Packit 06404a
          const float *w=_vorbis_window_get(b->window[0]-hs);
Packit 06404a
          float *pcm=v->pcm[j]+prevCenter;
Packit 06404a
          float *p=vb->pcm[j]+n1/2-n0/2;
Packit 06404a
          for(i=0;i
Packit 06404a
            pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
Packit 06404a
          for(;i
Packit 06404a
            pcm[i]=p[i];
Packit 06404a
        }else{
Packit 06404a
          /* small/small */
Packit 06404a
          const float *w=_vorbis_window_get(b->window[0]-hs);
Packit 06404a
          float *pcm=v->pcm[j]+prevCenter;
Packit 06404a
          float *p=vb->pcm[j];
Packit 06404a
          for(i=0;i
Packit 06404a
            pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
Packit 06404a
      /* the copy section */
Packit 06404a
      {
Packit 06404a
        float *pcm=v->pcm[j]+thisCenter;
Packit 06404a
        float *p=vb->pcm[j]+n;
Packit 06404a
        for(i=0;i
Packit 06404a
          pcm[i]=p[i];
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
Packit 06404a
    if(v->centerW)
Packit 06404a
      v->centerW=0;
Packit 06404a
    else
Packit 06404a
      v->centerW=n1;
Packit 06404a
Packit 06404a
    /* deal with initial packet state; we do this using the explicit
Packit 06404a
       pcm_returned==-1 flag otherwise we're sensitive to first block
Packit 06404a
       being short or long */
Packit 06404a
Packit 06404a
    if(v->pcm_returned==-1){
Packit 06404a
      v->pcm_returned=thisCenter;
Packit 06404a
      v->pcm_current=thisCenter;
Packit 06404a
    }else{
Packit 06404a
      v->pcm_returned=prevCenter;
Packit 06404a
      v->pcm_current=prevCenter+
Packit 06404a
        ((ci->blocksizes[v->lW]/4+
Packit 06404a
        ci->blocksizes[v->W]/4)>>hs);
Packit 06404a
    }
Packit 06404a
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* track the frame number... This is for convenience, but also
Packit 06404a
     making sure our last packet doesn't end with added padding.  If
Packit 06404a
     the last packet is partial, the number of samples we'll have to
Packit 06404a
     return will be past the vb->granulepos.
Packit 06404a
Packit 06404a
     This is not foolproof!  It will be confused if we begin
Packit 06404a
     decoding at the last page after a seek or hole.  In that case,
Packit 06404a
     we don't have a starting point to judge where the last frame
Packit 06404a
     is.  For this reason, vorbisfile will always try to make sure
Packit 06404a
     it reads the last two marked pages in proper sequence */
Packit 06404a
Packit 06404a
  if(b->sample_count==-1){
Packit 06404a
    b->sample_count=0;
Packit 06404a
  }else{
Packit 06404a
    b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
Packit 06404a
  }
Packit 06404a
Packit 06404a
  if(v->granulepos==-1){
Packit 06404a
    if(vb->granulepos!=-1){ /* only set if we have a position to set to */
Packit 06404a
Packit 06404a
      v->granulepos=vb->granulepos;
Packit 06404a
Packit 06404a
      /* is this a short page? */
Packit 06404a
      if(b->sample_count>v->granulepos){
Packit 06404a
        /* corner case; if this is both the first and last audio page,
Packit 06404a
           then spec says the end is cut, not beginning */
Packit 06404a
       long extra=b->sample_count-vb->granulepos;
Packit 06404a
Packit 06404a
        /* we use ogg_int64_t for granule positions because a
Packit 06404a
           uint64 isn't universally available.  Unfortunately,
Packit 06404a
           that means granposes can be 'negative' and result in
Packit 06404a
           extra being negative */
Packit 06404a
        if(extra<0)
Packit 06404a
          extra=0;
Packit 06404a
Packit 06404a
        if(vb->eofflag){
Packit 06404a
          /* trim the end */
Packit 06404a
          /* no preceding granulepos; assume we started at zero (we'd
Packit 06404a
             have to in a short single-page stream) */
Packit 06404a
          /* granulepos could be -1 due to a seek, but that would result
Packit 06404a
             in a long count, not short count */
Packit 06404a
Packit 06404a
          /* Guard against corrupt/malicious frames that set EOP and
Packit 06404a
             a backdated granpos; don't rewind more samples than we
Packit 06404a
             actually have */
Packit 06404a
          if(extra > (v->pcm_current - v->pcm_returned)<
Packit 06404a
            extra = (v->pcm_current - v->pcm_returned)<
Packit 06404a
Packit 06404a
          v->pcm_current-=extra>>hs;
Packit 06404a
        }else{
Packit 06404a
          /* trim the beginning */
Packit 06404a
          v->pcm_returned+=extra>>hs;
Packit 06404a
          if(v->pcm_returned>v->pcm_current)
Packit 06404a
            v->pcm_returned=v->pcm_current;
Packit 06404a
        }
Packit 06404a
Packit 06404a
      }
Packit 06404a
Packit 06404a
    }
Packit 06404a
  }else{
Packit 06404a
    v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
Packit 06404a
    if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
Packit 06404a
Packit 06404a
      if(v->granulepos>vb->granulepos){
Packit 06404a
        long extra=v->granulepos-vb->granulepos;
Packit 06404a
Packit 06404a
        if(extra)
Packit 06404a
          if(vb->eofflag){
Packit 06404a
            /* partial last frame.  Strip the extra samples off */
Packit 06404a
Packit 06404a
            /* Guard against corrupt/malicious frames that set EOP and
Packit 06404a
               a backdated granpos; don't rewind more samples than we
Packit 06404a
               actually have */
Packit 06404a
            if(extra > (v->pcm_current - v->pcm_returned)<
Packit 06404a
              extra = (v->pcm_current - v->pcm_returned)<
Packit 06404a
Packit 06404a
            /* we use ogg_int64_t for granule positions because a
Packit 06404a
               uint64 isn't universally available.  Unfortunately,
Packit 06404a
               that means granposes can be 'negative' and result in
Packit 06404a
               extra being negative */
Packit 06404a
            if(extra<0)
Packit 06404a
              extra=0;
Packit 06404a
Packit 06404a
            v->pcm_current-=extra>>hs;
Packit 06404a
          } /* else {Shouldn't happen *unless* the bitstream is out of
Packit 06404a
               spec.  Either way, believe the bitstream } */
Packit 06404a
      } /* else {Shouldn't happen *unless* the bitstream is out of
Packit 06404a
           spec.  Either way, believe the bitstream } */
Packit 06404a
      v->granulepos=vb->granulepos;
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* Update, cleanup */
Packit 06404a
Packit 06404a
  if(vb->eofflag)v->eofflag=1;
Packit 06404a
  return(0);
Packit 06404a
Packit 06404a
}
Packit 06404a
Packit 06404a
/* pcm==NULL indicates we just want the pending samples, no more */
Packit 06404a
int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm){
Packit 06404a
  vorbis_info *vi=v->vi;
Packit 06404a
Packit 06404a
  if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
Packit 06404a
    if(pcm){
Packit 06404a
      int i;
Packit 06404a
      for(i=0;i<vi->channels;i++)
Packit 06404a
        v->pcmret[i]=v->pcm[i]+v->pcm_returned;
Packit 06404a
      *pcm=v->pcmret;
Packit 06404a
    }
Packit 06404a
    return(v->pcm_current-v->pcm_returned);
Packit 06404a
  }
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
int vorbis_synthesis_read(vorbis_dsp_state *v,int n){
Packit 06404a
  if(n && v->pcm_returned+n>v->pcm_current)return(OV_EINVAL);
Packit 06404a
  v->pcm_returned+=n;
Packit 06404a
  return(0);
Packit 06404a
}
Packit 06404a
Packit 06404a
/* intended for use with a specific vorbisfile feature; we want access
Packit 06404a
   to the [usually synthetic/postextrapolated] buffer and lapping at
Packit 06404a
   the end of a decode cycle, specifically, a half-short-block worth.
Packit 06404a
   This funtion works like pcmout above, except it will also expose
Packit 06404a
   this implicit buffer data not normally decoded. */
Packit 06404a
int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm){
Packit 06404a
  vorbis_info *vi=v->vi;
Packit 06404a
  codec_setup_info *ci=vi->codec_setup;
Packit 06404a
  int hs=ci->halfrate_flag;
Packit 06404a
Packit 06404a
  int n=ci->blocksizes[v->W]>>(hs+1);
Packit 06404a
  int n0=ci->blocksizes[0]>>(hs+1);
Packit 06404a
  int n1=ci->blocksizes[1]>>(hs+1);
Packit 06404a
  int i,j;
Packit 06404a
Packit 06404a
  if(v->pcm_returned<0)return 0;
Packit 06404a
Packit 06404a
  /* our returned data ends at pcm_returned; because the synthesis pcm
Packit 06404a
     buffer is a two-fragment ring, that means our data block may be
Packit 06404a
     fragmented by buffering, wrapping or a short block not filling
Packit 06404a
     out a buffer.  To simplify things, we unfragment if it's at all
Packit 06404a
     possibly needed. Otherwise, we'd need to call lapout more than
Packit 06404a
     once as well as hold additional dsp state.  Opt for
Packit 06404a
     simplicity. */
Packit 06404a
Packit 06404a
  /* centerW was advanced by blockin; it would be the center of the
Packit 06404a
     *next* block */
Packit 06404a
  if(v->centerW==n1){
Packit 06404a
    /* the data buffer wraps; swap the halves */
Packit 06404a
    /* slow, sure, small */
Packit 06404a
    for(j=0;j<vi->channels;j++){
Packit 06404a
      float *p=v->pcm[j];
Packit 06404a
      for(i=0;i
Packit 06404a
        float temp=p[i];
Packit 06404a
        p[i]=p[i+n1];
Packit 06404a
        p[i+n1]=temp;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
Packit 06404a
    v->pcm_current-=n1;
Packit 06404a
    v->pcm_returned-=n1;
Packit 06404a
    v->centerW=0;
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* solidify buffer into contiguous space */
Packit 06404a
  if((v->lW^v->W)==1){
Packit 06404a
    /* long/short or short/long */
Packit 06404a
    for(j=0;j<vi->channels;j++){
Packit 06404a
      float *s=v->pcm[j];
Packit 06404a
      float *d=v->pcm[j]+(n1-n0)/2;
Packit 06404a
      for(i=(n1+n0)/2-1;i>=0;--i)
Packit 06404a
        d[i]=s[i];
Packit 06404a
    }
Packit 06404a
    v->pcm_returned+=(n1-n0)/2;
Packit 06404a
    v->pcm_current+=(n1-n0)/2;
Packit 06404a
  }else{
Packit 06404a
    if(v->lW==0){
Packit 06404a
      /* short/short */
Packit 06404a
      for(j=0;j<vi->channels;j++){
Packit 06404a
        float *s=v->pcm[j];
Packit 06404a
        float *d=v->pcm[j]+n1-n0;
Packit 06404a
        for(i=n0-1;i>=0;--i)
Packit 06404a
          d[i]=s[i];
Packit 06404a
      }
Packit 06404a
      v->pcm_returned+=n1-n0;
Packit 06404a
      v->pcm_current+=n1-n0;
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  if(pcm){
Packit 06404a
    int i;
Packit 06404a
    for(i=0;i<vi->channels;i++)
Packit 06404a
      v->pcmret[i]=v->pcm[i]+v->pcm_returned;
Packit 06404a
    *pcm=v->pcmret;
Packit 06404a
  }
Packit 06404a
Packit 06404a
  return(n1+n-v->pcm_returned);
Packit 06404a
Packit 06404a
}
Packit 06404a
Packit 06404a
const float *vorbis_window(vorbis_dsp_state *v,int W){
Packit 06404a
  vorbis_info *vi=v->vi;
Packit 06404a
  codec_setup_info *ci=vi->codec_setup;
Packit 06404a
  int hs=ci->halfrate_flag;
Packit 06404a
  private_state *b=v->backend_state;
Packit 06404a
Packit 06404a
  if(b->window[W]-1<0)return NULL;
Packit 06404a
  return _vorbis_window_get(b->window[W]-hs);
Packit 06404a
}