Logo Search packages:      
Sourcecode: alsa-tools version File versions  Download package

downmix.c

/*
 *
 *  downmix.c
 *    
 *    Copyright (C) Aaron Holtzman - Sept 1999
 *
 *    Originally based on code by Yuqing Deng.
 *
 *  This file is part of ac3dec, a free Dolby AC-3 stream decoder.
 *    
 *  ac3dec is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *   
 *  ac3dec is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *   
 *  You should have received a copy of the GNU General Public License
 *  along with GNU Make; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 *
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "ac3.h"
#include "ac3_internal.h"


#include "decode.h"
#include "downmix.h"
#include "debug.h"


//Pre-scaled downmix coefficients
static float cmixlev_lut[4] = { 0.2928, 0.2468, 0.2071, 0.2468 };
static float smixlev_lut[4] = { 0.2928, 0.2071, 0.0   , 0.2071 };

static void 
downmix_3f_2r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples)
{
      uint_32 j;
      float right_tmp;
      float left_tmp;
      float clev,slev;
      float *centre = 0, *left = 0, *right = 0, *left_sur = 0, *right_sur = 0;

      left      = samples[0];
      centre    = samples[1];
      right     = samples[2];
      left_sur  = samples[3];
      right_sur = samples[4];

      clev = cmixlev_lut[bsi->cmixlev];
      slev = smixlev_lut[bsi->surmixlev];

      for (j = 0; j < 256; j++) 
      {
            left_tmp = 0.4142f * *left++ + clev * *centre   + slev * *left_sur++;
            right_tmp= 0.4142f * *right++ + clev * *centre++ + slev * *right_sur++;

            s16_samples[j * 2 ]    = (sint_16) (left_tmp  * 32767.0f);
            s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f);
            // printf("[0] = %.6f, [1] = %.6f\n", left_tmp, right_tmp);
      }
}

static void 
downmix_3f_2r_to_4ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples)
{
      uint_32 j;
      float right_tmp, left_tmp, rear_right_tmp, rear_left_tmp;
      float clev,slev;
      float *centre = 0, *left = 0, *right = 0, *left_sur = 0, *right_sur = 0;

      left      = samples[0];
      centre    = samples[1];
      right     = samples[2];
      left_sur  = samples[3];
      right_sur = samples[4];

      clev = cmixlev_lut[bsi->cmixlev];
      slev = smixlev_lut[bsi->surmixlev];

      for (j = 0; j < 256; j++) 
      {
            left_tmp = 0.4142f * *left++  + clev * *centre;
            right_tmp= 0.4142f * *right++ + clev * *centre++;
            rear_left_tmp = 0.4142f * *left_sur++;
            rear_right_tmp = 0.4142f * *right_sur++;

            s16_samples[j * 4 ]    = (sint_16) (left_tmp  * 32767.0f);
            s16_samples[j * 4 + 1] = (sint_16) (right_tmp * 32767.0f);
            s16_samples[j * 4 + 2] = (sint_16) (rear_left_tmp  * 32767.0f);
            s16_samples[j * 4 + 3] = (sint_16) (rear_right_tmp * 32767.0f);
#if 0
            printf("[0] = %.6f, [1] = %.6f, [2] = %.6f, [3] = %.6f\n",
                        left_tmp, right_tmp, rear_left_tmp, rear_right_tmp);
#endif
      }
}

static void 
downmix_3f_2r_to_6ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples)
{
      uint_32 j;
      float right_tmp, centre_tmp, left_tmp, rear_right_tmp, rear_left_tmp, lfe_tmp;
      float clev,slev;
      float *centre = 0, *left = 0, *right = 0, *left_sur = 0, *right_sur = 0, *lfe = 0;

      left      = samples[0];
      centre    = samples[1];
      right     = samples[2];
      left_sur  = samples[3];
      right_sur = samples[4];
      lfe     = samples[5];

      clev = cmixlev_lut[bsi->cmixlev];
      slev = smixlev_lut[bsi->surmixlev];

      for (j = 0; j < 256; j++) 
      {
            left_tmp = 0.4142f * *left++;
            right_tmp= 0.4142f * *right++;
            centre_tmp = 0.4142f * *centre++;
            rear_left_tmp = 0.4142f * *left_sur++;
            rear_right_tmp = 0.4142f * *right_sur++;
            lfe_tmp = bsi->lfeon ? 0.4142f * *lfe++ : (float)0.0;

            s16_samples[j * 6 ]    = (sint_16) (left_tmp  * 32767.0f);
            s16_samples[j * 6 + 1] = (sint_16) (right_tmp * 32767.0f);
            s16_samples[j * 6 + 2] = (sint_16) (rear_left_tmp * 32767.0f);
            s16_samples[j * 6 + 3] = (sint_16) (rear_right_tmp * 32767.0f);
            s16_samples[j * 6 + 4] = (sint_16) (centre_tmp  * 32767.0f);
            s16_samples[j * 6 + 5] = (sint_16) (lfe_tmp * 32767.0f);
#if 0
            printf("[0] = %.6f, [1] = %.6f, [2] = %.6f, [3] = %.6f, [4] = %.6f, [5] = %.6f\n",
                        left_tmp, right_tmp, rear_left_tmp, rear_right_tmp,
                        centre_tmp, lfe_tmp);
#endif
      }
}

static void
downmix_2f_2r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples)
{
      uint_32 j;
      float right_tmp;
      float left_tmp;
      float slev;
      float *left = 0, *right = 0, *left_sur = 0, *right_sur = 0;

      left      = samples[0];
      right     = samples[1];
      left_sur  = samples[2];
      right_sur = samples[3];

      slev = smixlev_lut[bsi->surmixlev];

      for (j = 0; j < 256; j++) 
      {
            left_tmp = 0.4142f * *left++  + slev * *left_sur++;
            right_tmp= 0.4142f * *right++ + slev * *right_sur++;

            s16_samples[j * 2 ]    = (sint_16) (left_tmp  * 32767.0f);
            s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f);
      }
}

static void
downmix_3f_1r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples)
{
      uint_32 j;
      float right_tmp;
      float left_tmp;
      float clev,slev;
      float *centre = 0, *left = 0, *right = 0, *sur = 0;

      left      = samples[0];
      centre    = samples[1];
      right     = samples[2];
      //Mono surround
      sur = samples[3];

      clev = cmixlev_lut[bsi->cmixlev];
      slev = smixlev_lut[bsi->surmixlev];

      for (j = 0; j < 256; j++) 
      {
            left_tmp = 0.4142f * *left++  + clev * *centre++ + slev * *sur;
            right_tmp= 0.4142f * *right++ + clev * *centre   + slev * *sur++;

            s16_samples[j * 2 ]    = (sint_16) (left_tmp  * 32767.0f);
            s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f);
      }
}


static void
downmix_2f_1r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples)
{
      uint_32 j;
      float right_tmp;
      float left_tmp;
      float slev;
      float *left = 0, *right = 0, *sur = 0;

      left      = samples[0];
      right     = samples[1];
      //Mono surround
      sur = samples[2];

      slev = smixlev_lut[bsi->surmixlev];

      for (j = 0; j < 256; j++) 
      {
            left_tmp = 0.4142f * *left++  + slev * *sur;
            right_tmp= 0.4142f * *right++ + slev * *sur++;

            s16_samples[j * 2 ]    = (sint_16) (left_tmp  * 32767.0f);
            s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f);
      }
}

static void
downmix_3f_0r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples)
{
      uint_32 j;
      float right_tmp;
      float left_tmp;
      float clev;
      float *centre = 0, *left = 0, *right = 0;

      left      = samples[0];
      centre    = samples[1];
      right     = samples[2];

      clev = cmixlev_lut[bsi->cmixlev];

      for (j = 0; j < 256; j++) 
      {
            left_tmp = 0.4142f * *left++  + clev * *centre; 
            right_tmp= 0.4142f * *right++ + clev * *centre++;   

            s16_samples[j * 2 ]    = (sint_16) (left_tmp  * 32767.0f);
            s16_samples[j * 2 + 1] = (sint_16) (right_tmp * 32767.0f);
      }
}
                        
static void
downmix_2f_0r_to_2ch(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples)
{
      uint_32 j;
      float *left = 0, *right = 0;

      left      = samples[0];
      right     = samples[1];

      for (j = 0; j < 256; j++) 
      {
            s16_samples[j * 2 ]    = (sint_16) (*left++  * 32767.0f);
            s16_samples[j * 2 + 1] = (sint_16) (*right++ * 32767.0f);
      }
}

static void
downmix_1f_0r_to_2ch(float *centre,sint_16 *s16_samples)
{
      uint_32 j;
      float tmp;

      //Mono program!

      for (j = 0; j < 256; j++) 
      {
            tmp =  32767.0f * 0.7071f * *centre++;

            s16_samples[j * 2 ] = s16_samples[j * 2 + 1] = (sint_16) tmp;
      }
}

//
// Downmix into 2 or 4 channels  (4 ch isn't in quite yet)
//
// The downmix function names have the following format
//
// downmix_Xf_Yr_to_[2|4|6]ch[_dolby]
//
// where X        = number of front channels
//       Y        = number of rear channels
//       [2|4]    = number of output channels
//       [_dolby] = with or without dolby surround mix
//

void downmix(bsi_t* bsi, stream_samples_t samples,sint_16 *s16_samples)
{
      if(bsi->acmod > 7)
            dprintf("(downmix) invalid acmod number\n"); 

      //
      //There are two main cases, with or without Dolby Surround
      //
      if(ac3_config.flags & AC3_DOLBY_SURR_ENABLE)
      {
            fprintf(stderr,"Dolby Surround Mixes not currently enabled\n");
            exit(1);
      }

      //Non-Dolby surround downmixes
      switch(bsi->acmod)
      {
            // 3/2
            case 7:
                  switch (ac3_config.num_output_ch) {
                  case 2:
                        downmix_3f_2r_to_2ch(bsi,samples,s16_samples);
                        break;
                  case 4:
                        downmix_3f_2r_to_4ch(bsi,samples,s16_samples);
                        break;
                  case 6:
                        downmix_3f_2r_to_6ch(bsi,samples,s16_samples);
                        break;
                  default:
                        fprintf(stderr,"unsupported 3/2 channels %d\n", ac3_config.num_output_ch);
                        exit(1);
                  }
            break;

            // 2/2
            case 6:
                  if (ac3_config.num_output_ch != 2) {
                        fprintf(stderr,"unsupported 2/2 channels %d\n", ac3_config.num_output_ch);
                        exit(1);
                  }
                  downmix_2f_2r_to_2ch(bsi,samples,s16_samples);
            break;

            // 3/1
            case 5:
                  if (ac3_config.num_output_ch != 2) {
                        fprintf(stderr,"unsupported 3/1 channels %d\n", ac3_config.num_output_ch);
                        exit(1);
                  }
                  downmix_3f_1r_to_2ch(bsi,samples,s16_samples);
            break;

            // 2/1
            case 4:
                  if (ac3_config.num_output_ch != 2) {
                        fprintf(stderr,"unsupported 2/1 channels %d\n", ac3_config.num_output_ch);
                        exit(1);
                  }
                  downmix_2f_1r_to_2ch(bsi,samples,s16_samples);
            break;

            // 3/0
            case 3:
                  if (ac3_config.num_output_ch != 2) {
                        fprintf(stderr,"unsupported 3/0 channels %d\n", ac3_config.num_output_ch);
                        exit(1);
                  }
                  downmix_3f_0r_to_2ch(bsi,samples,s16_samples);
            break;

            // 2/0
            case 2:
                  if (ac3_config.num_output_ch != 2) {
                        fprintf(stderr,"unsupported 2/0 channels %d\n", ac3_config.num_output_ch);
                        exit(1);
                  }
                  downmix_2f_0r_to_2ch(bsi,samples,s16_samples);
            break;

            // 1/0
            case 1:
                  if (ac3_config.num_output_ch != 2) {
                        fprintf(stderr,"unsupported 1/0 channels %d\n", ac3_config.num_output_ch);
                        exit(1);
                  }
                  downmix_1f_0r_to_2ch(samples[0],s16_samples);
            break;

            // 1+1
            case 0:
                  if (ac3_config.num_output_ch != 2) {
                        fprintf(stderr,"unsupported 1/1 channels %d\n", ac3_config.num_output_ch);
                        exit(1);
                  }
                  downmix_1f_0r_to_2ch(samples[ac3_config.dual_mono_ch_sel],s16_samples);
            break;
      }
}



#if 0 

      //the dolby mixes lay here for the time being
      switch(bsi->acmod)
      {
            // 3/2
            case 7:
                  left      = samples[0];
                  centre    = samples[1];
                  right     = samples[2];
                  left_sur  = samples[3];
                  right_sur = samples[4];

                  for (j = 0; j < 256; j++) 
                  {
                        right_tmp = 0.2265f * *left_sur++ + 0.2265f * *right_sur++;
                        left_tmp  = -1 * right_tmp;
                        right_tmp += 0.3204f * *right++ + 0.2265f * *centre;
                        left_tmp  += 0.3204f * *left++  + 0.2265f * *centre++;

                        samples[1][j] = right_tmp;
                        samples[0][j] = left_tmp;
                  }

            break;

            // 2/2
            case 6:
                  left      = samples[0];
                  right     = samples[1];
                  left_sur  = samples[2];
                  right_sur = samples[3];

                  for (j = 0; j < 256; j++) 
                  {
                        right_tmp = 0.2265f * *left_sur++ + 0.2265f * *right_sur++;
                        left_tmp  = -1 * right_tmp;
                        right_tmp += 0.3204f * *right++;
                        left_tmp  += 0.3204f * *left++ ;

                        samples[1][j] = right_tmp;
                        samples[0][j] = left_tmp;
                  }
            break;

            // 3/1
            case 5:
                  left      = samples[0];
                  centre    = samples[1];
                  right     = samples[2];
                  //Mono surround
                  right_sur = samples[3];

                  for (j = 0; j < 256; j++) 
                  {
                        right_tmp =  0.2265f * *right_sur++;
                        left_tmp  = -1 * right_tmp;
                        right_tmp += 0.3204f * *right++ + 0.2265f * *centre;
                        left_tmp  += 0.3204f * *left++  + 0.2265f * *centre++;

                        samples[1][j] = right_tmp;
                        samples[0][j] = left_tmp;
                  }
            break;

            // 2/1
            case 4:
                  left      = samples[0];
                  right     = samples[1];
                  //Mono surround
                  right_sur = samples[2];

                  for (j = 0; j < 256; j++) 
                  {
                        right_tmp =  0.2265f * *right_sur++;
                        left_tmp  = -1 * right_tmp;
                        right_tmp += 0.3204f * *right++; 
                        left_tmp  += 0.3204f * *left++;

                        samples[1][j] = right_tmp;
                        samples[0][j] = left_tmp;
                  }
            break;

            // 3/0
            case 3:
                  left      = samples[0];
                  centre    = samples[1];
                  right     = samples[2];

                  for (j = 0; j < 256; j++) 
                  {
                        right_tmp = 0.3204f * *right++ + 0.2265f * *centre;
                        left_tmp  = 0.3204f * *left++  + 0.2265f * *centre++;

                        samples[1][j] = right_tmp;
                        samples[0][j] = left_tmp;
                  }
            break;

            // 2/0
            case 2:
            //Do nothing!
            break;

            // 1/0
            case 1:
                  //Mono program!
                  right = samples[0];

                  for (j = 0; j < 256; j++) 
                  {
                        right_tmp = 0.7071f * *right++;

                        samples[1][j] = right_tmp;
                        samples[0][j] = right_tmp;
                  }
                  
            break;

            // 1+1
            case 0:
                  //Dual mono, output selected by user
                  right = samples[ac3_config.dual_mono_ch_sel];

                  for (j = 0; j < 256; j++) 
                  {
                        right_tmp = 0.7071f * *right++;

                        samples[1][j] = right_tmp;
                        samples[0][j] = right_tmp;
                  }
            break;
#endif

Generated by  Doxygen 1.6.0   Back to index