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-2002 * 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/ogg.h> 23 #include "ivorbiscodec.h" 24 #include "mdct.h" 25 #include "codec_internal.h" 26 #include "codebook.h" 27 #include "window.h" 28 #include "registry.h" 29 #include "misc.h" 30 31 /* simplistic, wasteful way of doing this (unique lookup for each 32 mode/submapping); there should be a central repository for 33 identical lookups. That will require minor work, so I'm putting it 34 off as low priority. 35 36 Why a lookup for each backend in a given mode? Because the 37 blocksize is set by the mode, and low backend lookups may require 38 parameters from other areas of the mode/mapping */ 39 40 typedef struct { 41 vorbis_info_mode *mode; 42 vorbis_info_mapping0 *map; 43 44 vorbis_look_floor **floor_look; 45 46 vorbis_look_residue **residue_look; 47 48 vorbis_func_floor **floor_func; 49 vorbis_func_residue **residue_func; 50 51 int ch; 52 long lastframe; /* if a different mode is called, we need to 53 invalidate decay */ 54 } vorbis_look_mapping0; 55 56 static void mapping0_free_info(vorbis_info_mapping *i){ 57 vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i; 58 if(info){ 59 memset(info,0,sizeof(*info)); 60 _ogg_free(info); 61 } 62 } 63 64 static void mapping0_free_look(vorbis_look_mapping *look){ 65 int i; 66 vorbis_look_mapping0 *l=(vorbis_look_mapping0 *)look; 67 if(l){ 68 69 for(i=0;i<l->map->submaps;i++){ 70 l->floor_func[i]->free_look(l->floor_look[i]); 71 l->residue_func[i]->free_look(l->residue_look[i]); 72 } 73 74 _ogg_free(l->floor_func); 75 _ogg_free(l->residue_func); 76 _ogg_free(l->floor_look); 77 _ogg_free(l->residue_look); 78 memset(l,0,sizeof(*l)); 79 _ogg_free(l); 80 } 81 } 82 83 static vorbis_look_mapping *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm, 84 vorbis_info_mapping *m){ 85 int i; 86 vorbis_info *vi=vd->vi; 87 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; 88 vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)_ogg_calloc(1,sizeof(*look)); 89 vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m; 90 look->mode=vm; 91 92 look->floor_look=(vorbis_look_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_look)); 93 94 look->residue_look=(vorbis_look_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_look)); 95 96 look->floor_func=(vorbis_func_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_func)); 97 look->residue_func=(vorbis_func_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_func)); 98 99 for(i=0;i<info->submaps;i++){ 100 int floornum=info->floorsubmap[i]; 101 int resnum=info->residuesubmap[i]; 102 103 look->floor_func[i]=_floor_P[ci->floor_type[floornum]]; 104 look->floor_look[i]=look->floor_func[i]-> 105 look(vd,vm,ci->floor_param[floornum]); 106 look->residue_func[i]=_residue_P[ci->residue_type[resnum]]; 107 look->residue_look[i]=look->residue_func[i]-> 108 look(vd,vm,ci->residue_param[resnum]); 109 110 } 111 112 look->ch=vi->channels; 113 114 return(look); 115 } 116 117 static int ilog(unsigned int v){ 118 int ret=0; 119 if(v)--v; 120 while(v){ 121 ret++; 122 v>>=1; 123 } 124 return(ret); 125 } 126 127 /* also responsible for range checking */ 128 static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){ 129 int i,b; 130 vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)_ogg_calloc(1,sizeof(*info)); 131 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; 132 memset(info,0,sizeof(*info)); 133 134 b=oggpack_read(opb,1); 135 if(b<0)goto err_out; 136 if(b){ 137 info->submaps=oggpack_read(opb,4)+1; 138 if(info->submaps<=0)goto err_out; 139 }else 140 info->submaps=1; 141 142 b=oggpack_read(opb,1); 143 if(b<0)goto err_out; 144 if(b){ 145 info->coupling_steps=oggpack_read(opb,8)+1; 146 if(info->coupling_steps<=0)goto err_out; 147 for(i=0;i<info->coupling_steps;i++){ 148 int testM=info->coupling_mag[i]=oggpack_read(opb,ilog(vi->channels)); 149 int testA=info->coupling_ang[i]=oggpack_read(opb,ilog(vi->channels)); 150 151 if(testM<0 || 152 testA<0 || 153 testM==testA || 154 testM>=vi->channels || 155 testA>=vi->channels) goto err_out; 156 } 157 158 } 159 160 if(oggpack_read(opb,2)!=0)goto err_out; /* 2,3:reserved */ 161 162 if(info->submaps>1){ 163 for(i=0;i<vi->channels;i++){ 164 info->chmuxlist[i]=oggpack_read(opb,4); 165 if(info->chmuxlist[i]>=info->submaps || info->chmuxlist[i]<0)goto err_out; 166 } 167 } 168 for(i=0;i<info->submaps;i++){ 169 int temp=oggpack_read(opb,8); 170 if(temp>=ci->times)goto err_out; 171 info->floorsubmap[i]=oggpack_read(opb,8); 172 if(info->floorsubmap[i]>=ci->floors || info->floorsubmap[i]<0)goto err_out; 173 info->residuesubmap[i]=oggpack_read(opb,8); 174 if(info->residuesubmap[i]>=ci->residues || info->residuesubmap[i]<0) 175 goto err_out; 176 } 177 178 return info; 179 180 err_out: 181 mapping0_free_info(info); 182 return(NULL); 183 } 184 185 static int seq=0; 186 static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){ 187 vorbis_dsp_state *vd=vb->vd; 188 vorbis_info *vi=vd->vi; 189 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; 190 private_state *b=(private_state *)vd->backend_state; 191 vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l; 192 vorbis_info_mapping0 *info=look->map; 193 194 int i,j; 195 long n=vb->pcmend=ci->blocksizes[vb->W]; 196 197 ogg_int32_t **pcmbundle=(ogg_int32_t **)alloca(sizeof(*pcmbundle)*vi->channels); 198 int *zerobundle=(int *)alloca(sizeof(*zerobundle)*vi->channels); 199 200 int *nonzero =(int *)alloca(sizeof(*nonzero)*vi->channels); 201 void **floormemo=(void **)alloca(sizeof(*floormemo)*vi->channels); 202 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 */ 207 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]); 213 if(floormemo[i]) 214 nonzero[i]=1; 215 else 216 nonzero[i]=0; 217 memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2); 218 } 219 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; 226 } 227 } 228 229 /* recover the residue into our working vectors */ 230 for(i=0;i<info->submaps;i++){ 231 int ch_in_bundle=0; 232 for(j=0;j<vi->channels;j++){ 233 if(info->chmuxlist[j]==i){ 234 if(nonzero[j]) 235 zerobundle[ch_in_bundle]=1; 236 else 237 zerobundle[ch_in_bundle]=0; 238 pcmbundle[ch_in_bundle++]=vb->pcm[j]; 239 } 240 } 241 242 look->residue_func[i]->inverse(vb,look->residue_look[i], 243 pcmbundle,zerobundle,ch_in_bundle); 244 } 245 246 //for(j=0;j<vi->channels;j++) 247 //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0); 248 249 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]]; 254 255 for(j=0;j<n/2;j++){ 256 ogg_int32_t mag=pcmM[j]; 257 ogg_int32_t ang=pcmA[j]; 258 259 if(mag>0) 260 if(ang>0){ 261 pcmM[j]=mag; 262 pcmA[j]=mag-ang; 263 }else{ 264 pcmA[j]=mag; 265 pcmM[j]=mag+ang; 266 } 267 else 268 if(ang>0){ 269 pcmM[j]=mag; 270 pcmA[j]=mag+ang; 271 }else{ 272 pcmA[j]=mag; 273 pcmM[j]=mag-ang; 274 } 275 } 276 } 277 278 //for(j=0;j<vi->channels;j++) 279 //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0); 280 281 /* compute and apply spectral envelope */ 282 for(i=0;i<vi->channels;i++){ 283 ogg_int32_t *pcm=vb->pcm[i]; 284 int submap=info->chmuxlist[i]; 285 look->floor_func[submap]-> 286 inverse2(vb,look->floor_look[submap],floormemo[i],pcm); 287 } 288 289 //for(j=0;j<vi->channels;j++) 290 //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1); 291 292 /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ 293 /* only MDCT right now.... */ 294 for(i=0;i<vi->channels;i++){ 295 ogg_int32_t *pcm=vb->pcm[i]; 296 mdct_backward(n,pcm,pcm); 297 } 298 299 //for(j=0;j<vi->channels;j++) 300 //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0); 301 302 /* window the data */ 303 for(i=0;i<vi->channels;i++){ 304 ogg_int32_t *pcm=vb->pcm[i]; 305 if(nonzero[i]) 306 _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW); 307 else 308 for(j=0;j<n;j++) 309 pcm[j]=0; 310 311 } 312 313 //for(j=0;j<vi->channels;j++) 314 //_analysis_output("window",seq+j,vb->pcm[j],-24,n,0,0); 315 316 seq+=vi->channels; 317 /* all done! */ 318 return(0); 319 } 320 321 /* export hooks */ 322 vorbis_func_mapping mapping0_exportbundle={ 323 &mapping0_unpack, 324 &mapping0_look, 325 &mapping0_free_info, 326 &mapping0_free_look, 327 &mapping0_inverse 328 }; 329