summaryrefslogtreecommitdiff
path: root/src/libac3/downmix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libac3/downmix.c')
-rw-r--r--src/libac3/downmix.c255
1 files changed, 213 insertions, 42 deletions
diff --git a/src/libac3/downmix.c b/src/libac3/downmix.c
index a50b045be..fd801308d 100644
--- a/src/libac3/downmix.c
+++ b/src/libac3/downmix.c
@@ -42,6 +42,54 @@ 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_5ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
+{
+ uint32_t j;
+ 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];
+
+ for (j = 0; j < 256; j++)
+ {
+ s16_samples[j * 5 ] = (int16_t) (*left++ * 32767.0f);
+ s16_samples[j * 5 + 1] = (int16_t) (*right++ * 32767.0f);
+ s16_samples[j * 5 + 2] = (int16_t) (*left_sur++ * 32767.0f);
+ s16_samples[j * 5 + 3] = (int16_t) (*right_sur++ * 32767.0f);
+ s16_samples[j * 5 + 4] = (int16_t) (*centre++ * 32767.0f);
+ }
+}
+
+static void
+downmix_3f_2r_to_4ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
+{
+ uint32_t j;
+ float right_tmp;
+ float left_tmp;
+ 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];
+
+ for (j = 0; j < 256; j++)
+ {
+ left_tmp = 0.5000f * *left++ + 0.500f * *centre ;
+ right_tmp= 0.5000f * *right++ + 0.500f * *centre++ ;
+
+ s16_samples[j * 4 ] = (int16_t) (left_tmp * 32767.0f);
+ s16_samples[j * 4 + 1] = (int16_t) (right_tmp * 32767.0f);
+ s16_samples[j * 4 + 2] = (int16_t) (*left_sur++ * 32767.0f);
+ s16_samples[j * 4 + 3] = (int16_t) (*right_sur++ * 32767.0f);
+ }
+}
+
+static void
downmix_3f_2r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
{
uint32_t j;
@@ -70,6 +118,29 @@ downmix_3f_2r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_
}
static void
+downmix_2f_2r_to_4ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
+{
+ uint32_t j;
+ 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[state->surmixlev];
+
+ for (j = 0; j < 256; j++)
+ {
+ s16_samples[j * 5 ] = (int16_t) (*left++ * 32767.0f);
+ s16_samples[j * 5 + 1] = (int16_t) (*right++ * 32767.0f);
+ s16_samples[j * 5 + 2] = (int16_t) (*left_sur++ * 32767.0f);
+ s16_samples[j * 5 + 3] = (int16_t) (*right_sur++ * 32767.0f);
+ }
+}
+
+static void
downmix_2f_2r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
{
uint32_t j;
@@ -96,6 +167,58 @@ downmix_2f_2r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_
}
static void
+downmix_3f_1r_to_5ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
+{
+ uint32_t j;
+ float *centre = 0, *left = 0, *right = 0, *sur = 0;
+
+ left = samples[0];
+ centre = samples[1];
+ right = samples[2];
+ //Mono surround
+ sur = samples[3];
+
+ for (j = 0; j < 256; j++)
+ {
+ s16_samples[j * 5 ] = (int16_t) (*left++ * 32767.0f);
+ s16_samples[j * 5 + 1] = (int16_t) (*right++ * 32767.0f);
+ s16_samples[j * 5 + 2] = (int16_t) (*sur * 32767.0f);
+ s16_samples[j * 5 + 3] = (int16_t) (*sur++ * 32767.0f);
+ s16_samples[j * 5 + 4] = (int16_t) (*centre++ * 32767.0f);
+ }
+}
+
+static void
+downmix_3f_1r_to_4ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
+{
+ uint32_t 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[state->cmixlev];
+ slev = smixlev_lut[state->surmixlev];
+
+ for (j = 0; j < 256; j++)
+ {
+ left_tmp = 0.5000f * *left++ + 0.500f * *centre ;
+ right_tmp= 0.5000f * *right++ + 0.500f * *centre++ ;
+
+ s16_samples[j * 4 ] = (int16_t) (left_tmp * 32767.0f);
+ s16_samples[j * 4 + 1] = (int16_t) (right_tmp * 32767.0f);
+ s16_samples[j * 4 + 2] = (int16_t) (*sur * 32767.0f);
+ s16_samples[j * 4 + 3] = (int16_t) (*sur++ * 32767.0f);
+ }
+}
+
+static void
downmix_3f_1r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
{
uint32_t j;
@@ -125,6 +248,26 @@ downmix_3f_1r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_
static void
+downmix_2f_1r_to_4ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
+{
+ uint32_t j;
+ float *left = 0, *right = 0, *sur = 0;
+
+ left = samples[0];
+ right = samples[1];
+ //Mono surround
+ sur = samples[2];
+
+ for (j = 0; j < 256; j++)
+ {
+ s16_samples[j * 4 ] = (int16_t) (*left++ * 32767.0f);
+ s16_samples[j * 4 + 1] = (int16_t) (*right++ * 32767.0f);
+ s16_samples[j * 4 + 2] = (int16_t) (*sur * 32767.0f);
+ s16_samples[j * 4 + 3] = (int16_t) (*sur++ * 32767.0f);
+ }
+}
+
+static void
downmix_2f_1r_to_2ch(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
{
uint32_t j;
@@ -208,19 +351,19 @@ downmix_1f_0r_to_2ch(float *centre,int16_t *s16_samples)
}
//
-// Downmix into 2 or 4 channels (4 ch isn't in quite yet)
+// Downmix into 2 or 4 or 5 channels (4 ch isn't in quite yet)
//
// The downmix function names have the following format
//
-// downmix_Xf_Yr_to_[2|4]ch[_dolby]
+// downmix_Xf_Yr_to_[2|4|5]ch[_dolby]
//
// where X = number of front channels
// Y = number of rear channels
-// [2|4] = number of output channels
+// [2|4|5] = number of output channels
// [_dolby] = with or without dolby surround mix
//
-void downmix(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
+void downmix(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples, int num_channels)
{
if(state->acmod > 7)
dprintf("(downmix) invalid acmod number\n");
@@ -239,46 +382,74 @@ void downmix(ac3_state_t * state, stream_samples_t samples,int16_t *s16_samples)
//Non-Dolby surround downmixes
switch(state->acmod)
{
- // 3/2
- case 7:
- downmix_3f_2r_to_2ch(state, samples,s16_samples);
- break;
-
- // 2/2
- case 6:
- downmix_2f_2r_to_2ch(state, samples,s16_samples);
- break;
-
- // 3/1
- case 5:
- downmix_3f_1r_to_2ch(state, samples,s16_samples);
- break;
-
- // 2/1
- case 4:
- downmix_2f_1r_to_2ch(state, samples,s16_samples);
- break;
-
- // 3/0
- case 3:
- downmix_3f_0r_to_2ch(state, samples,s16_samples);
- break;
-
- case 2:
- downmix_2f_0r_to_2ch(state, samples,s16_samples);
- break;
-
- // 1/0
- case 1:
- downmix_1f_0r_to_2ch(samples[0],s16_samples);
- break;
-
- // 1+1
- case 0:
+ // 3/2
+ case 7:
+ switch (num_channels) {
+ case 5:
+ downmix_3f_2r_to_5ch(state, samples,s16_samples);
+ break;
+ case 4:
+ downmix_3f_2r_to_4ch(state, samples,s16_samples);
+ break;
+ case 2:
+ downmix_3f_2r_to_2ch(state, samples,s16_samples);
+ break;
+ }
+ break;
+
+ // 2/2
+ case 6:
+ if (num_channels == 4)
+ downmix_2f_2r_to_4ch(state, samples,s16_samples);
+ else
+ downmix_2f_2r_to_2ch(state, samples,s16_samples);
+ break;
+
+ // 3/1
+ case 5:
+
+ switch (num_channels) {
+ case 5:
+ downmix_3f_1r_to_5ch(state, samples,s16_samples);
+ break;
+ case 4:
+ downmix_3f_1r_to_4ch(state, samples,s16_samples);
+ break;
+ case 2:
+ downmix_3f_1r_to_2ch(state, samples,s16_samples);
+ break;
+ }
+
+ break;
+
+ // 2/1
+ case 4:
+ if (num_channels == 4)
+ downmix_2f_1r_to_4ch(state, samples,s16_samples);
+ else
+ downmix_2f_1r_to_2ch(state, samples,s16_samples);
+ break;
+
+ // 3/0
+ case 3:
+ downmix_3f_0r_to_2ch(state, samples,s16_samples);
+ break;
+
+ case 2:
+ downmix_2f_0r_to_2ch(state, samples,s16_samples);
+ break;
+
+ // 1/0
+ case 1:
+ downmix_1f_0r_to_2ch(samples[0],s16_samples);
+ break;
+
+ // 1+1
+ case 0:
#if 0
- downmix_1f_0r_to_2ch(samples[ac3_config.dual_mono_ch_sel],s16_samples);
+ downmix_1f_0r_to_2ch(samples[ac3_config.dual_mono_ch_sel],s16_samples);
#endif
- break;
+ break;
}
}