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