• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
4  *                                                                  *
5  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
6  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
7  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
8  *                                                                  *
9  * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
10  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
11  *                                                                  *
12  ********************************************************************
13 
14  function: PCM data vector blocking, windowing and dis/reassembly
15 
16  ********************************************************************/
17 
18 #include <stdlib.h>
19 #include "ogg.h"
20 #include "mdct.h"
21 #include "ivorbiscodec.h"
22 #include "codec_internal.h"
23 #include "misc.h"
24 #include "window_lookup.h"
25 
vorbis_dsp_restart(vorbis_dsp_state * v)26 int vorbis_dsp_restart(vorbis_dsp_state *v){
27   if(!v)return -1;
28   {
29     vorbis_info *vi=v->vi;
30     codec_setup_info *ci;
31 
32     if(!vi)return -1;
33     ci=vi->codec_setup;
34     if(!ci)return -1;
35 
36     v->out_end=-1;
37     v->out_begin=-1;
38 
39     v->granulepos=-1;
40     v->sequence=-1;
41     v->sample_count=-1;
42   }
43   return 0;
44 }
45 
vorbis_dsp_create(vorbis_info * vi)46 vorbis_dsp_state *vorbis_dsp_create(vorbis_info *vi){
47   int i;
48 
49   vorbis_dsp_state *v=_ogg_calloc(1,sizeof(*v));
50   codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
51 
52   v->vi=vi;
53 
54   v->work=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->work));
55   v->mdctright=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->mdctright));
56   for(i=0;i<vi->channels;i++){
57     v->work[i]=(ogg_int32_t *)_ogg_calloc(1,(ci->blocksizes[1]>>1)*
58 					  sizeof(*v->work[i]));
59     v->mdctright[i]=(ogg_int32_t *)_ogg_calloc(1,(ci->blocksizes[1]>>2)*
60 					       sizeof(*v->mdctright[i]));
61   }
62 
63   v->lW=0; /* previous window size */
64   v->W=0;  /* current window size */
65 
66   vorbis_dsp_restart(v);
67   return v;
68 }
69 
vorbis_dsp_destroy(vorbis_dsp_state * v)70 void vorbis_dsp_destroy(vorbis_dsp_state *v){
71   int i;
72   if(v){
73     vorbis_info *vi=v->vi;
74 
75     if(v->work){
76       for(i=0;i<vi->channels;i++)
77         if(v->work[i])_ogg_free(v->work[i]);
78       _ogg_free(v->work);
79     }
80     if(v->mdctright){
81       for(i=0;i<vi->channels;i++)
82         if(v->mdctright[i])_ogg_free(v->mdctright[i]);
83       _ogg_free(v->mdctright);
84     }
85 
86     _ogg_free(v);
87   }
88 }
89 
_vorbis_window(int left)90 static LOOKUP_T *_vorbis_window(int left){
91   switch(left){
92   case 32:
93     return vwin64;
94   case 64:
95     return vwin128;
96   case 128:
97     return vwin256;
98   case 256:
99     return vwin512;
100   case 512:
101     return vwin1024;
102   case 1024:
103     return vwin2048;
104   case 2048:
105     return vwin4096;
106 #ifndef LIMIT_TO_64kHz
107   case 4096:
108     return vwin8192;
109 #endif
110   default:
111     return(0);
112   }
113 }
114 
115 /* pcm==0 indicates we just want the pending samples, no more */
vorbis_dsp_pcmout(vorbis_dsp_state * v,ogg_int16_t * pcm,int samples)116 int vorbis_dsp_pcmout(vorbis_dsp_state *v,ogg_int16_t *pcm,int samples){
117   vorbis_info *vi=v->vi;
118   codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
119   if(v->out_begin>-1 && v->out_begin<v->out_end){
120     int n=v->out_end-v->out_begin;
121     if(pcm){
122       int i;
123       if(n>samples)n=samples;
124       for(i=0;i<vi->channels;i++)
125 	mdct_unroll_lap(ci->blocksizes[0],ci->blocksizes[1],
126 			v->lW,v->W,v->work[i],v->mdctright[i],
127 			_vorbis_window(ci->blocksizes[0]>>1),
128 			_vorbis_window(ci->blocksizes[1]>>1),
129 			pcm+i,vi->channels,
130 			v->out_begin,v->out_begin+n);
131     }
132     return(n);
133   }
134   return(0);
135 }
136 
vorbis_dsp_read(vorbis_dsp_state * v,int s)137 int vorbis_dsp_read(vorbis_dsp_state *v,int s){
138   if(s && v->out_begin+s>v->out_end)return(OV_EINVAL);
139   v->out_begin+=s;
140   return(0);
141 }
142 
vorbis_packet_blocksize(vorbis_info * vi,ogg_packet * op)143 long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
144   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
145   oggpack_buffer       opb;
146   int                  mode;
147   int modebits=0;
148   int v=ci->modes;
149 
150   oggpack_readinit(&opb,op->packet);
151 
152   /* Check the packet type */
153   if(oggpack_read(&opb,1)!=0){
154     /* Oops.  This is not an audio data packet */
155     return(OV_ENOTAUDIO);
156   }
157 
158   while(v>1){
159     modebits++;
160     v>>=1;
161   }
162 
163   /* read our mode and pre/post windowsize */
164   mode=oggpack_read(&opb,modebits);
165   if(mode==-1)return(OV_EBADPACKET);
166   return(ci->blocksizes[ci->mode_param[mode].blockflag]);
167 }
168 
169 
ilog(ogg_uint32_t v)170 static int ilog(ogg_uint32_t v){
171   int ret=0;
172   if(v)--v;
173   while(v){
174     ret++;
175     v>>=1;
176   }
177   return(ret);
178 }
179 
vorbis_dsp_synthesis(vorbis_dsp_state * vd,ogg_packet * op,int decodep)180 int vorbis_dsp_synthesis(vorbis_dsp_state *vd,ogg_packet *op,int decodep){
181   vorbis_info          *vi=vd->vi;
182   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
183   int                   mode,i;
184 
185   oggpack_readinit(&vd->opb,op->packet);
186 
187   /* Check the packet type */
188   if(oggpack_read(&vd->opb,1)!=0){
189     /* Oops.  This is not an audio data packet */
190     return OV_ENOTAUDIO ;
191   }
192 
193   /* read our mode and pre/post windowsize */
194   mode=oggpack_read(&vd->opb,ilog(ci->modes));
195   if(mode==-1 || mode>=ci->modes) return OV_EBADPACKET;
196 
197   /* shift information we still need from last window */
198   vd->lW=vd->W;
199   vd->W=ci->mode_param[mode].blockflag;
200   for(i=0;i<vi->channels;i++)
201     mdct_shift_right(ci->blocksizes[vd->lW],vd->work[i],vd->mdctright[i]);
202 
203   if(vd->W){
204     int temp;
205     oggpack_read(&vd->opb,1);
206     temp=oggpack_read(&vd->opb,1);
207     if(temp==-1) return OV_EBADPACKET;
208   }
209 
210   /* packet decode and portions of synthesis that rely on only this block */
211   if(decodep){
212     mapping_inverse(vd,ci->map_param+ci->mode_param[mode].mapping);
213 
214     if(vd->out_begin==-1){
215       vd->out_begin=0;
216       vd->out_end=0;
217     }else{
218       vd->out_begin=0;
219       vd->out_end=ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
220     }
221   }
222 
223   /* track the frame number... This is for convenience, but also
224      making sure our last packet doesn't end with added padding.
225 
226      This is not foolproof!  It will be confused if we begin
227      decoding at the last page after a seek or hole.  In that case,
228      we don't have a starting point to judge where the last frame
229      is.  For this reason, vorbisfile will always try to make sure
230      it reads the last two marked pages in proper sequence */
231 
232   /* if we're out of sequence, dump granpos tracking until we sync back up */
233   if(vd->sequence==-1 || vd->sequence+1 != op->packetno-3){
234     /* out of sequence; lose count */
235     vd->granulepos=-1;
236     vd->sample_count=-1;
237   }
238 
239   vd->sequence=op->packetno;
240   vd->sequence=vd->sequence-3;
241 
242   if(vd->sample_count==-1){
243     vd->sample_count=0;
244   }else{
245     vd->sample_count+=
246       ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
247   }
248 
249   if(vd->granulepos==-1){
250     if(op->granulepos!=-1){ /* only set if we have a
251 			       position to set to */
252 
253       vd->granulepos=op->granulepos;
254 
255       /* is this a short page? */
256       if(vd->sample_count>vd->granulepos){
257 	/* corner case; if this is both the first and last audio page,
258 	   then spec says the end is cut, not beginning */
259 	if(op->e_o_s){
260 	  /* trim the end */
261 	  /* no preceeding granulepos; assume we started at zero (we'd
262 	     have to in a short single-page stream) */
263 	  /* granulepos could be -1 due to a seek, but that would result
264 	     in a long coun t, not short count */
265 
266 	  vd->out_end-=vd->sample_count-vd->granulepos;
267 	}else{
268 	  /* trim the beginning */
269 	  vd->out_begin+=vd->sample_count-vd->granulepos;
270 	  if(vd->out_begin>vd->out_end)
271 	    vd->out_begin=vd->out_end;
272 	}
273 
274       }
275 
276     }
277   }else{
278     vd->granulepos+=
279       ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4;
280     if(op->granulepos!=-1 && vd->granulepos!=op->granulepos){
281 
282       if(vd->granulepos>op->granulepos){
283 	long extra=vd->granulepos-op->granulepos;
284 
285 	if(extra)
286 	  if(op->e_o_s){
287 	    /* partial last frame.  Strip the extra samples off */
288 	    vd->out_end-=extra;
289 	  } /* else {Shouldn't happen *unless* the bitstream is out of
290 	       spec.  Either way, believe the bitstream } */
291       } /* else {Shouldn't happen *unless* the bitstream is out of
292 	   spec.  Either way, believe the bitstream } */
293       vd->granulepos=op->granulepos;
294     }
295   }
296 
297   return(0);
298 }
299