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 
vorbis_dsp_restart(vorbis_dsp_state * v)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 
vorbis_dsp_init(vorbis_dsp_state * v,vorbis_info * vi)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 
vorbis_dsp_create(vorbis_info * vi)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 
vorbis_dsp_clear(vorbis_dsp_state * v)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 
vorbis_dsp_destroy(vorbis_dsp_state * v)113 void vorbis_dsp_destroy(vorbis_dsp_state *v){
114   vorbis_dsp_clear(v);
115   _ogg_free(v);
116 }
117 
_vorbis_window(int left)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 */
vorbis_dsp_pcmout(vorbis_dsp_state * v,ogg_int16_t * pcm,int samples)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 
vorbis_dsp_read(vorbis_dsp_state * v,int s)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 
vorbis_packet_blocksize(vorbis_info * vi,ogg_packet * op)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 
ilog(ogg_uint32_t v)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 
vorbis_dsp_synthesis(vorbis_dsp_state * vd,ogg_packet * op,int decodep)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