Home | History | Annotate | Download | only in Tremolo
      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