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
46int 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
66int 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
89vorbis_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
95void 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
113void vorbis_dsp_destroy(vorbis_dsp_state *v){
114  vorbis_dsp_clear(v);
115  _ogg_free(v);
116}
117
118static 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 */
144int 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
165int 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
171long 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
198static 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
208int 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