1 /********************************************************************
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
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. *
9 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
10 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
12 ********************************************************************
14 function: channel mapping 0 implementation
16 ********************************************************************/
18 #include "config-tremor.h"
23 #include "ivorbiscodec.h"
25 #include "codec_internal.h"
33 /* simplistic, wasteful way of doing this (unique lookup for each
34 mode/submapping); there should be a central repository for
35 identical lookups. That will require minor work, so I'm putting it
38 Why a lookup for each backend in a given mode? Because the
39 blocksize is set by the mode, and low backend lookups may require
40 parameters from other areas of the mode/mapping */
43 vorbis_info_mode
*mode
;
44 vorbis_info_mapping0
*map
;
46 vorbis_look_floor
**floor_look
;
48 vorbis_look_residue
**residue_look
;
50 vorbis_func_floor
**floor_func
;
51 vorbis_func_residue
**residue_func
;
54 long lastframe
; /* if a different mode is called, we need to
56 } vorbis_look_mapping0
;
58 static void mapping0_free_info(vorbis_info_mapping
*i
){
59 vorbis_info_mapping0
*info
=(vorbis_info_mapping0
*)i
;
61 memset(info
,0,sizeof(*info
));
66 static void mapping0_free_look(vorbis_look_mapping
*look
){
68 vorbis_look_mapping0
*l
=(vorbis_look_mapping0
*)look
;
71 for(i
=0;i
<l
->map
->submaps
;i
++){
72 l
->floor_func
[i
]->free_look(l
->floor_look
[i
]);
73 l
->residue_func
[i
]->free_look(l
->residue_look
[i
]);
76 _ogg_free(l
->floor_func
);
77 _ogg_free(l
->residue_func
);
78 _ogg_free(l
->floor_look
);
79 _ogg_free(l
->residue_look
);
80 memset(l
,0,sizeof(*l
));
85 static vorbis_look_mapping
*mapping0_look(vorbis_dsp_state
*vd
,vorbis_info_mode
*vm
,
86 vorbis_info_mapping
*m
){
88 vorbis_info
*vi
=vd
->vi
;
89 codec_setup_info
*ci
=(codec_setup_info
*)vi
->codec_setup
;
90 vorbis_look_mapping0
*look
=(vorbis_look_mapping0
*)_ogg_calloc(1,sizeof(*look
));
91 vorbis_info_mapping0
*info
=look
->map
=(vorbis_info_mapping0
*)m
;
94 look
->floor_look
=(vorbis_look_floor
**)_ogg_calloc(info
->submaps
,sizeof(*look
->floor_look
));
96 look
->residue_look
=(vorbis_look_residue
**)_ogg_calloc(info
->submaps
,sizeof(*look
->residue_look
));
98 look
->floor_func
=(vorbis_func_floor
**)_ogg_calloc(info
->submaps
,sizeof(*look
->floor_func
));
99 look
->residue_func
=(vorbis_func_residue
**)_ogg_calloc(info
->submaps
,sizeof(*look
->residue_func
));
101 for(i
=0;i
<info
->submaps
;i
++){
102 int floornum
=info
->floorsubmap
[i
];
103 int resnum
=info
->residuesubmap
[i
];
105 look
->floor_func
[i
]=_floor_P
[ci
->floor_type
[floornum
]];
106 look
->floor_look
[i
]=look
->floor_func
[i
]->
107 look(vd
,vm
,ci
->floor_param
[floornum
]);
108 look
->residue_func
[i
]=_residue_P
[ci
->residue_type
[resnum
]];
109 look
->residue_look
[i
]=look
->residue_func
[i
]->
110 look(vd
,vm
,ci
->residue_param
[resnum
]);
114 look
->ch
=vi
->channels
;
119 static int ilog(unsigned int v
){
130 /* also responsible for range checking */
131 static vorbis_info_mapping
*mapping0_unpack(vorbis_info
*vi
,oggpack_buffer
*opb
){
133 vorbis_info_mapping0
*info
=(vorbis_info_mapping0
*)_ogg_calloc(1,sizeof(*info
));
134 codec_setup_info
*ci
=(codec_setup_info
*)vi
->codec_setup
;
135 memset(info
,0,sizeof(*info
));
137 if(oggpack_read(opb
,1))
138 info
->submaps
=oggpack_read(opb
,4)+1;
142 if(oggpack_read(opb
,1)){
143 info
->coupling_steps
=oggpack_read(opb
,8)+1;
145 for(i
=0;i
<info
->coupling_steps
;i
++){
146 int testM
=info
->coupling_mag
[i
]=oggpack_read(opb
,ilog(vi
->channels
));
147 int testA
=info
->coupling_ang
[i
]=oggpack_read(opb
,ilog(vi
->channels
));
152 testM
>=vi
->channels
||
153 testA
>=vi
->channels
) goto err_out
;
158 if(oggpack_read(opb
,2)>0)goto err_out
; /* 2,3:reserved */
161 for(i
=0;i
<vi
->channels
;i
++){
162 info
->chmuxlist
[i
]=oggpack_read(opb
,4);
163 if(info
->chmuxlist
[i
]>=info
->submaps
)goto err_out
;
166 for(i
=0;i
<info
->submaps
;i
++){
167 int temp
=oggpack_read(opb
,8);
168 if(temp
>=ci
->times
)goto err_out
;
169 info
->floorsubmap
[i
]=oggpack_read(opb
,8);
170 if(info
->floorsubmap
[i
]>=ci
->floors
)goto err_out
;
171 info
->residuesubmap
[i
]=oggpack_read(opb
,8);
172 if(info
->residuesubmap
[i
]>=ci
->residues
)goto err_out
;
178 mapping0_free_info(info
);
185 static int mapping0_inverse(vorbis_block
*vb
,vorbis_look_mapping
*l
){
186 vorbis_dsp_state
*vd
=vb
->vd
;
187 vorbis_info
*vi
=vd
->vi
;
188 codec_setup_info
*ci
=(codec_setup_info
*)vi
->codec_setup
;
189 private_state
*b
=(private_state
*)vd
->backend_state
;
190 vorbis_look_mapping0
*look
=(vorbis_look_mapping0
*)l
;
191 vorbis_info_mapping0
*info
=look
->map
;
194 long n
=vb
->pcmend
=ci
->blocksizes
[vb
->W
];
196 /* bounded mapping arrays instead of using alloca();
197 avoids memory leak; we can only deal with stereo anyway */
198 ogg_int32_t
*pcmbundle
[CHANNELS
];
199 int zerobundle
[CHANNELS
];
200 int nonzero
[CHANNELS
];
201 void *floormemo
[CHANNELS
];
203 /* time domain information decode (note that applying the
204 information would have to happen later; we'll probably add a
205 function entry to the harness for that later */
206 /* NOT IMPLEMENTED */
208 /* recover the spectral envelope; store it in the PCM vector for now */
209 for(i
=0;i
<vi
->channels
;i
++){
210 int submap
=info
->chmuxlist
[i
];
211 floormemo
[i
]=look
->floor_func
[submap
]->
212 inverse1(vb
,look
->floor_look
[submap
]);
217 memset(vb
->pcm
[i
],0,sizeof(*vb
->pcm
[i
])*n
/2);
220 /* channel coupling can 'dirty' the nonzero listing */
221 for(i
=0;i
<info
->coupling_steps
;i
++){
222 if(nonzero
[info
->coupling_mag
[i
]] ||
223 nonzero
[info
->coupling_ang
[i
]]){
224 nonzero
[info
->coupling_mag
[i
]]=1;
225 nonzero
[info
->coupling_ang
[i
]]=1;
229 /* recover the residue into our working vectors */
230 for(i
=0;i
<info
->submaps
;i
++){
232 for(j
=0;j
<vi
->channels
;j
++){
233 if(info
->chmuxlist
[j
]==i
){
235 zerobundle
[ch_in_bundle
]=1;
237 zerobundle
[ch_in_bundle
]=0;
238 pcmbundle
[ch_in_bundle
++]=vb
->pcm
[j
];
242 look
->residue_func
[i
]->inverse(vb
,look
->residue_look
[i
],
243 pcmbundle
,zerobundle
,ch_in_bundle
);
246 //for(j=0;j<vi->channels;j++)
247 //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0);
250 /* channel coupling */
251 for(i
=info
->coupling_steps
-1;i
>=0;i
--){
252 ogg_int32_t
*pcmM
=vb
->pcm
[info
->coupling_mag
[i
]];
253 ogg_int32_t
*pcmA
=vb
->pcm
[info
->coupling_ang
[i
]];
256 ogg_int32_t mag
=pcmM
[j
];
257 ogg_int32_t ang
=pcmA
[j
];
279 //for(j=0;j<vi->channels;j++)
280 //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0);
282 /* compute and apply spectral envelope */
284 for(i
=0;i
<vi
->channels
;i
++){
285 ogg_int32_t
*pcm
=vb
->pcm
[i
];
286 int submap
=info
->chmuxlist
[i
];
287 look
->floor_func
[submap
]->
288 inverse2(vb
,look
->floor_look
[submap
],floormemo
[i
],pcm
);
291 //for(j=0;j<vi->channels;j++)
292 //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1);
294 /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
295 /* only MDCT right now.... */
297 for(i
=0;i
<vi
->channels
;i
++){
298 ogg_int32_t
*pcm
=vb
->pcm
[i
];
299 int submap
=info
->chmuxlist
[i
];
302 look
->floor_func
[submap
]->
303 inverse2(vb
,look
->floor_look
[submap
],floormemo
[i
],pcm
);
304 mdct_backward(n
, (int32_t*) pcm
, (int32_t*) pcm
);
305 /* window the data */
306 _vorbis_apply_window(pcm
,b
->window
,ci
->blocksizes
,vb
->lW
,vb
->W
,vb
->nW
);
309 memset(pcm
, 0, sizeof(ogg_int32_t
)*n
);
312 //for(j=0;j<vi->channels;j++)
313 //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0);
315 //for(j=0;j<vi->channels;j++)
316 //_analysis_output("window",seq+j,vb->pcm[j],-24,n,0,0);
324 const vorbis_func_mapping mapping0_exportbundle ICONST_ATTR
={