blob: ccc84daef27de94442ff4c9c191e73688be5275e [file] [log] [blame]
/************************************************************************
* 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);
}