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