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"
30 #include <codecs/lib/codeclib.h>
32 /* simplistic, wasteful way of doing this (unique lookup for each
33 mode/submapping); there should be a central repository for
34 identical lookups. That will require minor work, so I'm putting it
37 Why a lookup for each backend in a given mode? Because the
38 blocksize is set by the mode, and low backend lookups may require
39 parameters from other areas of the mode/mapping */
42 vorbis_info_mode
*mode
;
43 vorbis_info_mapping0
*map
;
45 vorbis_look_floor
**floor_look
;
47 vorbis_look_residue
**residue_look
;
49 vorbis_func_floor
**floor_func
;
50 vorbis_func_residue
**residue_func
;
53 long lastframe
; /* if a different mode is called, we need to
55 } vorbis_look_mapping0
;
57 static void mapping0_free_info(vorbis_info_mapping
*i
){
58 vorbis_info_mapping0
*info
=(vorbis_info_mapping0
*)i
;
60 memset(info
,0,sizeof(*info
));
65 static void mapping0_free_look(vorbis_look_mapping
*look
){
67 vorbis_look_mapping0
*l
=(vorbis_look_mapping0
*)look
;
70 for(i
=0;i
<l
->map
->submaps
;i
++){
71 l
->floor_func
[i
]->free_look(l
->floor_look
[i
]);
72 l
->residue_func
[i
]->free_look(l
->residue_look
[i
]);
75 _ogg_free(l
->floor_func
);
76 _ogg_free(l
->residue_func
);
77 _ogg_free(l
->floor_look
);
78 _ogg_free(l
->residue_look
);
79 memset(l
,0,sizeof(*l
));
84 static vorbis_look_mapping
*mapping0_look(vorbis_dsp_state
*vd
,vorbis_info_mode
*vm
,
85 vorbis_info_mapping
*m
){
87 vorbis_info
*vi
=vd
->vi
;
88 codec_setup_info
*ci
=(codec_setup_info
*)vi
->codec_setup
;
89 vorbis_look_mapping0
*look
=(vorbis_look_mapping0
*)_ogg_calloc(1,sizeof(*look
));
90 vorbis_info_mapping0
*info
=look
->map
=(vorbis_info_mapping0
*)m
;
93 look
->floor_look
=(vorbis_look_floor
**)_ogg_calloc(info
->submaps
,sizeof(*look
->floor_look
));
95 look
->residue_look
=(vorbis_look_residue
**)_ogg_calloc(info
->submaps
,sizeof(*look
->residue_look
));
97 look
->floor_func
=(vorbis_func_floor
**)_ogg_calloc(info
->submaps
,sizeof(*look
->floor_func
));
98 look
->residue_func
=(vorbis_func_residue
**)_ogg_calloc(info
->submaps
,sizeof(*look
->residue_func
));
100 for(i
=0;i
<info
->submaps
;i
++){
101 int floornum
=info
->floorsubmap
[i
];
102 int resnum
=info
->residuesubmap
[i
];
104 look
->floor_func
[i
]=_floor_P
[ci
->floor_type
[floornum
]];
105 look
->floor_look
[i
]=look
->floor_func
[i
]->
106 look(vd
,vm
,ci
->floor_param
[floornum
]);
107 look
->residue_func
[i
]=_residue_P
[ci
->residue_type
[resnum
]];
108 look
->residue_look
[i
]=look
->residue_func
[i
]->
109 look(vd
,vm
,ci
->residue_param
[resnum
]);
113 look
->ch
=vi
->channels
;
118 static int ilog(unsigned int v
){
129 /* also responsible for range checking */
130 static vorbis_info_mapping
*mapping0_unpack(vorbis_info
*vi
,oggpack_buffer
*opb
){
132 vorbis_info_mapping0
*info
=(vorbis_info_mapping0
*)_ogg_calloc(1,sizeof(*info
));
133 codec_setup_info
*ci
=(codec_setup_info
*)vi
->codec_setup
;
134 memset(info
,0,sizeof(*info
));
136 if(oggpack_read(opb
,1))
137 info
->submaps
=oggpack_read(opb
,4)+1;
141 if(oggpack_read(opb
,1)){
142 info
->coupling_steps
=oggpack_read(opb
,8)+1;
144 for(i
=0;i
<info
->coupling_steps
;i
++){
145 int testM
=info
->coupling_mag
[i
]=oggpack_read(opb
,ilog(vi
->channels
));
146 int testA
=info
->coupling_ang
[i
]=oggpack_read(opb
,ilog(vi
->channels
));
151 testM
>=vi
->channels
||
152 testA
>=vi
->channels
) goto err_out
;
157 if(oggpack_read(opb
,2)>0)goto err_out
; /* 2,3:reserved */
160 for(i
=0;i
<vi
->channels
;i
++){
161 info
->chmuxlist
[i
]=oggpack_read(opb
,4);
162 if(info
->chmuxlist
[i
]>=info
->submaps
)goto err_out
;
165 for(i
=0;i
<info
->submaps
;i
++){
166 int temp
=oggpack_read(opb
,8);
167 if(temp
>=ci
->times
)goto err_out
;
168 info
->floorsubmap
[i
]=oggpack_read(opb
,8);
169 if(info
->floorsubmap
[i
]>=ci
->floors
)goto err_out
;
170 info
->residuesubmap
[i
]=oggpack_read(opb
,8);
171 if(info
->residuesubmap
[i
]>=ci
->residues
)goto err_out
;
177 mapping0_free_info(info
);
182 #define MAGANG( _mag, _ang )\
185 asm( "cmp %[mag], #0\n\t"\
186 "cmpgt %[ang], #0\n\t"\
187 "subgt %[temp], %[mag], %[ang]\n\t"\
189 "cmp %[mag], #0\n\t"\
190 "cmple %[ang], #0\n\t"\
191 "addgt %[temp], %[mag], %[ang]\n\t"\
192 "suble %[temp], %[mag], %[ang]\n\t"\
193 "1: cmp %[ang], #0\n\t"\
194 "movle %[ang], %[mag]\n\t"\
195 "movle %[mag], %[temp]\n\t"\
196 "movgt %[ang], %[temp]\n\t"\
197 : [mag] "+r" ( ( _mag ) ), [ang] "+r" ( ( _ang ) ), [temp] "=&r" (temp)\
202 static inline void channel_couple(ogg_int32_t
*pcmM
, ogg_int32_t
*pcmA
, int n
)
204 ogg_int32_t
* const pcmMend
= pcmM
+ n
/2;
205 while(LIKELY(pcmM
< pcmMend
))
207 register int M0
asm("r2"),M1
asm("r3"),M2
asm("r4"),M3
asm("r5");
208 register int A0
asm("r6"),A1
asm("r7"),A2
asm("r8"),A3
asm("r9");
209 asm volatile( "ldmia %[pcmM], {%[M0], %[M1], %[M2], %[M3]}\n\t"
210 "ldmia %[pcmA], {%[A0], %[A1], %[A2], %[A3]}\n\t"
211 : [M0
] "=r" (M0
), [M1
] "=r" (M1
), [M2
] "=r" (M2
), [M3
] "=r" (M3
),
212 [A0
] "=r" (A0
), [A1
] "=r" (A1
), [A2
] "=r" (A2
), [A3
] "=r" (A3
)
213 : [pcmM
] "r" (pcmM
), [pcmA
] "r" (pcmA
) );
218 asm volatile( "stmia %[pcmM]!, {%[M0], %[M1], %[M2], %[M3]}\n\t"
219 "stmia %[pcmA]!, {%[A0], %[A1], %[A2], %[A3]}\n\t"
220 : [pcmM
] "+r" (pcmM
), [pcmA
] "+r" (pcmA
)
221 : [M0
] "r" (M0
), [M1
] "r" (M1
), [M2
] "r" (M2
), [M3
] "r" (M3
),
222 [A0
] "r" (A0
), [A1
] "r" (A1
), [A2
] "r" (A2
), [A3
] "r" (A3
) );
226 static inline void channel_couple(ogg_int32_t
*pcmM
, ogg_int32_t
*pcmA
, int n
)
230 ogg_int32_t mag
= pcmM
[j
], ang
= pcmA
[j
];
249 static int mapping0_inverse(vorbis_block
*vb
,vorbis_look_mapping
*l
){
250 vorbis_dsp_state
*vd
=vb
->vd
;
251 vorbis_info
*vi
=vd
->vi
;
252 codec_setup_info
*ci
=(codec_setup_info
*)vi
->codec_setup
;
253 private_state
*b
=(private_state
*)vd
->backend_state
;
254 vorbis_look_mapping0
*look
=(vorbis_look_mapping0
*)l
;
255 vorbis_info_mapping0
*info
=look
->map
;
258 long n
=vb
->pcmend
=ci
->blocksizes
[vb
->W
];
260 /* bounded mapping arrays instead of using alloca();
261 avoids memory leak; we can only deal with stereo anyway */
262 ogg_int32_t
*pcmbundle
[CHANNELS
];
263 int zerobundle
[CHANNELS
];
264 int nonzero
[CHANNELS
];
265 void *floormemo
[CHANNELS
];
267 /* time domain information decode (note that applying the
268 information would have to happen later; we'll probably add a
269 function entry to the harness for that later */
270 /* NOT IMPLEMENTED */
272 /* recover the spectral envelope; store it in the PCM vector for now */
273 for(i
=0;i
<vi
->channels
;i
++){
274 int submap
=info
->chmuxlist
[i
];
275 floormemo
[i
]=look
->floor_func
[submap
]->
276 inverse1(vb
,look
->floor_look
[submap
]);
281 memset(vb
->pcm
[i
],0,sizeof(*vb
->pcm
[i
])*n
/2);
284 /* channel coupling can 'dirty' the nonzero listing */
285 for(i
=0;i
<info
->coupling_steps
;i
++){
286 if(nonzero
[info
->coupling_mag
[i
]] ||
287 nonzero
[info
->coupling_ang
[i
]]){
288 nonzero
[info
->coupling_mag
[i
]]=1;
289 nonzero
[info
->coupling_ang
[i
]]=1;
293 /* recover the residue into our working vectors */
294 for(i
=0;i
<info
->submaps
;i
++){
296 for(j
=0;j
<vi
->channels
;j
++){
297 if(info
->chmuxlist
[j
]==i
){
299 zerobundle
[ch_in_bundle
]=1;
301 zerobundle
[ch_in_bundle
]=0;
302 pcmbundle
[ch_in_bundle
++]=vb
->pcm
[j
];
306 look
->residue_func
[i
]->inverse(vb
,look
->residue_look
[i
],
307 pcmbundle
,zerobundle
,ch_in_bundle
);
310 //for(j=0;j<vi->channels;j++)
311 //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0);
314 /* channel coupling */
315 for(i
=info
->coupling_steps
-1;i
>=0;i
--){
316 ogg_int32_t
*pcmM
=vb
->pcm
[info
->coupling_mag
[i
]];
317 ogg_int32_t
*pcmA
=vb
->pcm
[info
->coupling_ang
[i
]];
318 channel_couple(pcmM
,pcmA
,n
);
321 //for(j=0;j<vi->channels;j++)
322 //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0);
324 //for(j=0;j<vi->channels;j++)
325 //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1);
327 /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
328 /* only MDCT right now.... */
330 for(i
=0;i
<vi
->channels
;i
++){
331 ogg_int32_t
*pcm
=vb
->pcm
[i
];
332 int submap
=info
->chmuxlist
[i
];
335 /* compute and apply spectral envelope */
336 look
->floor_func
[submap
]->
337 inverse2(vb
,look
->floor_look
[submap
],floormemo
[i
],pcm
);
339 ff_imdct_calc(ci
->blocksizes_nbits
[vb
->W
],
342 /* window the data */
343 _vorbis_apply_window(pcm
,b
->window
,ci
->blocksizes
,vb
->lW
,vb
->W
,vb
->nW
);
346 memset(pcm
, 0, sizeof(ogg_int32_t
)*n
);
349 //for(j=0;j<vi->channels;j++)
350 //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0);
352 //for(j=0;j<vi->channels;j++)
353 //_analysis_output("window",seq+j,vb->pcm[j],-24,n,0,0);
361 const vorbis_func_mapping mapping0_exportbundle ICONST_ATTR
={