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: channel mapping 0 implementation
35 
36  ************************************************************************/
37 
38 #include <stdlib.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <math.h>
42 #include "ogg.h"
43 #include "os.h"
44 #include "ivorbiscodec.h"
45 #include "mdct.h"
46 #include "codec_internal.h"
47 #include "codebook.h"
48 #include "misc.h"
49 
mapping_clear_info(vorbis_info_mapping * info)50 void mapping_clear_info(vorbis_info_mapping *info){
51   if(info){
52     if(info->chmuxlist)_ogg_free(info->chmuxlist);
53     if(info->submaplist)_ogg_free(info->submaplist);
54     if(info->coupling)_ogg_free(info->coupling);
55     memset(info,0,sizeof(*info));
56   }
57 }
58 
ilog(unsigned int v)59 static int ilog(unsigned int v){
60   int ret=0;
61   if(v)--v;
62   while(v){
63     ret++;
64     v>>=1;
65   }
66   return(ret);
67 }
68 
69 /* also responsible for range checking */
mapping_info_unpack(vorbis_info_mapping * info,vorbis_info * vi,oggpack_buffer * opb)70 int mapping_info_unpack(vorbis_info_mapping *info,vorbis_info *vi,
71 			oggpack_buffer *opb){
72   int i;
73   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
74   memset(info,0,sizeof(*info));
75 
76   if(oggpack_read(opb,1))
77     info->submaps=oggpack_read(opb,4)+1;
78   else
79     info->submaps=1;
80 
81   if(oggpack_read(opb,1)){
82     info->coupling_steps=oggpack_read(opb,8)+1;
83     info->coupling=
84       _ogg_malloc(info->coupling_steps*sizeof(*info->coupling));
85 
86     for(i=0;i<info->coupling_steps;i++){
87       int testM=info->coupling[i].mag=(unsigned char)(oggpack_read(opb,ilog(vi->channels)));
88       int testA=info->coupling[i].ang=(unsigned char)(oggpack_read(opb,ilog(vi->channels)));
89 
90       if(testM<0 ||
91 	 testA<0 ||
92 	 testM==testA ||
93 	 testM>=vi->channels ||
94 	 testA>=vi->channels) goto err_out;
95     }
96 
97   }
98 
99   if(oggpack_read(opb,2)>0)goto err_out; /* 2,3:reserved */
100 
101   if(info->submaps>1){
102     info->chmuxlist=_ogg_malloc(sizeof(*info->chmuxlist)*vi->channels);
103     for(i=0;i<vi->channels;i++){
104       info->chmuxlist[i]=(unsigned char)(oggpack_read(opb,4));
105       if(info->chmuxlist[i]>=info->submaps)goto err_out;
106     }
107   }
108 
109   info->submaplist=_ogg_malloc(sizeof(*info->submaplist)*info->submaps);
110   for(i=0;i<info->submaps;i++){
111     int temp=oggpack_read(opb,8);
112     info->submaplist[i].floor=(char)oggpack_read(opb,8);
113     if(info->submaplist[i].floor>=ci->floors)goto err_out;
114     info->submaplist[i].residue=(char)oggpack_read(opb,8);
115     if(info->submaplist[i].residue>=ci->residues)goto err_out;
116   }
117 
118   return 0;
119 
120  err_out:
121   mapping_clear_info(info);
122   return -1;
123 }
124 
mapping_inverse(vorbis_dsp_state * vd,vorbis_info_mapping * info)125 int mapping_inverse(vorbis_dsp_state *vd,vorbis_info_mapping *info){
126   vorbis_info          *vi=vd->vi;
127   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
128 
129   int                   i,j;
130   long                  n=ci->blocksizes[vd->W];
131 
132   ogg_int32_t **pcmbundle=
133     alloca(sizeof(*pcmbundle)*vi->channels);
134   int          *zerobundle=
135     alloca(sizeof(*zerobundle)*vi->channels);
136   int          *nonzero=
137     alloca(sizeof(*nonzero)*vi->channels);
138   ogg_int32_t **floormemo=
139     alloca(sizeof(*floormemo)*vi->channels);
140 
141   /* recover the spectral envelope; store it in the PCM vector for now */
142   for(i=0;i<vi->channels;i++){
143     int submap=0;
144     int floorno;
145 
146     if(info->submaps>1)
147       submap=info->chmuxlist[i];
148     floorno=info->submaplist[submap].floor;
149 
150     if(ci->floor_type[floorno]){
151       /* floor 1 */
152       floormemo[i]=alloca(sizeof(*floormemo[i])*
153 			  floor1_memosize(ci->floor_param[floorno]));
154       floormemo[i]=floor1_inverse1(vd,ci->floor_param[floorno],floormemo[i]);
155     }else{
156       /* floor 0 */
157       floormemo[i]=alloca(sizeof(*floormemo[i])*
158 			  floor0_memosize(ci->floor_param[floorno]));
159       floormemo[i]=floor0_inverse1(vd,ci->floor_param[floorno],floormemo[i]);
160     }
161 
162     if(floormemo[i])
163       nonzero[i]=1;
164     else
165       nonzero[i]=0;
166     memset(vd->work[i],0,sizeof(*vd->work[i])*n/2);
167   }
168 
169   /* channel coupling can 'dirty' the nonzero listing */
170   for(i=0;i<info->coupling_steps;i++){
171     if(nonzero[info->coupling[i].mag] ||
172        nonzero[info->coupling[i].ang]){
173       nonzero[info->coupling[i].mag]=1;
174       nonzero[info->coupling[i].ang]=1;
175     }
176   }
177 
178   /* recover the residue into our working vectors */
179   for(i=0;i<info->submaps;i++){
180     int ch_in_bundle=0;
181     for(j=0;j<vi->channels;j++){
182       if(!info->chmuxlist || info->chmuxlist[j]==i){
183 	if(nonzero[j])
184 	  zerobundle[ch_in_bundle]=1;
185 	else
186 	  zerobundle[ch_in_bundle]=0;
187 	pcmbundle[ch_in_bundle++]=vd->work[j];
188       }
189     }
190 
191     res_inverse(vd,ci->residue_param+info->submaplist[i].residue,
192 		pcmbundle,zerobundle,ch_in_bundle);
193   }
194 
195   //for(j=0;j<vi->channels;j++)
196   //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0);
197 
198   /* channel coupling */
199   for(i=info->coupling_steps-1;i>=0;i--){
200     ogg_int32_t *pcmM=vd->work[info->coupling[i].mag];
201     ogg_int32_t *pcmA=vd->work[info->coupling[i].ang];
202 
203     for(j=0;j<n/2;j++){
204       ogg_int32_t mag=pcmM[j];
205       ogg_int32_t ang=pcmA[j];
206 
207       if(mag>0)
208 	if(ang>0){
209 	  pcmM[j]=mag;
210 	  pcmA[j]=mag-ang;
211 	}else{
212 	  pcmA[j]=mag;
213 	  pcmM[j]=mag+ang;
214 	}
215       else
216 	if(ang>0){
217 	  pcmM[j]=mag;
218 	  pcmA[j]=mag+ang;
219 	}else{
220 	  pcmA[j]=mag;
221 	  pcmM[j]=mag-ang;
222 	}
223     }
224   }
225 
226   //for(j=0;j<vi->channels;j++)
227   //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0);
228 
229   /* compute and apply spectral envelope */
230   for(i=0;i<vi->channels;i++){
231     ogg_int32_t *pcm=vd->work[i];
232     int submap=0;
233     int floorno;
234 
235     if(info->submaps>1)
236       submap=info->chmuxlist[i];
237     floorno=info->submaplist[submap].floor;
238 
239     if(ci->floor_type[floorno]){
240       /* floor 1 */
241       floor1_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm);
242     }else{
243       /* floor 0 */
244       floor0_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm);
245     }
246   }
247 
248   //for(j=0;j<vi->channels;j++)
249   //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1);
250 
251   /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
252   /* only MDCT right now.... */
253   for(i=0;i<vi->channels;i++)
254     mdct_backward(n,vd->work[i]);
255 
256   //for(j=0;j<vi->channels;j++)
257   //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0);
258 
259   /* all done! */
260   return(0);
261 }
262