| /************************************************************************ |
| * Copyright (C) 2002-2009, Xiph.org Foundation |
| * Copyright (C) 2010, Robin Watts for Pinknoise Productions Ltd |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the names of the Xiph.org Foundation nor Pinknoise |
| * Productions Ltd nor the names of its contributors may be used to |
| * endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| ************************************************************************ |
| |
| function: channel mapping 0 implementation |
| |
| ************************************************************************/ |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <math.h> |
| #include "ogg.h" |
| #include "os.h" |
| #include "ivorbiscodec.h" |
| #include "mdct.h" |
| #include "codec_internal.h" |
| #include "codebook.h" |
| #include "misc.h" |
| |
| void mapping_clear_info(vorbis_info_mapping *info){ |
| if(info){ |
| if(info->chmuxlist)_ogg_free(info->chmuxlist); |
| if(info->submaplist)_ogg_free(info->submaplist); |
| if(info->coupling)_ogg_free(info->coupling); |
| memset(info,0,sizeof(*info)); |
| } |
| } |
| |
| static int ilog(unsigned int v){ |
| int ret=0; |
| if(v)--v; |
| while(v){ |
| ret++; |
| v>>=1; |
| } |
| return(ret); |
| } |
| |
| /* also responsible for range checking */ |
| int mapping_info_unpack(vorbis_info_mapping *info,vorbis_info *vi, |
| oggpack_buffer *opb){ |
| int i; |
| codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
| memset(info,0,sizeof(*info)); |
| |
| if(oggpack_read(opb,1)) |
| info->submaps=oggpack_read(opb,4)+1; |
| else |
| info->submaps=1; |
| |
| if(oggpack_read(opb,1)){ |
| info->coupling_steps=oggpack_read(opb,8)+1; |
| info->coupling= |
| _ogg_malloc(info->coupling_steps*sizeof(*info->coupling)); |
| |
| for(i=0;i<info->coupling_steps;i++){ |
| int testM=info->coupling[i].mag=(unsigned char)(oggpack_read(opb,ilog(vi->channels))); |
| int testA=info->coupling[i].ang=(unsigned char)(oggpack_read(opb,ilog(vi->channels))); |
| |
| if(testM<0 || |
| testA<0 || |
| testM==testA || |
| testM>=vi->channels || |
| testA>=vi->channels) goto err_out; |
| } |
| |
| } |
| |
| if(oggpack_read(opb,2)>0)goto err_out; /* 2,3:reserved */ |
| |
| if(info->submaps>1){ |
| info->chmuxlist=_ogg_malloc(sizeof(*info->chmuxlist)*vi->channels); |
| for(i=0;i<vi->channels;i++){ |
| info->chmuxlist[i]=(unsigned char)(oggpack_read(opb,4)); |
| if(info->chmuxlist[i]>=info->submaps)goto err_out; |
| } |
| } |
| |
| info->submaplist=_ogg_malloc(sizeof(*info->submaplist)*info->submaps); |
| for(i=0;i<info->submaps;i++){ |
| int temp=oggpack_read(opb,8); |
| info->submaplist[i].floor=(char)oggpack_read(opb,8); |
| if(info->submaplist[i].floor>=ci->floors)goto err_out; |
| info->submaplist[i].residue=(char)oggpack_read(opb,8); |
| if(info->submaplist[i].residue>=ci->residues)goto err_out; |
| } |
| |
| return 0; |
| |
| err_out: |
| mapping_clear_info(info); |
| return -1; |
| } |
| |
| int mapping_inverse(vorbis_dsp_state *vd,vorbis_info_mapping *info){ |
| vorbis_info *vi=vd->vi; |
| codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; |
| |
| int i,j; |
| long n=ci->blocksizes[vd->W]; |
| |
| ogg_int32_t **pcmbundle= |
| alloca(sizeof(*pcmbundle)*vi->channels); |
| int *zerobundle= |
| alloca(sizeof(*zerobundle)*vi->channels); |
| int *nonzero= |
| alloca(sizeof(*nonzero)*vi->channels); |
| ogg_int32_t **floormemo= |
| alloca(sizeof(*floormemo)*vi->channels); |
| |
| /* recover the spectral envelope; store it in the PCM vector for now */ |
| for(i=0;i<vi->channels;i++){ |
| int submap=0; |
| int floorno; |
| |
| if(info->submaps>1) |
| submap=info->chmuxlist[i]; |
| floorno=info->submaplist[submap].floor; |
| |
| if(ci->floor_type[floorno]){ |
| /* floor 1 */ |
| floormemo[i]=alloca(sizeof(*floormemo[i])* |
| floor1_memosize(ci->floor_param[floorno])); |
| floormemo[i]=floor1_inverse1(vd,ci->floor_param[floorno],floormemo[i]); |
| }else{ |
| /* floor 0 */ |
| floormemo[i]=alloca(sizeof(*floormemo[i])* |
| floor0_memosize(ci->floor_param[floorno])); |
| floormemo[i]=floor0_inverse1(vd,ci->floor_param[floorno],floormemo[i]); |
| } |
| |
| if(floormemo[i]) |
| nonzero[i]=1; |
| else |
| nonzero[i]=0; |
| memset(vd->work[i],0,sizeof(*vd->work[i])*n/2); |
| } |
| |
| /* channel coupling can 'dirty' the nonzero listing */ |
| for(i=0;i<info->coupling_steps;i++){ |
| if(nonzero[info->coupling[i].mag] || |
| nonzero[info->coupling[i].ang]){ |
| nonzero[info->coupling[i].mag]=1; |
| nonzero[info->coupling[i].ang]=1; |
| } |
| } |
| |
| /* recover the residue into our working vectors */ |
| for(i=0;i<info->submaps;i++){ |
| int ch_in_bundle=0; |
| for(j=0;j<vi->channels;j++){ |
| if(!info->chmuxlist || info->chmuxlist[j]==i){ |
| if(nonzero[j]) |
| zerobundle[ch_in_bundle]=1; |
| else |
| zerobundle[ch_in_bundle]=0; |
| pcmbundle[ch_in_bundle++]=vd->work[j]; |
| } |
| } |
| |
| res_inverse(vd,ci->residue_param+info->submaplist[i].residue, |
| pcmbundle,zerobundle,ch_in_bundle); |
| } |
| |
| //for(j=0;j<vi->channels;j++) |
| //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0); |
| |
| /* channel coupling */ |
| for(i=info->coupling_steps-1;i>=0;i--){ |
| ogg_int32_t *pcmM=vd->work[info->coupling[i].mag]; |
| ogg_int32_t *pcmA=vd->work[info->coupling[i].ang]; |
| |
| for(j=0;j<n/2;j++){ |
| ogg_int32_t mag=pcmM[j]; |
| ogg_int32_t ang=pcmA[j]; |
| |
| if(mag>0) |
| if(ang>0){ |
| pcmM[j]=mag; |
| pcmA[j]=mag-ang; |
| }else{ |
| pcmA[j]=mag; |
| pcmM[j]=mag+ang; |
| } |
| else |
| if(ang>0){ |
| pcmM[j]=mag; |
| pcmA[j]=mag+ang; |
| }else{ |
| pcmA[j]=mag; |
| pcmM[j]=mag-ang; |
| } |
| } |
| } |
| |
| //for(j=0;j<vi->channels;j++) |
| //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0); |
| |
| /* compute and apply spectral envelope */ |
| for(i=0;i<vi->channels;i++){ |
| ogg_int32_t *pcm=vd->work[i]; |
| int submap=0; |
| int floorno; |
| |
| if(info->submaps>1) |
| submap=info->chmuxlist[i]; |
| floorno=info->submaplist[submap].floor; |
| |
| if(ci->floor_type[floorno]){ |
| /* floor 1 */ |
| floor1_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm); |
| }else{ |
| /* floor 0 */ |
| floor0_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm); |
| } |
| } |
| |
| //for(j=0;j<vi->channels;j++) |
| //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1); |
| |
| /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ |
| /* only MDCT right now.... */ |
| for(i=0;i<vi->channels;i++) |
| mdct_backward(n,vd->work[i]); |
| |
| //for(j=0;j<vi->channels;j++) |
| //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0); |
| |
| /* all done! */ |
| return(0); |
| } |