Home | History | Annotate | Download | only in Tremolo
      1 /************************************************************************
      2  * Copyright (C) 2002-2009, Xiph.org Foundation
      3  * Copyright (C) 2010, Robin Watts for Pinknoise Productions Ltd
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  *
     10  *     * Redistributions of source code must retain the above copyright
     11  * notice, this list of conditions and the following disclaimer.
     12  *     * Redistributions in binary form must reproduce the above
     13  * copyright notice, this list of conditions and the following disclaimer
     14  * in the documentation and/or other materials provided with the
     15  * distribution.
     16  *     * Neither the names of the Xiph.org Foundation nor Pinknoise
     17  * Productions Ltd nor the names of its contributors may be used to
     18  * endorse or promote products derived from this software without
     19  * specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  ************************************************************************
     33 
     34  function: PCM data vector blocking, windowing and dis/reassembly
     35 
     36  ************************************************************************/
     37 
     38 #include <stdlib.h>
     39 #include "ogg.h"
     40 #include "mdct.h"
     41 #include "ivorbiscodec.h"
     42 #include "codec_internal.h"
     43 #include "misc.h"
     44 #include "window_lookup.h"
     45 
     46 int vorbis_dsp_restart(vorbis_dsp_state *v){
     47   if(!v)return -1;
     48   {
     49     vorbis_info *vi=v->vi;
     50     codec_setup_info *ci;
     51 
     52     if(!vi)return -1;
     53     ci=vi->codec_setup;
     54     if(!ci)return -1;
     55 
     56     v->out_end=-1;
     57     v->out_begin=-1;
     58 
     59     v->granulepos=-1;
     60     v->sequence=-1;
     61     v->sample_count=-1;
     62   }
     63   return 0;
     64 }
     65 
     66 int vorbis_dsp_init(vorbis_dsp_state *v,vorbis_info *vi){
     67   int i;
     68 
     69   codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
     70 
     71   v->vi=vi;
     72 
     73   v->work=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->work));
     74   v->mdctright=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->mdctright));
     75   for(i=0;i<vi->channels;i++){
     76     v->work[i]=(ogg_int32_t *)_ogg_calloc(1,(ci->blocksizes[1]>>1)*
     77 					  sizeof(*v->work[i]));
     78     v->mdctright[i]=(ogg_int32_t *)_ogg_calloc(1,(ci->blocksizes[1]>>2)*
     79 					       sizeof(*v->mdctright[i]));
     80   }
     81 
     82   v->lW=0; /* previous window size */
     83   v->W=0;  /* current window size */
     84 
     85   vorbis_dsp_restart(v);
     86   return 0;
     87 }
     88 
     89 vorbis_dsp_state *vorbis_dsp_create(vorbis_info *vi){
     90   vorbis_dsp_state *v=_ogg_calloc(1,sizeof(*v));
     91   vorbis_dsp_init(v,vi);
     92   return v;
     93 }
     94 
     95 void vorbis_dsp_clear(vorbis_dsp_state *v){
     96   int i;
     97   if(v){
     98     vorbis_info *vi=v->vi;
     99 
    100     if(v->work){
    101       for(i=0;i<vi->channels;i++)
    102         if(v->work[i])_ogg_free(v->work[i]);
    103       _ogg_free(v->work);
    104     }
    105     if(v->mdctright){
    106       for(i=0;i<vi->channels;i++)
    107         if(v->mdctright[i])_ogg_free(v->mdctright[i]);
    108       _ogg_free(v->mdctright);
    109     }
    110   }
    111 }
    112 
    113 void vorbis_dsp_destroy(vorbis_dsp_state *v){
    114   vorbis_dsp_clear(v);
    115   _ogg_free(v);
    116 }
    117 
    118 static LOOKUP_T *_vorbis_window(int left){
    119   switch(left){
    120   case 32:
    121     return vwin64;
    122   case 64:
    123     return vwin128;
    124   case 128:
    125     return vwin256;
    126   case 256:
    127     return vwin512;
    128   case 512:
    129     return vwin1024;
    130   case 1024:
    131     return vwin2048;
    132   case 2048:
    133     return vwin4096;
    134 #ifndef LIMIT_TO_64kHz
    135   case 4096:
    136     return vwin8192;
    137 #endif
    138   default:
    139     return(0);
    140   }
    141 }
    142 
    143 /* pcm==0 indicates we just want the pending samples, no more */
    144 int vorbis_dsp_pcmout(vorbis_dsp_state *v,ogg_int16_t *pcm,int samples){
    145   vorbis_info *vi=v->vi;
    146   codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
    147   if(v->out_begin>-1 && v->out_begin<v->out_end){
    148     int n=v->out_end-v->out_begin;
    149     if(pcm){
    150       int i;
    151       if(n>samples)n=samples;
    152       for(i=0;i<vi->channels;i++)
    153 	mdct_unroll_lap(ci->blocksizes[0],ci->blocksizes[1],
    154 			v->lW,v->W,v->work[i],v->mdctright[i],
    155 			_vorbis_window(ci->blocksizes[0]>>1),
    156 			_vorbis_window(ci->blocksizes[1]>>1),
    157 			pcm+i,vi->channels,
    158 			v->out_begin,v->out_begin+n);
    159     }
    160     return(n);
    161   }
    162   return(0);
    163 }
    164 
    165 int vorbis_dsp_read(vorbis_dsp_state *v,int s){
    166   if(s && v->out_begin+s>v->out_end)return(OV_EINVAL);
    167   v->out_begin+=s;
    168   return(0);
    169 }
    170 
    171 long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
    172   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
    173   oggpack_buffer       opb;
    174   int                  mode;
    175   int modebits=0;
    176   int v=ci->modes;
    177 
    178   oggpack_readinit(&opb,op->packet);
    179 
    180   /* Check the packet type */
    181   if(oggpack_read(&opb,1)!=0){
    182     /* Oops.  This is not an audio data packet */
    183     return(OV_ENOTAUDIO);
    184   }
    185 
    186   while(v>1){
    187     modebits++;
    188     v>>=1;
    189   }
    190 
    191   /* read our mode and pre/post windowsize */
    192   mode=oggpack_read(&opb,modebits);
    193   if(mode==-1)return(OV_EBADPACKET);
    194   return(ci->blocksizes[ci->mode_param[mode].blockflag]);
    195 }
    196 
    197 
    198 static int ilog(ogg_uint32_t v){
    199   int ret=0;
    200   if(v)--v;
    201   while(v){
    202     ret++;
    203     v>>=1;
    204   }
    205   return(ret);
    206 }
    207 
    208 int vorbis_dsp_synthesis(vorbis_dsp_state *vd,ogg_packet *op,int decodep){
    209   vorbis_info          *vi=vd->vi;
    210   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
    211   int                   mode,i;
    212 
    213   oggpack_readinit(&vd->opb,op->packet);
    214 
    215   /* Check the packet type */
    216   if(oggpack_read(&vd->opb,1)!=0){
    217     /* Oops.  This is not an audio data packet */
    218     return OV_ENOTAUDIO ;
    219   }
    220 
    221   /* read our mode and pre/post windowsize */
    222   mode=oggpack_read(&vd->opb,ilog(ci->modes));
    223   if(mode==-1 || mode>=ci->modes) return OV_EBADPACKET;
    224 
    225   /* shift information we still need from last window */
    226   vd->lW=vd->W;
    227   vd->W=ci->mode_param[mode].blockflag;
    228   for(i=0;i<vi->channels;i++)
    229     mdct_shift_right(ci->blocksizes[vd->lW],vd->work[i],vd->mdctright[i]);
    230 
    231   if(vd->W){
    232     int temp;
    233     oggpack_read(&vd->opb,1);
    234     temp=oggpack_read(&vd->opb,1);
    235     if(temp==-1) return OV_EBADPACKET;
    236   }
    237 
    238   /* packet decode and portions of synthesis that rely on only this block */
    239   if(decodep){
    240     mapping_inverse(vd,ci->map_param+ci->mode_param[mode].mapping);
    241 
    242     if(vd->out_begin==-1){
    243       vd->out_begin=0;
    244       vd->out_end=0;
    245     }else{
    246       vd->out_begin=0;
    247       vd->out_end=ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
    248     }
    249   }
    250 
    251   /* track the frame number... This is for convenience, but also
    252      making sure our last packet doesn't end with added padding.
    253 
    254      This is not foolproof!  It will be confused if we begin
    255      decoding at the last page after a seek or hole.  In that case,
    256      we don't have a starting point to judge where the last frame
    257      is.  For this reason, vorbisfile will always try to make sure
    258      it reads the last two marked pages in proper sequence */
    259 
    260   /* if we're out of sequence, dump granpos tracking until we sync back up */
    261   if(vd->sequence==-1 || vd->sequence+1 != op->packetno-3){
    262     /* out of sequence; lose count */
    263     vd->granulepos=-1;
    264     vd->sample_count=-1;
    265   }
    266 
    267   vd->sequence=op->packetno;
    268   vd->sequence=vd->sequence-3;
    269 
    270   if(vd->sample_count==-1){
    271     vd->sample_count=0;
    272   }else{
    273     vd->sample_count+=
    274       ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
    275   }
    276 
    277   if(vd->granulepos==-1){
    278     if(op->granulepos!=-1){ /* only set if we have a
    279 			       position to set to */
    280 
    281       vd->granulepos=op->granulepos;
    282 
    283       /* is this a short page? */
    284       if(vd->sample_count>vd->granulepos){
    285 	/* corner case; if this is both the first and last audio page,
    286 	   then spec says the end is cut, not beginning */
    287 	if(op->e_o_s){
    288 	  /* trim the end */
    289 	  /* no preceeding granulepos; assume we started at zero (we'd
    290 	     have to in a short single-page stream) */
    291 	  /* granulepos could be -1 due to a seek, but that would result
    292 	     in a long coun t, not short count */
    293 
    294 	  vd->out_end-=(int)(vd->sample_count-vd->granulepos);
    295 	}else{
    296 	  /* trim the beginning */
    297 	  vd->out_begin+=(int)(vd->sample_count-vd->granulepos);
    298 	  if(vd->out_begin>vd->out_end)
    299 	    vd->out_begin=vd->out_end;
    300 	}
    301 
    302       }
    303 
    304     }
    305   }else{
    306     vd->granulepos+=
    307       ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
    308     if(op->granulepos!=-1 && vd->granulepos!=op->granulepos){
    309 
    310       if(vd->granulepos>op->granulepos){
    311 	long extra=(long)(vd->granulepos-op->granulepos);
    312 
    313 	if(extra)
    314 	  if(op->e_o_s){
    315 	    /* partial last frame.  Strip the extra samples off */
    316 	    vd->out_end-=extra;
    317 	  } /* else {Shouldn't happen *unless* the bitstream is out of
    318 	       spec.  Either way, believe the bitstream } */
    319       } /* else {Shouldn't happen *unless* the bitstream is out of
    320 	   spec.  Either way, believe the bitstream } */
    321       vd->granulepos=op->granulepos;
    322     }
    323   }
    324 
    325   return(0);
    326 }
    327