1 /************************************************************************ 2 * Copyright (C) 2002-2009, Xiph.org Foundation 3 * Copyright (C) 2010, Robin Watts for Pinknoise Productions Ltd 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following disclaimer 14 * in the documentation and/or other materials provided with the 15 * distribution. 16 * * Neither the names of the Xiph.org Foundation nor Pinknoise 17 * Productions Ltd nor the names of its contributors may be used to 18 * endorse or promote products derived from this software without 19 * specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 ************************************************************************ 33 34 function: channel mapping 0 implementation 35 36 ************************************************************************/ 37 38 #include <stdlib.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <math.h> 42 #include "ogg.h" 43 #include "os.h" 44 #include "ivorbiscodec.h" 45 #include "mdct.h" 46 #include "codec_internal.h" 47 #include "codebook.h" 48 #include "misc.h" 49 50 void mapping_clear_info(vorbis_info_mapping *info){ 51 if(info){ 52 if(info->chmuxlist)_ogg_free(info->chmuxlist); 53 if(info->submaplist)_ogg_free(info->submaplist); 54 if(info->coupling)_ogg_free(info->coupling); 55 memset(info,0,sizeof(*info)); 56 } 57 } 58 59 static int ilog(unsigned int v){ 60 int ret=0; 61 if(v)--v; 62 while(v){ 63 ret++; 64 v>>=1; 65 } 66 return(ret); 67 } 68 69 /* also responsible for range checking */ 70 int mapping_info_unpack(vorbis_info_mapping *info,vorbis_info *vi, 71 oggpack_buffer *opb){ 72 int i; 73 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; 74 memset(info,0,sizeof(*info)); 75 76 if(oggpack_read(opb,1)) 77 info->submaps=oggpack_read(opb,4)+1; 78 else 79 info->submaps=1; 80 81 if(oggpack_read(opb,1)){ 82 info->coupling_steps=oggpack_read(opb,8)+1; 83 info->coupling= 84 _ogg_malloc(info->coupling_steps*sizeof(*info->coupling)); 85 86 for(i=0;i<info->coupling_steps;i++){ 87 int testM=info->coupling[i].mag=(unsigned char)(oggpack_read(opb,ilog(vi->channels))); 88 int testA=info->coupling[i].ang=(unsigned char)(oggpack_read(opb,ilog(vi->channels))); 89 90 if(testM<0 || 91 testA<0 || 92 testM==testA || 93 testM>=vi->channels || 94 testA>=vi->channels) goto err_out; 95 } 96 97 } 98 99 if(oggpack_read(opb,2)>0)goto err_out; /* 2,3:reserved */ 100 101 if(info->submaps>1){ 102 info->chmuxlist=_ogg_malloc(sizeof(*info->chmuxlist)*vi->channels); 103 for(i=0;i<vi->channels;i++){ 104 info->chmuxlist[i]=(unsigned char)(oggpack_read(opb,4)); 105 if(info->chmuxlist[i]>=info->submaps)goto err_out; 106 } 107 } 108 109 info->submaplist=_ogg_malloc(sizeof(*info->submaplist)*info->submaps); 110 for(i=0;i<info->submaps;i++){ 111 int temp=oggpack_read(opb,8); 112 info->submaplist[i].floor=(char)oggpack_read(opb,8); 113 if(info->submaplist[i].floor>=ci->floors)goto err_out; 114 info->submaplist[i].residue=(char)oggpack_read(opb,8); 115 if(info->submaplist[i].residue>=ci->residues)goto err_out; 116 } 117 118 return 0; 119 120 err_out: 121 mapping_clear_info(info); 122 return -1; 123 } 124 125 int mapping_inverse(vorbis_dsp_state *vd,vorbis_info_mapping *info){ 126 vorbis_info *vi=vd->vi; 127 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; 128 129 int i,j; 130 long n=ci->blocksizes[vd->W]; 131 132 ogg_int32_t **pcmbundle= 133 alloca(sizeof(*pcmbundle)*vi->channels); 134 int *zerobundle= 135 alloca(sizeof(*zerobundle)*vi->channels); 136 int *nonzero= 137 alloca(sizeof(*nonzero)*vi->channels); 138 ogg_int32_t **floormemo= 139 alloca(sizeof(*floormemo)*vi->channels); 140 141 /* recover the spectral envelope; store it in the PCM vector for now */ 142 for(i=0;i<vi->channels;i++){ 143 int submap=0; 144 int floorno; 145 146 if(info->submaps>1) 147 submap=info->chmuxlist[i]; 148 floorno=info->submaplist[submap].floor; 149 150 if(ci->floor_type[floorno]){ 151 /* floor 1 */ 152 floormemo[i]=alloca(sizeof(*floormemo[i])* 153 floor1_memosize(ci->floor_param[floorno])); 154 floormemo[i]=floor1_inverse1(vd,ci->floor_param[floorno],floormemo[i]); 155 }else{ 156 /* floor 0 */ 157 floormemo[i]=alloca(sizeof(*floormemo[i])* 158 floor0_memosize(ci->floor_param[floorno])); 159 floormemo[i]=floor0_inverse1(vd,ci->floor_param[floorno],floormemo[i]); 160 } 161 162 if(floormemo[i]) 163 nonzero[i]=1; 164 else 165 nonzero[i]=0; 166 memset(vd->work[i],0,sizeof(*vd->work[i])*n/2); 167 } 168 169 /* channel coupling can 'dirty' the nonzero listing */ 170 for(i=0;i<info->coupling_steps;i++){ 171 if(nonzero[info->coupling[i].mag] || 172 nonzero[info->coupling[i].ang]){ 173 nonzero[info->coupling[i].mag]=1; 174 nonzero[info->coupling[i].ang]=1; 175 } 176 } 177 178 /* recover the residue into our working vectors */ 179 for(i=0;i<info->submaps;i++){ 180 int ch_in_bundle=0; 181 for(j=0;j<vi->channels;j++){ 182 if(!info->chmuxlist || info->chmuxlist[j]==i){ 183 if(nonzero[j]) 184 zerobundle[ch_in_bundle]=1; 185 else 186 zerobundle[ch_in_bundle]=0; 187 pcmbundle[ch_in_bundle++]=vd->work[j]; 188 } 189 } 190 191 res_inverse(vd,ci->residue_param+info->submaplist[i].residue, 192 pcmbundle,zerobundle,ch_in_bundle); 193 } 194 195 //for(j=0;j<vi->channels;j++) 196 //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0); 197 198 /* channel coupling */ 199 for(i=info->coupling_steps-1;i>=0;i--){ 200 ogg_int32_t *pcmM=vd->work[info->coupling[i].mag]; 201 ogg_int32_t *pcmA=vd->work[info->coupling[i].ang]; 202 203 for(j=0;j<n/2;j++){ 204 ogg_int32_t mag=pcmM[j]; 205 ogg_int32_t ang=pcmA[j]; 206 207 if(mag>0) 208 if(ang>0){ 209 pcmM[j]=mag; 210 pcmA[j]=mag-ang; 211 }else{ 212 pcmA[j]=mag; 213 pcmM[j]=mag+ang; 214 } 215 else 216 if(ang>0){ 217 pcmM[j]=mag; 218 pcmA[j]=mag+ang; 219 }else{ 220 pcmA[j]=mag; 221 pcmM[j]=mag-ang; 222 } 223 } 224 } 225 226 //for(j=0;j<vi->channels;j++) 227 //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0); 228 229 /* compute and apply spectral envelope */ 230 for(i=0;i<vi->channels;i++){ 231 ogg_int32_t *pcm=vd->work[i]; 232 int submap=0; 233 int floorno; 234 235 if(info->submaps>1) 236 submap=info->chmuxlist[i]; 237 floorno=info->submaplist[submap].floor; 238 239 if(ci->floor_type[floorno]){ 240 /* floor 1 */ 241 floor1_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm); 242 }else{ 243 /* floor 0 */ 244 floor0_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm); 245 } 246 } 247 248 //for(j=0;j<vi->channels;j++) 249 //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1); 250 251 /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ 252 /* only MDCT right now.... */ 253 for(i=0;i<vi->channels;i++) 254 mdct_backward(n,vd->work[i]); 255 256 //for(j=0;j<vi->channels;j++) 257 //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0); 258 259 /* all done! */ 260 return(0); 261 } 262