• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
4  *                                                                  *
5  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
6  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
7  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
8  *                                                                  *
9  * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
10  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
11  *                                                                  *
12  ********************************************************************
13 
14  function: channel mapping 0 implementation
15 
16  ********************************************************************/
17 
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <math.h>
22 #include "ogg.h"
23 #include "os.h"
24 #include "ivorbiscodec.h"
25 #include "mdct.h"
26 #include "codec_internal.h"
27 #include "codebook.h"
28 #include "misc.h"
29 
mapping_clear_info(vorbis_info_mapping * info)30 void mapping_clear_info(vorbis_info_mapping *info){
31   if(info){
32     if(info->chmuxlist)_ogg_free(info->chmuxlist);
33     if(info->submaplist)_ogg_free(info->submaplist);
34     if(info->coupling)_ogg_free(info->coupling);
35     memset(info,0,sizeof(*info));
36   }
37 }
38 
ilog(unsigned int v)39 static int ilog(unsigned int v){
40   int ret=0;
41   if(v)--v;
42   while(v){
43     ret++;
44     v>>=1;
45   }
46   return(ret);
47 }
48 
49 /* also responsible for range checking */
mapping_info_unpack(vorbis_info_mapping * info,vorbis_info * vi,oggpack_buffer * opb)50 int mapping_info_unpack(vorbis_info_mapping *info,vorbis_info *vi,
51 			oggpack_buffer *opb){
52   int i;
53   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
54   memset(info,0,sizeof(*info));
55 
56   if(oggpack_read(opb,1))
57     info->submaps=oggpack_read(opb,4)+1;
58   else
59     info->submaps=1;
60 
61   if(oggpack_read(opb,1)){
62     info->coupling_steps=oggpack_read(opb,8)+1;
63     info->coupling=
64       _ogg_malloc(info->coupling_steps*sizeof(*info->coupling));
65 
66     for(i=0;i<info->coupling_steps;i++){
67       int testM=info->coupling[i].mag=oggpack_read(opb,ilog(vi->channels));
68       int testA=info->coupling[i].ang=oggpack_read(opb,ilog(vi->channels));
69 
70       if(testM<0 ||
71 	 testA<0 ||
72 	 testM==testA ||
73 	 testM>=vi->channels ||
74 	 testA>=vi->channels) goto err_out;
75     }
76 
77   }
78 
79   if(oggpack_read(opb,2)>0)goto err_out; /* 2,3:reserved */
80 
81   if(info->submaps>1){
82     info->chmuxlist=_ogg_malloc(sizeof(*info->chmuxlist)*vi->channels);
83     for(i=0;i<vi->channels;i++){
84       info->chmuxlist[i]=oggpack_read(opb,4);
85       if(info->chmuxlist[i]>=info->submaps)goto err_out;
86     }
87   }
88 
89   info->submaplist=_ogg_malloc(sizeof(*info->submaplist)*info->submaps);
90   for(i=0;i<info->submaps;i++){
91     int temp=oggpack_read(opb,8);
92     info->submaplist[i].floor=oggpack_read(opb,8);
93     if(info->submaplist[i].floor>=ci->floors)goto err_out;
94     info->submaplist[i].residue=oggpack_read(opb,8);
95     if(info->submaplist[i].residue>=ci->residues)goto err_out;
96   }
97 
98   return 0;
99 
100  err_out:
101   mapping_clear_info(info);
102   return -1;
103 }
104 
mapping_inverse(vorbis_dsp_state * vd,vorbis_info_mapping * info)105 int mapping_inverse(vorbis_dsp_state *vd,vorbis_info_mapping *info){
106   vorbis_info          *vi=vd->vi;
107   codec_setup_info     *ci=(codec_setup_info *)vi->codec_setup;
108 
109   int                   i,j;
110   long                  n=ci->blocksizes[vd->W];
111 
112   ogg_int32_t **pcmbundle=
113     alloca(sizeof(*pcmbundle)*vi->channels);
114   int          *zerobundle=
115     alloca(sizeof(*zerobundle)*vi->channels);
116   int          *nonzero=
117     alloca(sizeof(*nonzero)*vi->channels);
118   ogg_int32_t **floormemo=
119     alloca(sizeof(*floormemo)*vi->channels);
120 
121   /* recover the spectral envelope; store it in the PCM vector for now */
122   for(i=0;i<vi->channels;i++){
123     int submap=0;
124     int floorno;
125 
126     if(info->submaps>1)
127       submap=info->chmuxlist[i];
128     floorno=info->submaplist[submap].floor;
129 
130     if(ci->floor_type[floorno]){
131       /* floor 1 */
132       floormemo[i]=alloca(sizeof(*floormemo[i])*
133 			  floor1_memosize(ci->floor_param[floorno]));
134       floormemo[i]=floor1_inverse1(vd,ci->floor_param[floorno],floormemo[i]);
135     }else{
136       /* floor 0 */
137       floormemo[i]=alloca(sizeof(*floormemo[i])*
138 			  floor0_memosize(ci->floor_param[floorno]));
139       floormemo[i]=floor0_inverse1(vd,ci->floor_param[floorno],floormemo[i]);
140     }
141 
142     if(floormemo[i])
143       nonzero[i]=1;
144     else
145       nonzero[i]=0;
146     memset(vd->work[i],0,sizeof(*vd->work[i])*n/2);
147   }
148 
149   /* channel coupling can 'dirty' the nonzero listing */
150   for(i=0;i<info->coupling_steps;i++){
151     if(nonzero[info->coupling[i].mag] ||
152        nonzero[info->coupling[i].ang]){
153       nonzero[info->coupling[i].mag]=1;
154       nonzero[info->coupling[i].ang]=1;
155     }
156   }
157 
158   /* recover the residue into our working vectors */
159   for(i=0;i<info->submaps;i++){
160     int ch_in_bundle=0;
161     for(j=0;j<vi->channels;j++){
162       if(!info->chmuxlist || info->chmuxlist[j]==i){
163 	if(nonzero[j])
164 	  zerobundle[ch_in_bundle]=1;
165 	else
166 	  zerobundle[ch_in_bundle]=0;
167 	pcmbundle[ch_in_bundle++]=vd->work[j];
168       }
169     }
170 
171     res_inverse(vd,ci->residue_param+info->submaplist[i].residue,
172 		pcmbundle,zerobundle,ch_in_bundle);
173   }
174 
175   //for(j=0;j<vi->channels;j++)
176   //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0);
177 
178   /* channel coupling */
179   for(i=info->coupling_steps-1;i>=0;i--){
180     ogg_int32_t *pcmM=vd->work[info->coupling[i].mag];
181     ogg_int32_t *pcmA=vd->work[info->coupling[i].ang];
182 
183     for(j=0;j<n/2;j++){
184       ogg_int32_t mag=pcmM[j];
185       ogg_int32_t ang=pcmA[j];
186 
187       if(mag>0)
188 	if(ang>0){
189 	  pcmM[j]=mag;
190 	  pcmA[j]=mag-ang;
191 	}else{
192 	  pcmA[j]=mag;
193 	  pcmM[j]=mag+ang;
194 	}
195       else
196 	if(ang>0){
197 	  pcmM[j]=mag;
198 	  pcmA[j]=mag+ang;
199 	}else{
200 	  pcmA[j]=mag;
201 	  pcmM[j]=mag-ang;
202 	}
203     }
204   }
205 
206   //for(j=0;j<vi->channels;j++)
207   //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0);
208 
209   /* compute and apply spectral envelope */
210   for(i=0;i<vi->channels;i++){
211     ogg_int32_t *pcm=vd->work[i];
212     int submap=0;
213     int floorno;
214 
215     if(info->submaps>1)
216       submap=info->chmuxlist[i];
217     floorno=info->submaplist[submap].floor;
218 
219     if(ci->floor_type[floorno]){
220       /* floor 1 */
221       floor1_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm);
222     }else{
223       /* floor 0 */
224       floor0_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm);
225     }
226   }
227 
228   //for(j=0;j<vi->channels;j++)
229   //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1);
230 
231   /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
232   /* only MDCT right now.... */
233   for(i=0;i<vi->channels;i++)
234     mdct_backward(n,vd->work[i]);
235 
236   //for(j=0;j<vi->channels;j++)
237   //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0);
238 
239   /* all done! */
240   return(0);
241 }
242