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 b
=oggpack_read(opb
,1);
139 info
->submaps
=oggpack_read(opb
,4)+1;
140 if(info
->submaps
<=0)goto err_out
;
144 b
=oggpack_read(opb
,1);
147 info
->coupling_steps
=oggpack_read(opb
,8)+1;
148 if(info
->coupling_steps
<=0)goto err_out
;
149 for(i
=0;i
<info
->coupling_steps
;i
++){
150 int testM
=info
->coupling_mag
[i
]=oggpack_read(opb
,ilog(vi
->channels
));
151 int testA
=info
->coupling_ang
[i
]=oggpack_read(opb
,ilog(vi
->channels
));
156 testM
>=vi
->channels
||
157 testA
>=vi
->channels
) goto err_out
;
162 if(oggpack_read(opb
,2)!=0)goto err_out
; /* 2,3:reserved */
165 for(i
=0;i
<vi
->channels
;i
++){
166 info
->chmuxlist
[i
]=oggpack_read(opb
,4);
167 if(info
->chmuxlist
[i
]>=info
->submaps
|| info
->chmuxlist
[i
]<0)goto err_out
;
170 for(i
=0;i
<info
->submaps
;i
++){
171 int temp
=oggpack_read(opb
,8);
172 if(temp
>=ci
->times
)goto err_out
;
173 info
->floorsubmap
[i
]=oggpack_read(opb
,8);
174 if(info
->floorsubmap
[i
]>=ci
->floors
|| info
->floorsubmap
[i
]<0)goto err_out
;
175 info
->residuesubmap
[i
]=oggpack_read(opb
,8);
176 if(info
->residuesubmap
[i
]>=ci
->residues
|| info
->residuesubmap
[i
]<0)
183 mapping0_free_info(info
);
188 #define MAGANG( _mag, _ang )\
191 asm( "mov %[temp], %[ang]\n\t"\
192 "cmp %[mag], #0\n\t"\
193 "rsble %[temp], %[temp], #0\n\t"\
194 "cmp %[ang], #0\n\t"\
195 "subgt %[ang], %[mag], %[temp]\n\t"\
196 "movle %[ang], %[mag]\n\t"\
197 "addle %[mag], %[mag], %[temp]\n\t"\
198 : [mag] "+r" ( ( _mag ) ), [ang] "+r" ( ( _ang ) ), [temp] "=&r" (temp)\
203 static inline void channel_couple(ogg_int32_t
*pcmM
, ogg_int32_t
*pcmA
, int n
)
205 ogg_int32_t
* const pcmMend
= pcmM
+ n
/2;
206 while(LIKELY(pcmM
< pcmMend
))
208 register int M0
asm("r2"),M1
asm("r3"),M2
asm("r4"),M3
asm("r5");
209 register int A0
asm("r6"),A1
asm("r7"),A2
asm("r8"),A3
asm("r9");
210 asm volatile( "ldmia %[pcmM], {%[M0], %[M1], %[M2], %[M3]}\n\t"
211 "ldmia %[pcmA], {%[A0], %[A1], %[A2], %[A3]}\n\t"
212 : [M0
] "=r" (M0
), [M1
] "=r" (M1
), [M2
] "=r" (M2
), [M3
] "=r" (M3
),
213 [A0
] "=r" (A0
), [A1
] "=r" (A1
), [A2
] "=r" (A2
), [A3
] "=r" (A3
)
214 : [pcmM
] "r" (pcmM
), [pcmA
] "r" (pcmA
)
220 asm volatile( "stmia %[pcmM]!, {%[M0], %[M1], %[M2], %[M3]}\n\t"
221 "stmia %[pcmA]!, {%[A0], %[A1], %[A2], %[A3]}\n\t"
222 : [pcmM
] "+r" (pcmM
), [pcmA
] "+r" (pcmA
)
223 : [M0
] "r" (M0
), [M1
] "r" (M1
), [M2
] "r" (M2
), [M3
] "r" (M3
),
224 [A0
] "r" (A0
), [A1
] "r" (A1
), [A2
] "r" (A2
), [A3
] "r" (A3
)
229 #elif defined CPU_COLDFIRE
231 #define MAGANG( _mag, _ang, _pcmA, _pcmM, _off )\
234 asm volatile( "move.l %[ang], %[temp]\n\t"\
241 "add.l %[mag], %[temp]\n\t"\
242 "move.l %[temp], (" #_off ", %[pcmM])\n\t"\
243 ".word 0x51fa\n\t" /* trapf.w, shadow next insn */ \
245 "sub.l %[temp], %[mag]\n\t"\
246 "move.l %[mag], (%[pcmA])+\n\t"\
247 : [mag] "+r" ( ( _mag ) ), [ang] "+d" ( ( _ang ) ), [temp] "=&d" (temp),\
252 static inline void channel_couple(ogg_int32_t
*pcmM
, ogg_int32_t
*pcmA
, unsigned int n
)
254 ogg_int32_t
* const pcmMend
= pcmM
+ n
/2;
255 while(LIKELY(pcmM
< pcmMend
))
257 register int M0
asm("a2"),M1
asm("a3"),M2
asm("a4"),M3
asm("a5");
258 register int A0
asm("d2"),A1
asm("d3"),A2
asm("d4"),A3
asm("d5");
259 asm volatile( "movem.l (%[pcmM]), %[M0]-%[M3]\n\t"
260 "movem.l (%[pcmA]), %[A0]-%[A3]\n\t"
261 : [M0
] "=r" (M0
), [M1
] "=r" (M1
), [M2
] "=r" (M2
), [M3
] "=r" (M3
),
262 [A0
] "=r" (A0
), [A1
] "=r" (A1
), [A2
] "=r" (A2
), [A3
] "=r" (A3
)
263 : [pcmM
] "a" (pcmM
), [pcmA
] "a" (pcmA
) );
265 MAGANG( M0
, A0
, pcmA
, pcmM
, 0 );
266 MAGANG( M1
, A1
, pcmA
, pcmM
, 4 );
267 MAGANG( M2
, A2
, pcmA
, pcmM
, 8 );
268 MAGANG( M3
, A3
, pcmA
, pcmM
, 12 );
270 asm volatile( "lea.l (4*4, %[pcmM]), %[pcmM]\n\t"
271 : [pcmM
] "+a" (pcmM
));
275 static inline void channel_couple(ogg_int32_t
*pcmM
, ogg_int32_t
*pcmA
, int n
)
279 ogg_int32_t mag
= pcmM
[j
], ang
= pcmA
[j
], _ang
;
296 static int mapping0_inverse(vorbis_block
*vb
,vorbis_look_mapping
*l
){
297 vorbis_dsp_state
*vd
=vb
->vd
;
298 vorbis_info
*vi
=vd
->vi
;
299 codec_setup_info
*ci
=(codec_setup_info
*)vi
->codec_setup
;
300 private_state
*b
=(private_state
*)vd
->backend_state
;
301 vorbis_look_mapping0
*look
=(vorbis_look_mapping0
*)l
;
302 vorbis_info_mapping0
*info
=look
->map
;
305 long n
=vb
->pcmend
=ci
->blocksizes
[vb
->W
];
307 /* bounded mapping arrays instead of using alloca();
308 avoids memory leak; we can only deal with stereo anyway */
309 ogg_int32_t
*pcmbundle
[CHANNELS
];
310 int zerobundle
[CHANNELS
];
311 int nonzero
[CHANNELS
];
312 void *floormemo
[CHANNELS
];
314 /* time domain information decode (note that applying the
315 information would have to happen later; we'll probably add a
316 function entry to the harness for that later */
317 /* NOT IMPLEMENTED */
319 /* recover the spectral envelope; store it in the PCM vector for now */
320 for(i
=0;i
<vi
->channels
;i
++){
321 int submap
=info
->chmuxlist
[i
];
322 floormemo
[i
]=look
->floor_func
[submap
]->
323 inverse1(vb
,look
->floor_look
[submap
]);
328 memset(vb
->pcm
[i
],0,sizeof(*vb
->pcm
[i
])*n
/2);
331 /* channel coupling can 'dirty' the nonzero listing */
332 for(i
=0;i
<info
->coupling_steps
;i
++){
333 if(nonzero
[info
->coupling_mag
[i
]] ||
334 nonzero
[info
->coupling_ang
[i
]]){
335 nonzero
[info
->coupling_mag
[i
]]=1;
336 nonzero
[info
->coupling_ang
[i
]]=1;
340 /* recover the residue into our working vectors */
341 for(i
=0;i
<info
->submaps
;i
++){
343 for(j
=0;j
<vi
->channels
;j
++){
344 if(info
->chmuxlist
[j
]==i
){
346 zerobundle
[ch_in_bundle
]=1;
348 zerobundle
[ch_in_bundle
]=0;
349 pcmbundle
[ch_in_bundle
++]=vb
->pcm
[j
];
353 look
->residue_func
[i
]->inverse(vb
,look
->residue_look
[i
],
354 pcmbundle
,zerobundle
,ch_in_bundle
);
357 //for(j=0;j<vi->channels;j++)
358 //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0);
361 /* channel coupling */
362 for(i
=info
->coupling_steps
-1;i
>=0;i
--){
363 ogg_int32_t
*pcmM
=vb
->pcm
[info
->coupling_mag
[i
]];
364 ogg_int32_t
*pcmA
=vb
->pcm
[info
->coupling_ang
[i
]];
365 channel_couple(pcmM
,pcmA
,n
);
368 //for(j=0;j<vi->channels;j++)
369 //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0);
371 //for(j=0;j<vi->channels;j++)
372 //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1);
374 /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
375 /* only MDCT right now.... */
377 for(i
=0;i
<vi
->channels
;i
++){
378 ogg_int32_t
*pcm
=vb
->pcm
[i
];
379 int submap
=info
->chmuxlist
[i
];
382 /* compute and apply spectral envelope */
383 look
->floor_func
[submap
]->
384 inverse2(vb
,look
->floor_look
[submap
],floormemo
[i
],pcm
);
386 ff_imdct_calc(ci
->blocksizes_nbits
[vb
->W
],
389 /* window the data */
390 _vorbis_apply_window(pcm
,b
->window
,ci
->blocksizes
,vb
->lW
,vb
->W
,vb
->nW
);
393 memset(pcm
, 0, sizeof(ogg_int32_t
)*n
);
396 //for(j=0;j<vi->channels;j++)
397 //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0);
399 //for(j=0;j<vi->channels;j++)
400 //_analysis_output("window",seq+j,vb->pcm[j],-24,n,0,0);
408 const vorbis_func_mapping mapping0_exportbundle ICONST_ATTR
={