LCOV - code coverage report
Current view: directory - media/libvorbis/lib - vorbis_block.c (source / functions) Found Hit Coverage
Test: app.info Lines: 488 0 0.0 %
Date: 2012-06-02 Functions: 19 0 0.0 %

       1                 : /********************************************************************
       2                 :  *                                                                  *
       3                 :  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
       4                 :  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
       5                 :  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
       6                 :  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
       7                 :  *                                                                  *
       8                 :  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *
       9                 :  * by the Xiph.Org Foundation http://www.xiph.org/                  *
      10                 :  *                                                                  *
      11                 :  ********************************************************************
      12                 : 
      13                 :  function: PCM data vector blocking, windowing and dis/reassembly
      14                 :  last mod: $Id: block.c 17561 2010-10-23 10:34:24Z xiphmont $
      15                 : 
      16                 :  Handle windowing, overlap-add, etc of the PCM vectors.  This is made
      17                 :  more amusing by Vorbis' current two allowed block sizes.
      18                 : 
      19                 :  ********************************************************************/
      20                 : 
      21                 : #include <stdio.h>
      22                 : #include <stdlib.h>
      23                 : #include <string.h>
      24                 : #include <ogg/ogg.h>
      25                 : #include "vorbis/codec.h"
      26                 : #include "codec_internal.h"
      27                 : 
      28                 : #include "window.h"
      29                 : #include "mdct.h"
      30                 : #include "lpc.h"
      31                 : #include "registry.h"
      32                 : #include "misc.h"
      33                 : 
      34               0 : static int ilog2(unsigned int v){
      35               0 :   int ret=0;
      36               0 :   if(v)--v;
      37               0 :   while(v){
      38               0 :     ret++;
      39               0 :     v>>=1;
      40                 :   }
      41               0 :   return(ret);
      42                 : }
      43                 : 
      44                 : /* pcm accumulator examples (not exhaustive):
      45                 : 
      46                 :  <-------------- lW ---------------->
      47                 :                    <--------------- W ---------------->
      48                 : :            .....|.....       _______________         |
      49                 : :        .'''     |     '''_---      |       |\        |
      50                 : :.....'''         |_____--- '''......|       | \_______|
      51                 : :.................|__________________|_______|__|______|
      52                 :                   |<------ Sl ------>|      > Sr <     |endW
      53                 :                   |beginSl           |endSl  |  |endSr
      54                 :                   |beginW            |endlW  |beginSr
      55                 : 
      56                 : 
      57                 :                       |< lW >|
      58                 :                    <--------------- W ---------------->
      59                 :                   |   |  ..  ______________            |
      60                 :                   |   | '  `/        |     ---_        |
      61                 :                   |___.'___/`.       |         ---_____|
      62                 :                   |_______|__|_______|_________________|
      63                 :                   |      >|Sl|<      |<------ Sr ----->|endW
      64                 :                   |       |  |endSl  |beginSr          |endSr
      65                 :                   |beginW |  |endlW
      66                 :                   mult[0] |beginSl                     mult[n]
      67                 : 
      68                 :  <-------------- lW ----------------->
      69                 :                           |<--W-->|
      70                 : :            ..............  ___  |   |
      71                 : :        .'''             |`/   \ |   |
      72                 : :.....'''                 |/`....\|...|
      73                 : :.........................|___|___|___|
      74                 :                           |Sl |Sr |endW
      75                 :                           |   |   |endSr
      76                 :                           |   |beginSr
      77                 :                           |   |endSl
      78                 :                           |beginSl
      79                 :                           |beginW
      80                 : */
      81                 : 
      82                 : /* block abstraction setup *********************************************/
      83                 : 
      84                 : #ifndef WORD_ALIGN
      85                 : #define WORD_ALIGN 8
      86                 : #endif
      87                 : 
      88               0 : int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
      89                 :   int i;
      90               0 :   memset(vb,0,sizeof(*vb));
      91               0 :   vb->vd=v;
      92               0 :   vb->localalloc=0;
      93               0 :   vb->localstore=NULL;
      94               0 :   if(v->analysisp){
      95               0 :     vorbis_block_internal *vbi=
      96               0 :       vb->internal=_ogg_calloc(1,sizeof(vorbis_block_internal));
      97               0 :     vbi->ampmax=-9999;
      98                 : 
      99               0 :     for(i=0;i<PACKETBLOBS;i++){
     100               0 :       if(i==PACKETBLOBS/2){
     101               0 :         vbi->packetblob[i]=&vb->opb;
     102                 :       }else{
     103               0 :         vbi->packetblob[i]=
     104               0 :           _ogg_calloc(1,sizeof(oggpack_buffer));
     105                 :       }
     106               0 :       oggpack_writeinit(vbi->packetblob[i]);
     107                 :     }
     108                 :   }
     109                 : 
     110               0 :   return(0);
     111                 : }
     112                 : 
     113               0 : void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
     114               0 :   bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
     115               0 :   if(bytes+vb->localtop>vb->localalloc){
     116                 :     /* can't just _ogg_realloc... there are outstanding pointers */
     117               0 :     if(vb->localstore){
     118               0 :       struct alloc_chain *link=_ogg_malloc(sizeof(*link));
     119               0 :       vb->totaluse+=vb->localtop;
     120               0 :       link->next=vb->reap;
     121               0 :       link->ptr=vb->localstore;
     122               0 :       vb->reap=link;
     123                 :     }
     124                 :     /* highly conservative */
     125               0 :     vb->localalloc=bytes;
     126               0 :     vb->localstore=_ogg_malloc(vb->localalloc);
     127               0 :     vb->localtop=0;
     128                 :   }
     129                 :   {
     130               0 :     void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
     131               0 :     vb->localtop+=bytes;
     132               0 :     return ret;
     133                 :   }
     134                 : }
     135                 : 
     136                 : /* reap the chain, pull the ripcord */
     137               0 : void _vorbis_block_ripcord(vorbis_block *vb){
     138                 :   /* reap the chain */
     139               0 :   struct alloc_chain *reap=vb->reap;
     140               0 :   while(reap){
     141               0 :     struct alloc_chain *next=reap->next;
     142               0 :     _ogg_free(reap->ptr);
     143               0 :     memset(reap,0,sizeof(*reap));
     144               0 :     _ogg_free(reap);
     145               0 :     reap=next;
     146                 :   }
     147                 :   /* consolidate storage */
     148               0 :   if(vb->totaluse){
     149               0 :     vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
     150               0 :     vb->localalloc+=vb->totaluse;
     151               0 :     vb->totaluse=0;
     152                 :   }
     153                 : 
     154                 :   /* pull the ripcord */
     155               0 :   vb->localtop=0;
     156               0 :   vb->reap=NULL;
     157               0 : }
     158                 : 
     159               0 : int vorbis_block_clear(vorbis_block *vb){
     160                 :   int i;
     161               0 :   vorbis_block_internal *vbi=vb->internal;
     162                 : 
     163               0 :   _vorbis_block_ripcord(vb);
     164               0 :   if(vb->localstore)_ogg_free(vb->localstore);
     165                 : 
     166               0 :   if(vbi){
     167               0 :     for(i=0;i<PACKETBLOBS;i++){
     168               0 :       oggpack_writeclear(vbi->packetblob[i]);
     169               0 :       if(i!=PACKETBLOBS/2)_ogg_free(vbi->packetblob[i]);
     170                 :     }
     171               0 :     _ogg_free(vbi);
     172                 :   }
     173               0 :   memset(vb,0,sizeof(*vb));
     174               0 :   return(0);
     175                 : }
     176                 : 
     177                 : /* Analysis side code, but directly related to blocking.  Thus it's
     178                 :    here and not in analysis.c (which is for analysis transforms only).
     179                 :    The init is here because some of it is shared */
     180                 : 
     181               0 : static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi,int encp){
     182                 :   int i;
     183               0 :   codec_setup_info *ci=vi->codec_setup;
     184               0 :   private_state *b=NULL;
     185                 :   int hs;
     186                 : 
     187               0 :   if(ci==NULL) return 1;
     188               0 :   hs=ci->halfrate_flag;
     189                 : 
     190               0 :   memset(v,0,sizeof(*v));
     191               0 :   b=v->backend_state=_ogg_calloc(1,sizeof(*b));
     192                 : 
     193               0 :   v->vi=vi;
     194               0 :   b->modebits=ilog2(ci->modes);
     195                 : 
     196               0 :   b->transform[0]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[0]));
     197               0 :   b->transform[1]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[1]));
     198                 : 
     199                 :   /* MDCT is tranform 0 */
     200                 : 
     201               0 :   b->transform[0][0]=_ogg_calloc(1,sizeof(mdct_lookup));
     202               0 :   b->transform[1][0]=_ogg_calloc(1,sizeof(mdct_lookup));
     203               0 :   mdct_init(b->transform[0][0],ci->blocksizes[0]>>hs);
     204               0 :   mdct_init(b->transform[1][0],ci->blocksizes[1]>>hs);
     205                 : 
     206                 :   /* Vorbis I uses only window type 0 */
     207               0 :   b->window[0]=ilog2(ci->blocksizes[0])-6;
     208               0 :   b->window[1]=ilog2(ci->blocksizes[1])-6;
     209                 : 
     210               0 :   if(encp){ /* encode/decode differ here */
     211                 : 
     212                 :     /* analysis always needs an fft */
     213               0 :     drft_init(&b->fft_look[0],ci->blocksizes[0]);
     214               0 :     drft_init(&b->fft_look[1],ci->blocksizes[1]);
     215                 : 
     216                 :     /* finish the codebooks */
     217               0 :     if(!ci->fullbooks){
     218               0 :       ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
     219               0 :       for(i=0;i<ci->books;i++)
     220               0 :         vorbis_book_init_encode(ci->fullbooks+i,ci->book_param[i]);
     221                 :     }
     222                 : 
     223               0 :     b->psy=_ogg_calloc(ci->psys,sizeof(*b->psy));
     224               0 :     for(i=0;i<ci->psys;i++){
     225               0 :       _vp_psy_init(b->psy+i,
     226                 :                    ci->psy_param[i],
     227                 :                    &ci->psy_g_param,
     228               0 :                    ci->blocksizes[ci->psy_param[i]->blockflag]/2,
     229                 :                    vi->rate);
     230                 :     }
     231                 : 
     232               0 :     v->analysisp=1;
     233                 :   }else{
     234                 :     /* finish the codebooks */
     235               0 :     if(!ci->fullbooks){
     236               0 :       ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
     237               0 :       for(i=0;i<ci->books;i++){
     238               0 :         if(ci->book_param[i]==NULL)
     239               0 :           goto abort_books;
     240               0 :         if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
     241               0 :           goto abort_books;
     242                 :         /* decode codebooks are now standalone after init */
     243               0 :         vorbis_staticbook_destroy(ci->book_param[i]);
     244               0 :         ci->book_param[i]=NULL;
     245                 :       }
     246                 :     }
     247                 :   }
     248                 : 
     249                 :   /* initialize the storage vectors. blocksize[1] is small for encode,
     250                 :      but the correct size for decode */
     251               0 :   v->pcm_storage=ci->blocksizes[1];
     252               0 :   v->pcm=_ogg_malloc(vi->channels*sizeof(*v->pcm));
     253               0 :   v->pcmret=_ogg_malloc(vi->channels*sizeof(*v->pcmret));
     254                 :   {
     255                 :     int i;
     256               0 :     for(i=0;i<vi->channels;i++)
     257               0 :       v->pcm[i]=_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
     258                 :   }
     259                 : 
     260                 :   /* all 1 (large block) or 0 (small block) */
     261                 :   /* explicitly set for the sake of clarity */
     262               0 :   v->lW=0; /* previous window size */
     263               0 :   v->W=0;  /* current window size */
     264                 : 
     265                 :   /* all vector indexes */
     266               0 :   v->centerW=ci->blocksizes[1]/2;
     267                 : 
     268               0 :   v->pcm_current=v->centerW;
     269                 : 
     270                 :   /* initialize all the backend lookups */
     271               0 :   b->flr=_ogg_calloc(ci->floors,sizeof(*b->flr));
     272               0 :   b->residue=_ogg_calloc(ci->residues,sizeof(*b->residue));
     273                 : 
     274               0 :   for(i=0;i<ci->floors;i++)
     275               0 :     b->flr[i]=_floor_P[ci->floor_type[i]]->
     276               0 :       look(v,ci->floor_param[i]);
     277                 : 
     278               0 :   for(i=0;i<ci->residues;i++)
     279               0 :     b->residue[i]=_residue_P[ci->residue_type[i]]->
     280               0 :       look(v,ci->residue_param[i]);
     281                 : 
     282               0 :   return 0;
     283                 :  abort_books:
     284               0 :   for(i=0;i<ci->books;i++){
     285               0 :     if(ci->book_param[i]!=NULL){
     286               0 :       vorbis_staticbook_destroy(ci->book_param[i]);
     287               0 :       ci->book_param[i]=NULL;
     288                 :     }
     289                 :   }
     290               0 :   vorbis_dsp_clear(v);
     291               0 :   return -1;
     292                 : }
     293                 : 
     294                 : /* arbitrary settings and spec-mandated numbers get filled in here */
     295               0 : int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){
     296               0 :   private_state *b=NULL;
     297                 : 
     298               0 :   if(_vds_shared_init(v,vi,1))return 1;
     299               0 :   b=v->backend_state;
     300               0 :   b->psy_g_look=_vp_global_look(vi);
     301                 : 
     302                 :   /* Initialize the envelope state storage */
     303               0 :   b->ve=_ogg_calloc(1,sizeof(*b->ve));
     304               0 :   _ve_envelope_init(b->ve,vi);
     305                 : 
     306               0 :   vorbis_bitrate_init(vi,&b->bms);
     307                 : 
     308                 :   /* compressed audio packets start after the headers
     309                 :      with sequence number 3 */
     310               0 :   v->sequence=3;
     311                 : 
     312               0 :   return(0);
     313                 : }
     314                 : 
     315               0 : void vorbis_dsp_clear(vorbis_dsp_state *v){
     316                 :   int i;
     317               0 :   if(v){
     318               0 :     vorbis_info *vi=v->vi;
     319               0 :     codec_setup_info *ci=(vi?vi->codec_setup:NULL);
     320               0 :     private_state *b=v->backend_state;
     321                 : 
     322               0 :     if(b){
     323                 : 
     324               0 :       if(b->ve){
     325               0 :         _ve_envelope_clear(b->ve);
     326               0 :         _ogg_free(b->ve);
     327                 :       }
     328                 : 
     329               0 :       if(b->transform[0]){
     330               0 :         mdct_clear(b->transform[0][0]);
     331               0 :         _ogg_free(b->transform[0][0]);
     332               0 :         _ogg_free(b->transform[0]);
     333                 :       }
     334               0 :       if(b->transform[1]){
     335               0 :         mdct_clear(b->transform[1][0]);
     336               0 :         _ogg_free(b->transform[1][0]);
     337               0 :         _ogg_free(b->transform[1]);
     338                 :       }
     339                 : 
     340               0 :       if(b->flr){
     341               0 :         if(ci)
     342               0 :           for(i=0;i<ci->floors;i++)
     343               0 :             _floor_P[ci->floor_type[i]]->
     344               0 :               free_look(b->flr[i]);
     345               0 :         _ogg_free(b->flr);
     346                 :       }
     347               0 :       if(b->residue){
     348               0 :         if(ci)
     349               0 :           for(i=0;i<ci->residues;i++)
     350               0 :             _residue_P[ci->residue_type[i]]->
     351               0 :               free_look(b->residue[i]);
     352               0 :         _ogg_free(b->residue);
     353                 :       }
     354               0 :       if(b->psy){
     355               0 :         if(ci)
     356               0 :           for(i=0;i<ci->psys;i++)
     357               0 :             _vp_psy_clear(b->psy+i);
     358               0 :         _ogg_free(b->psy);
     359                 :       }
     360                 : 
     361               0 :       if(b->psy_g_look)_vp_global_free(b->psy_g_look);
     362               0 :       vorbis_bitrate_clear(&b->bms);
     363                 : 
     364               0 :       drft_clear(&b->fft_look[0]);
     365               0 :       drft_clear(&b->fft_look[1]);
     366                 : 
     367                 :     }
     368                 : 
     369               0 :     if(v->pcm){
     370               0 :       if(vi)
     371               0 :         for(i=0;i<vi->channels;i++)
     372               0 :           if(v->pcm[i])_ogg_free(v->pcm[i]);
     373               0 :       _ogg_free(v->pcm);
     374               0 :       if(v->pcmret)_ogg_free(v->pcmret);
     375                 :     }
     376                 : 
     377               0 :     if(b){
     378                 :       /* free header, header1, header2 */
     379               0 :       if(b->header)_ogg_free(b->header);
     380               0 :       if(b->header1)_ogg_free(b->header1);
     381               0 :       if(b->header2)_ogg_free(b->header2);
     382               0 :       _ogg_free(b);
     383                 :     }
     384                 : 
     385               0 :     memset(v,0,sizeof(*v));
     386                 :   }
     387               0 : }
     388                 : 
     389               0 : float **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){
     390                 :   int i;
     391               0 :   vorbis_info *vi=v->vi;
     392               0 :   private_state *b=v->backend_state;
     393                 : 
     394                 :   /* free header, header1, header2 */
     395               0 :   if(b->header)_ogg_free(b->header);b->header=NULL;
     396               0 :   if(b->header1)_ogg_free(b->header1);b->header1=NULL;
     397               0 :   if(b->header2)_ogg_free(b->header2);b->header2=NULL;
     398                 : 
     399                 :   /* Do we have enough storage space for the requested buffer? If not,
     400                 :      expand the PCM (and envelope) storage */
     401                 : 
     402               0 :   if(v->pcm_current+vals>=v->pcm_storage){
     403               0 :     v->pcm_storage=v->pcm_current+vals*2;
     404                 : 
     405               0 :     for(i=0;i<vi->channels;i++){
     406               0 :       v->pcm[i]=_ogg_realloc(v->pcm[i],v->pcm_storage*sizeof(*v->pcm[i]));
     407                 :     }
     408                 :   }
     409                 : 
     410               0 :   for(i=0;i<vi->channels;i++)
     411               0 :     v->pcmret[i]=v->pcm[i]+v->pcm_current;
     412                 : 
     413               0 :   return(v->pcmret);
     414                 : }
     415                 : 
     416               0 : static void _preextrapolate_helper(vorbis_dsp_state *v){
     417                 :   int i;
     418               0 :   int order=16;
     419               0 :   float *lpc=alloca(order*sizeof(*lpc));
     420               0 :   float *work=alloca(v->pcm_current*sizeof(*work));
     421                 :   long j;
     422               0 :   v->preextrapolate=1;
     423                 : 
     424               0 :   if(v->pcm_current-v->centerW>order*2){ /* safety */
     425               0 :     for(i=0;i<v->vi->channels;i++){
     426                 :       /* need to run the extrapolation in reverse! */
     427               0 :       for(j=0;j<v->pcm_current;j++)
     428               0 :         work[j]=v->pcm[i][v->pcm_current-j-1];
     429                 : 
     430                 :       /* prime as above */
     431               0 :       vorbis_lpc_from_data(work,lpc,v->pcm_current-v->centerW,order);
     432                 : 
     433                 : #if 0
     434                 :       if(v->vi->channels==2){
     435                 :         if(i==0)
     436                 :           _analysis_output("predataL",0,work,v->pcm_current-v->centerW,0,0,0);
     437                 :         else
     438                 :           _analysis_output("predataR",0,work,v->pcm_current-v->centerW,0,0,0);
     439                 :       }else{
     440                 :         _analysis_output("predata",0,work,v->pcm_current-v->centerW,0,0,0);
     441                 :       }
     442                 : #endif
     443                 : 
     444                 :       /* run the predictor filter */
     445               0 :       vorbis_lpc_predict(lpc,work+v->pcm_current-v->centerW-order,
     446                 :                          order,
     447               0 :                          work+v->pcm_current-v->centerW,
     448                 :                          v->centerW);
     449                 : 
     450               0 :       for(j=0;j<v->pcm_current;j++)
     451               0 :         v->pcm[i][v->pcm_current-j-1]=work[j];
     452                 : 
     453                 :     }
     454                 :   }
     455               0 : }
     456                 : 
     457                 : 
     458                 : /* call with val<=0 to set eof */
     459                 : 
     460               0 : int vorbis_analysis_wrote(vorbis_dsp_state *v, int vals){
     461               0 :   vorbis_info *vi=v->vi;
     462               0 :   codec_setup_info *ci=vi->codec_setup;
     463                 : 
     464               0 :   if(vals<=0){
     465               0 :     int order=32;
     466                 :     int i;
     467               0 :     float *lpc=alloca(order*sizeof(*lpc));
     468                 : 
     469                 :     /* if it wasn't done earlier (very short sample) */
     470               0 :     if(!v->preextrapolate)
     471               0 :       _preextrapolate_helper(v);
     472                 : 
     473                 :     /* We're encoding the end of the stream.  Just make sure we have
     474                 :        [at least] a few full blocks of zeroes at the end. */
     475                 :     /* actually, we don't want zeroes; that could drop a large
     476                 :        amplitude off a cliff, creating spread spectrum noise that will
     477                 :        suck to encode.  Extrapolate for the sake of cleanliness. */
     478                 : 
     479               0 :     vorbis_analysis_buffer(v,ci->blocksizes[1]*3);
     480               0 :     v->eofflag=v->pcm_current;
     481               0 :     v->pcm_current+=ci->blocksizes[1]*3;
     482                 : 
     483               0 :     for(i=0;i<vi->channels;i++){
     484               0 :       if(v->eofflag>order*2){
     485                 :         /* extrapolate with LPC to fill in */
     486                 :         long n;
     487                 : 
     488                 :         /* make a predictor filter */
     489               0 :         n=v->eofflag;
     490               0 :         if(n>ci->blocksizes[1])n=ci->blocksizes[1];
     491               0 :         vorbis_lpc_from_data(v->pcm[i]+v->eofflag-n,lpc,n,order);
     492                 : 
     493                 :         /* run the predictor filter */
     494               0 :         vorbis_lpc_predict(lpc,v->pcm[i]+v->eofflag-order,order,
     495               0 :                            v->pcm[i]+v->eofflag,v->pcm_current-v->eofflag);
     496                 :       }else{
     497                 :         /* not enough data to extrapolate (unlikely to happen due to
     498                 :            guarding the overlap, but bulletproof in case that
     499                 :            assumtion goes away). zeroes will do. */
     500               0 :         memset(v->pcm[i]+v->eofflag,0,
     501               0 :                (v->pcm_current-v->eofflag)*sizeof(*v->pcm[i]));
     502                 : 
     503                 :       }
     504                 :     }
     505                 :   }else{
     506                 : 
     507               0 :     if(v->pcm_current+vals>v->pcm_storage)
     508               0 :       return(OV_EINVAL);
     509                 : 
     510               0 :     v->pcm_current+=vals;
     511                 : 
     512                 :     /* we may want to reverse extrapolate the beginning of a stream
     513                 :        too... in case we're beginning on a cliff! */
     514                 :     /* clumsy, but simple.  It only runs once, so simple is good. */
     515               0 :     if(!v->preextrapolate && v->pcm_current-v->centerW>ci->blocksizes[1])
     516               0 :       _preextrapolate_helper(v);
     517                 : 
     518                 :   }
     519               0 :   return(0);
     520                 : }
     521                 : 
     522                 : /* do the deltas, envelope shaping, pre-echo and determine the size of
     523                 :    the next block on which to continue analysis */
     524               0 : int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
     525                 :   int i;
     526               0 :   vorbis_info *vi=v->vi;
     527               0 :   codec_setup_info *ci=vi->codec_setup;
     528               0 :   private_state *b=v->backend_state;
     529               0 :   vorbis_look_psy_global *g=b->psy_g_look;
     530               0 :   long beginW=v->centerW-ci->blocksizes[v->W]/2,centerNext;
     531               0 :   vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal;
     532                 : 
     533                 :   /* check to see if we're started... */
     534               0 :   if(!v->preextrapolate)return(0);
     535                 : 
     536                 :   /* check to see if we're done... */
     537               0 :   if(v->eofflag==-1)return(0);
     538                 : 
     539                 :   /* By our invariant, we have lW, W and centerW set.  Search for
     540                 :      the next boundary so we can determine nW (the next window size)
     541                 :      which lets us compute the shape of the current block's window */
     542                 : 
     543                 :   /* we do an envelope search even on a single blocksize; we may still
     544                 :      be throwing more bits at impulses, and envelope search handles
     545                 :      marking impulses too. */
     546                 :   {
     547               0 :     long bp=_ve_envelope_search(v);
     548               0 :     if(bp==-1){
     549                 : 
     550               0 :       if(v->eofflag==0)return(0); /* not enough data currently to search for a
     551                 :                                      full long block */
     552               0 :       v->nW=0;
     553                 :     }else{
     554                 : 
     555               0 :       if(ci->blocksizes[0]==ci->blocksizes[1])
     556               0 :         v->nW=0;
     557                 :       else
     558               0 :         v->nW=bp;
     559                 :     }
     560                 :   }
     561                 : 
     562               0 :   centerNext=v->centerW+ci->blocksizes[v->W]/4+ci->blocksizes[v->nW]/4;
     563                 : 
     564                 :   {
     565                 :     /* center of next block + next block maximum right side. */
     566                 : 
     567               0 :     long blockbound=centerNext+ci->blocksizes[v->nW]/2;
     568               0 :     if(v->pcm_current<blockbound)return(0); /* not enough data yet;
     569                 :                                                although this check is
     570                 :                                                less strict that the
     571                 :                                                _ve_envelope_search,
     572                 :                                                the search is not run
     573                 :                                                if we only use one
     574                 :                                                block size */
     575                 : 
     576                 : 
     577                 :   }
     578                 : 
     579                 :   /* fill in the block.  Note that for a short window, lW and nW are *short*
     580                 :      regardless of actual settings in the stream */
     581                 : 
     582               0 :   _vorbis_block_ripcord(vb);
     583               0 :   vb->lW=v->lW;
     584               0 :   vb->W=v->W;
     585               0 :   vb->nW=v->nW;
     586                 : 
     587               0 :   if(v->W){
     588               0 :     if(!v->lW || !v->nW){
     589               0 :       vbi->blocktype=BLOCKTYPE_TRANSITION;
     590                 :       /*fprintf(stderr,"-");*/
     591                 :     }else{
     592               0 :       vbi->blocktype=BLOCKTYPE_LONG;
     593                 :       /*fprintf(stderr,"_");*/
     594                 :     }
     595                 :   }else{
     596               0 :     if(_ve_envelope_mark(v)){
     597               0 :       vbi->blocktype=BLOCKTYPE_IMPULSE;
     598                 :       /*fprintf(stderr,"|");*/
     599                 : 
     600                 :     }else{
     601               0 :       vbi->blocktype=BLOCKTYPE_PADDING;
     602                 :       /*fprintf(stderr,".");*/
     603                 : 
     604                 :     }
     605                 :   }
     606                 : 
     607               0 :   vb->vd=v;
     608               0 :   vb->sequence=v->sequence++;
     609               0 :   vb->granulepos=v->granulepos;
     610               0 :   vb->pcmend=ci->blocksizes[v->W];
     611                 : 
     612                 :   /* copy the vectors; this uses the local storage in vb */
     613                 : 
     614                 :   /* this tracks 'strongest peak' for later psychoacoustics */
     615                 :   /* moved to the global psy state; clean this mess up */
     616               0 :   if(vbi->ampmax>g->ampmax)g->ampmax=vbi->ampmax;
     617               0 :   g->ampmax=_vp_ampmax_decay(g->ampmax,v);
     618               0 :   vbi->ampmax=g->ampmax;
     619                 : 
     620               0 :   vb->pcm=_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
     621               0 :   vbi->pcmdelay=_vorbis_block_alloc(vb,sizeof(*vbi->pcmdelay)*vi->channels);
     622               0 :   for(i=0;i<vi->channels;i++){
     623               0 :     vbi->pcmdelay[i]=
     624               0 :       _vorbis_block_alloc(vb,(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i]));
     625               0 :     memcpy(vbi->pcmdelay[i],v->pcm[i],(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i]));
     626               0 :     vb->pcm[i]=vbi->pcmdelay[i]+beginW;
     627                 : 
     628                 :     /* before we added the delay
     629                 :        vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
     630                 :        memcpy(vb->pcm[i],v->pcm[i]+beginW,ci->blocksizes[v->W]*sizeof(*vb->pcm[i]));
     631                 :     */
     632                 : 
     633                 :   }
     634                 : 
     635                 :   /* handle eof detection: eof==0 means that we've not yet received EOF
     636                 :                            eof>0  marks the last 'real' sample in pcm[]
     637                 :                            eof<0  'no more to do'; doesn't get here */
     638                 : 
     639               0 :   if(v->eofflag){
     640               0 :     if(v->centerW>=v->eofflag){
     641               0 :       v->eofflag=-1;
     642               0 :       vb->eofflag=1;
     643               0 :       return(1);
     644                 :     }
     645                 :   }
     646                 : 
     647                 :   /* advance storage vectors and clean up */
     648                 :   {
     649               0 :     int new_centerNext=ci->blocksizes[1]/2;
     650               0 :     int movementW=centerNext-new_centerNext;
     651                 : 
     652               0 :     if(movementW>0){
     653                 : 
     654               0 :       _ve_envelope_shift(b->ve,movementW);
     655               0 :       v->pcm_current-=movementW;
     656                 : 
     657               0 :       for(i=0;i<vi->channels;i++)
     658               0 :         memmove(v->pcm[i],v->pcm[i]+movementW,
     659               0 :                 v->pcm_current*sizeof(*v->pcm[i]));
     660                 : 
     661                 : 
     662               0 :       v->lW=v->W;
     663               0 :       v->W=v->nW;
     664               0 :       v->centerW=new_centerNext;
     665                 : 
     666               0 :       if(v->eofflag){
     667               0 :         v->eofflag-=movementW;
     668               0 :         if(v->eofflag<=0)v->eofflag=-1;
     669                 :         /* do not add padding to end of stream! */
     670               0 :         if(v->centerW>=v->eofflag){
     671               0 :           v->granulepos+=movementW-(v->centerW-v->eofflag);
     672                 :         }else{
     673               0 :           v->granulepos+=movementW;
     674                 :         }
     675                 :       }else{
     676               0 :         v->granulepos+=movementW;
     677                 :       }
     678                 :     }
     679                 :   }
     680                 : 
     681                 :   /* done */
     682               0 :   return(1);
     683                 : }
     684                 : 
     685               0 : int vorbis_synthesis_restart(vorbis_dsp_state *v){
     686               0 :   vorbis_info *vi=v->vi;
     687                 :   codec_setup_info *ci;
     688                 :   int hs;
     689                 : 
     690               0 :   if(!v->backend_state)return -1;
     691               0 :   if(!vi)return -1;
     692               0 :   ci=vi->codec_setup;
     693               0 :   if(!ci)return -1;
     694               0 :   hs=ci->halfrate_flag;
     695                 : 
     696               0 :   v->centerW=ci->blocksizes[1]>>(hs+1);
     697               0 :   v->pcm_current=v->centerW>>hs;
     698                 : 
     699               0 :   v->pcm_returned=-1;
     700               0 :   v->granulepos=-1;
     701               0 :   v->sequence=-1;
     702               0 :   v->eofflag=0;
     703               0 :   ((private_state *)(v->backend_state))->sample_count=-1;
     704                 : 
     705               0 :   return(0);
     706                 : }
     707                 : 
     708               0 : int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
     709               0 :   if(_vds_shared_init(v,vi,0)){
     710               0 :     vorbis_dsp_clear(v);
     711               0 :     return 1;
     712                 :   }
     713               0 :   vorbis_synthesis_restart(v);
     714               0 :   return 0;
     715                 : }
     716                 : 
     717                 : /* Unlike in analysis, the window is only partially applied for each
     718                 :    block.  The time domain envelope is not yet handled at the point of
     719                 :    calling (as it relies on the previous block). */
     720                 : 
     721               0 : int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
     722               0 :   vorbis_info *vi=v->vi;
     723               0 :   codec_setup_info *ci=vi->codec_setup;
     724               0 :   private_state *b=v->backend_state;
     725               0 :   int hs=ci->halfrate_flag;
     726                 :   int i,j;
     727                 : 
     728               0 :   if(!vb)return(OV_EINVAL);
     729               0 :   if(v->pcm_current>v->pcm_returned  && v->pcm_returned!=-1)return(OV_EINVAL);
     730                 : 
     731               0 :   v->lW=v->W;
     732               0 :   v->W=vb->W;
     733               0 :   v->nW=-1;
     734                 : 
     735               0 :   if((v->sequence==-1)||
     736               0 :      (v->sequence+1 != vb->sequence)){
     737               0 :     v->granulepos=-1; /* out of sequence; lose count */
     738               0 :     b->sample_count=-1;
     739                 :   }
     740                 : 
     741               0 :   v->sequence=vb->sequence;
     742                 : 
     743               0 :   if(vb->pcm){  /* no pcm to process if vorbis_synthesis_trackonly
     744                 :                    was called on block */
     745               0 :     int n=ci->blocksizes[v->W]>>(hs+1);
     746               0 :     int n0=ci->blocksizes[0]>>(hs+1);
     747               0 :     int n1=ci->blocksizes[1]>>(hs+1);
     748                 : 
     749                 :     int thisCenter;
     750                 :     int prevCenter;
     751                 : 
     752               0 :     v->glue_bits+=vb->glue_bits;
     753               0 :     v->time_bits+=vb->time_bits;
     754               0 :     v->floor_bits+=vb->floor_bits;
     755               0 :     v->res_bits+=vb->res_bits;
     756                 : 
     757               0 :     if(v->centerW){
     758               0 :       thisCenter=n1;
     759               0 :       prevCenter=0;
     760                 :     }else{
     761               0 :       thisCenter=0;
     762               0 :       prevCenter=n1;
     763                 :     }
     764                 : 
     765                 :     /* v->pcm is now used like a two-stage double buffer.  We don't want
     766                 :        to have to constantly shift *or* adjust memory usage.  Don't
     767                 :        accept a new block until the old is shifted out */
     768                 : 
     769               0 :     for(j=0;j<vi->channels;j++){
     770                 :       /* the overlap/add section */
     771               0 :       if(v->lW){
     772               0 :         if(v->W){
     773                 :           /* large/large */
     774               0 :           float *w=_vorbis_window_get(b->window[1]-hs);
     775               0 :           float *pcm=v->pcm[j]+prevCenter;
     776               0 :           float *p=vb->pcm[j];
     777               0 :           for(i=0;i<n1;i++)
     778               0 :             pcm[i]=pcm[i]*w[n1-i-1] + p[i]*w[i];
     779                 :         }else{
     780                 :           /* large/small */
     781               0 :           float *w=_vorbis_window_get(b->window[0]-hs);
     782               0 :           float *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
     783               0 :           float *p=vb->pcm[j];
     784               0 :           for(i=0;i<n0;i++)
     785               0 :             pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
     786                 :         }
     787                 :       }else{
     788               0 :         if(v->W){
     789                 :           /* small/large */
     790               0 :           float *w=_vorbis_window_get(b->window[0]-hs);
     791               0 :           float *pcm=v->pcm[j]+prevCenter;
     792               0 :           float *p=vb->pcm[j]+n1/2-n0/2;
     793               0 :           for(i=0;i<n0;i++)
     794               0 :             pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
     795               0 :           for(;i<n1/2+n0/2;i++)
     796               0 :             pcm[i]=p[i];
     797                 :         }else{
     798                 :           /* small/small */
     799               0 :           float *w=_vorbis_window_get(b->window[0]-hs);
     800               0 :           float *pcm=v->pcm[j]+prevCenter;
     801               0 :           float *p=vb->pcm[j];
     802               0 :           for(i=0;i<n0;i++)
     803               0 :             pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i];
     804                 :         }
     805                 :       }
     806                 : 
     807                 :       /* the copy section */
     808                 :       {
     809               0 :         float *pcm=v->pcm[j]+thisCenter;
     810               0 :         float *p=vb->pcm[j]+n;
     811               0 :         for(i=0;i<n;i++)
     812               0 :           pcm[i]=p[i];
     813                 :       }
     814                 :     }
     815                 : 
     816               0 :     if(v->centerW)
     817               0 :       v->centerW=0;
     818                 :     else
     819               0 :       v->centerW=n1;
     820                 : 
     821                 :     /* deal with initial packet state; we do this using the explicit
     822                 :        pcm_returned==-1 flag otherwise we're sensitive to first block
     823                 :        being short or long */
     824                 : 
     825               0 :     if(v->pcm_returned==-1){
     826               0 :       v->pcm_returned=thisCenter;
     827               0 :       v->pcm_current=thisCenter;
     828                 :     }else{
     829               0 :       v->pcm_returned=prevCenter;
     830               0 :       v->pcm_current=prevCenter+
     831               0 :         ((ci->blocksizes[v->lW]/4+
     832               0 :         ci->blocksizes[v->W]/4)>>hs);
     833                 :     }
     834                 : 
     835                 :   }
     836                 : 
     837                 :   /* track the frame number... This is for convenience, but also
     838                 :      making sure our last packet doesn't end with added padding.  If
     839                 :      the last packet is partial, the number of samples we'll have to
     840                 :      return will be past the vb->granulepos.
     841                 : 
     842                 :      This is not foolproof!  It will be confused if we begin
     843                 :      decoding at the last page after a seek or hole.  In that case,
     844                 :      we don't have a starting point to judge where the last frame
     845                 :      is.  For this reason, vorbisfile will always try to make sure
     846                 :      it reads the last two marked pages in proper sequence */
     847                 : 
     848               0 :   if(b->sample_count==-1){
     849               0 :     b->sample_count=0;
     850                 :   }else{
     851               0 :     b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
     852                 :   }
     853                 : 
     854               0 :   if(v->granulepos==-1){
     855               0 :     if(vb->granulepos!=-1){ /* only set if we have a position to set to */
     856                 : 
     857               0 :       v->granulepos=vb->granulepos;
     858                 : 
     859                 :       /* is this a short page? */
     860               0 :       if(b->sample_count>v->granulepos){
     861                 :         /* corner case; if this is both the first and last audio page,
     862                 :            then spec says the end is cut, not beginning */
     863               0 :        long extra=b->sample_count-vb->granulepos;
     864                 : 
     865                 :         /* we use ogg_int64_t for granule positions because a
     866                 :            uint64 isn't universally available.  Unfortunately,
     867                 :            that means granposes can be 'negative' and result in
     868                 :            extra being negative */
     869               0 :         if(extra<0)
     870               0 :           extra=0;
     871                 : 
     872               0 :         if(vb->eofflag){
     873                 :           /* trim the end */
     874                 :           /* no preceding granulepos; assume we started at zero (we'd
     875                 :              have to in a short single-page stream) */
     876                 :           /* granulepos could be -1 due to a seek, but that would result
     877                 :              in a long count, not short count */
     878                 : 
     879                 :           /* Guard against corrupt/malicious frames that set EOP and
     880                 :              a backdated granpos; don't rewind more samples than we
     881                 :              actually have */
     882               0 :           if(extra > (v->pcm_current - v->pcm_returned)<<hs)
     883               0 :             extra = (v->pcm_current - v->pcm_returned)<<hs;
     884                 : 
     885               0 :           v->pcm_current-=extra>>hs;
     886                 :         }else{
     887                 :           /* trim the beginning */
     888               0 :           v->pcm_returned+=extra>>hs;
     889               0 :           if(v->pcm_returned>v->pcm_current)
     890               0 :             v->pcm_returned=v->pcm_current;
     891                 :         }
     892                 : 
     893                 :       }
     894                 : 
     895                 :     }
     896                 :   }else{
     897               0 :     v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
     898               0 :     if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
     899                 : 
     900               0 :       if(v->granulepos>vb->granulepos){
     901               0 :         long extra=v->granulepos-vb->granulepos;
     902                 : 
     903               0 :         if(extra)
     904               0 :           if(vb->eofflag){
     905                 :             /* partial last frame.  Strip the extra samples off */
     906                 : 
     907                 :             /* Guard against corrupt/malicious frames that set EOP and
     908                 :                a backdated granpos; don't rewind more samples than we
     909                 :                actually have */
     910               0 :             if(extra > (v->pcm_current - v->pcm_returned)<<hs)
     911               0 :               extra = (v->pcm_current - v->pcm_returned)<<hs;
     912                 : 
     913                 :             /* we use ogg_int64_t for granule positions because a
     914                 :                uint64 isn't universally available.  Unfortunately,
     915                 :                that means granposes can be 'negative' and result in
     916                 :                extra being negative */
     917               0 :             if(extra<0)
     918               0 :               extra=0;
     919                 : 
     920               0 :             v->pcm_current-=extra>>hs;
     921                 :           } /* else {Shouldn't happen *unless* the bitstream is out of
     922                 :                spec.  Either way, believe the bitstream } */
     923                 :       } /* else {Shouldn't happen *unless* the bitstream is out of
     924                 :            spec.  Either way, believe the bitstream } */
     925               0 :       v->granulepos=vb->granulepos;
     926                 :     }
     927                 :   }
     928                 : 
     929                 :   /* Update, cleanup */
     930                 : 
     931               0 :   if(vb->eofflag)v->eofflag=1;
     932               0 :   return(0);
     933                 : 
     934                 : }
     935                 : 
     936                 : /* pcm==NULL indicates we just want the pending samples, no more */
     937               0 : int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm){
     938               0 :   vorbis_info *vi=v->vi;
     939                 : 
     940               0 :   if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
     941               0 :     if(pcm){
     942                 :       int i;
     943               0 :       for(i=0;i<vi->channels;i++)
     944               0 :         v->pcmret[i]=v->pcm[i]+v->pcm_returned;
     945               0 :       *pcm=v->pcmret;
     946                 :     }
     947               0 :     return(v->pcm_current-v->pcm_returned);
     948                 :   }
     949               0 :   return(0);
     950                 : }
     951                 : 
     952               0 : int vorbis_synthesis_read(vorbis_dsp_state *v,int n){
     953               0 :   if(n && v->pcm_returned+n>v->pcm_current)return(OV_EINVAL);
     954               0 :   v->pcm_returned+=n;
     955               0 :   return(0);
     956                 : }
     957                 : 
     958                 : /* intended for use with a specific vorbisfile feature; we want access
     959                 :    to the [usually synthetic/postextrapolated] buffer and lapping at
     960                 :    the end of a decode cycle, specifically, a half-short-block worth.
     961                 :    This funtion works like pcmout above, except it will also expose
     962                 :    this implicit buffer data not normally decoded. */
     963               0 : int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm){
     964               0 :   vorbis_info *vi=v->vi;
     965               0 :   codec_setup_info *ci=vi->codec_setup;
     966               0 :   int hs=ci->halfrate_flag;
     967                 : 
     968               0 :   int n=ci->blocksizes[v->W]>>(hs+1);
     969               0 :   int n0=ci->blocksizes[0]>>(hs+1);
     970               0 :   int n1=ci->blocksizes[1]>>(hs+1);
     971                 :   int i,j;
     972                 : 
     973               0 :   if(v->pcm_returned<0)return 0;
     974                 : 
     975                 :   /* our returned data ends at pcm_returned; because the synthesis pcm
     976                 :      buffer is a two-fragment ring, that means our data block may be
     977                 :      fragmented by buffering, wrapping or a short block not filling
     978                 :      out a buffer.  To simplify things, we unfragment if it's at all
     979                 :      possibly needed. Otherwise, we'd need to call lapout more than
     980                 :      once as well as hold additional dsp state.  Opt for
     981                 :      simplicity. */
     982                 : 
     983                 :   /* centerW was advanced by blockin; it would be the center of the
     984                 :      *next* block */
     985               0 :   if(v->centerW==n1){
     986                 :     /* the data buffer wraps; swap the halves */
     987                 :     /* slow, sure, small */
     988               0 :     for(j=0;j<vi->channels;j++){
     989               0 :       float *p=v->pcm[j];
     990               0 :       for(i=0;i<n1;i++){
     991               0 :         float temp=p[i];
     992               0 :         p[i]=p[i+n1];
     993               0 :         p[i+n1]=temp;
     994                 :       }
     995                 :     }
     996                 : 
     997               0 :     v->pcm_current-=n1;
     998               0 :     v->pcm_returned-=n1;
     999               0 :     v->centerW=0;
    1000                 :   }
    1001                 : 
    1002                 :   /* solidify buffer into contiguous space */
    1003               0 :   if((v->lW^v->W)==1){
    1004                 :     /* long/short or short/long */
    1005               0 :     for(j=0;j<vi->channels;j++){
    1006               0 :       float *s=v->pcm[j];
    1007               0 :       float *d=v->pcm[j]+(n1-n0)/2;
    1008               0 :       for(i=(n1+n0)/2-1;i>=0;--i)
    1009               0 :         d[i]=s[i];
    1010                 :     }
    1011               0 :     v->pcm_returned+=(n1-n0)/2;
    1012               0 :     v->pcm_current+=(n1-n0)/2;
    1013                 :   }else{
    1014               0 :     if(v->lW==0){
    1015                 :       /* short/short */
    1016               0 :       for(j=0;j<vi->channels;j++){
    1017               0 :         float *s=v->pcm[j];
    1018               0 :         float *d=v->pcm[j]+n1-n0;
    1019               0 :         for(i=n0-1;i>=0;--i)
    1020               0 :           d[i]=s[i];
    1021                 :       }
    1022               0 :       v->pcm_returned+=n1-n0;
    1023               0 :       v->pcm_current+=n1-n0;
    1024                 :     }
    1025                 :   }
    1026                 : 
    1027               0 :   if(pcm){
    1028                 :     int i;
    1029               0 :     for(i=0;i<vi->channels;i++)
    1030               0 :       v->pcmret[i]=v->pcm[i]+v->pcm_returned;
    1031               0 :     *pcm=v->pcmret;
    1032                 :   }
    1033                 : 
    1034               0 :   return(n1+n-v->pcm_returned);
    1035                 : 
    1036                 : }
    1037                 : 
    1038               0 : float *vorbis_window(vorbis_dsp_state *v,int W){
    1039               0 :   vorbis_info *vi=v->vi;
    1040               0 :   codec_setup_info *ci=vi->codec_setup;
    1041               0 :   int hs=ci->halfrate_flag;
    1042               0 :   private_state *b=v->backend_state;
    1043                 : 
    1044               0 :   if(b->window[W]-1<0)return NULL;
    1045               0 :   return _vorbis_window_get(b->window[W]-hs);
    1046                 : }

Generated by: LCOV version 1.7