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
50void 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
59static 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 */
70int 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
125int 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