summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuenter Bartsch <guenter@users.sourceforge.net>2001-07-20 22:37:56 +0000
committerGuenter Bartsch <guenter@users.sourceforge.net>2001-07-20 22:37:56 +0000
commit74534c743117a45b7f62c939f24270f7b5d549c5 (patch)
treedb28648ffc13941bad8276bf843659d15ff590bb
parent5254a0d8747c08ef38b0963c85485246b2b5a8e1 (diff)
downloadxine-lib-74534c743117a45b7f62c939f24270f7b5d549c5.tar.gz
xine-lib-74534c743117a45b7f62c939f24270f7b5d549c5.tar.bz2
latest libac3 update from walken including lfe support
CVS patchset: 314 CVS date: 2001/07/20 22:37:56
-rw-r--r--src/audio_out/audio_oss_out.c16
-rw-r--r--src/libac3/ac3.h26
-rw-r--r--src/libac3/ac3_internal.h18
-rw-r--r--src/libac3/bit_allocate.c5
-rw-r--r--src/libac3/bitstream.h2
-rw-r--r--src/libac3/downmix.c103
-rw-r--r--src/libac3/imdct.c59
-rw-r--r--src/libac3/imdct_mlib.c41
-rw-r--r--src/libac3/parse.c61
-rw-r--r--src/libac3/tables.h75
-rw-r--r--src/libac3/xine_decoder.c83
-rw-r--r--src/xine-engine/audio_out.h18
12 files changed, 276 insertions, 231 deletions
diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c
index fb5906776..8d36ae818 100644
--- a/src/audio_out/audio_oss_out.c
+++ b/src/audio_out/audio_oss_out.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: audio_oss_out.c,v 1.20 2001/07/14 17:45:06 jcdutton Exp $
+ * $Id: audio_oss_out.c,v 1.21 2001/07/20 22:37:56 guenter Exp $
*/
/* required for swab() */
@@ -198,6 +198,11 @@ static int ao_open(ao_functions_t *this_gen,
ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp);
this->num_channels = tmp;
break;
+ case AO_CAP_MODE_5_1CHANNEL:
+ tmp = 6;
+ ioctl(this->audio_fd, SNDCTL_DSP_CHANNELS, &tmp);
+ this->num_channels = tmp;
+ break;
case AO_CAP_MODE_AC3:
tmp = AFMT_AC3;
ioctl(this->audio_fd,SNDCTL_DSP_SETFMT,&tmp);
@@ -586,6 +591,15 @@ ao_functions_t *init_audio_out_plugin (config_values_t *config) {
} else
printf ("(5-channel not enabled in .xinerc) " );
}
+ num_channels = 6;
+ status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels);
+ if ( (status != -1) && (num_channels==6) ) {
+ if (config->lookup_int (config, "five_lfe_channel", 0)) {
+ this->capabilities |= AO_CAP_MODE_5_1CHANNEL;
+ printf ("5.1-channel ");
+ } else
+ printf ("(5.1-channel not enabled in .xinerc) " );
+ }
ioctl(audio_fd,SNDCTL_DSP_GETFMTS,&caps);
if (caps & AFMT_AC3) {
diff --git a/src/libac3/ac3.h b/src/libac3/ac3.h
index 305a10e49..03b849357 100644
--- a/src/libac3/ac3.h
+++ b/src/libac3/ac3.h
@@ -22,24 +22,28 @@
*
*/
+typedef float sample_t;
+
typedef struct ac3_ba_s {
- uint16_t fsnroffst; // fine SNR offset
- uint16_t fgaincod; // fast gain
- uint16_t deltbae; // delta bit allocation exists
- int8_t deltba[50]; // per-band delta bit allocation
+ uint16_t fsnroffst; // fine SNR offset
+ uint16_t fgaincod; // fast gain
+ uint16_t deltbae; // delta bit allocation exists
+ int8_t deltba[50]; // per-band delta bit allocation
} ac3_ba_t;
typedef struct ac3_state_s {
+ sample_t * delay; // delay samples for imdct
+
uint8_t fscod; // sample rate
uint8_t halfrate; // halfrate factor
uint8_t acmod; // coded channels
- float clev; // centre channel mix level
- float slev; // surround channels mix level
+ sample_t clev; // centre channel mix level
+ sample_t slev; // surround channels mix level
uint8_t lfeon; // coded lfe channel
int output; // type of output
- float level; // output level
- float bias; // output bias
+ sample_t level; // output level
+ sample_t bias; // output bias
uint16_t cplinu; // coupling in use
uint16_t chincpl[5]; // channel coupled
@@ -47,7 +51,7 @@ typedef struct ac3_state_s {
uint16_t cplbndstrc[18]; // coupling band structure
uint16_t cplstrtmant; // coupling channel start mantissa
uint16_t cplendmant; // coupling channel end mantissa
- float cplco[5][18]; // coupling coordinates
+ sample_t cplco[5][18]; // coupling coordinates
// derived information
uint16_t cplstrtbnd; // coupling start band (for bit allocation)
@@ -101,5 +105,5 @@ void ac3_init (void);
int ac3_syncinfo (uint8_t * buf, int * flags,
int * sample_rate, int * bit_rate);
int ac3_frame (ac3_state_t * state, uint8_t * buf, int * flags,
- float * level, float bias);
-int ac3_block (ac3_state_t * state);
+ sample_t * level, sample_t bias, sample_t * delay);
+int ac3_block (ac3_state_t * state, sample_t samples[][256]);
diff --git a/src/libac3/ac3_internal.h b/src/libac3/ac3_internal.h
index b414578bd..065ccbb36 100644
--- a/src/libac3/ac3_internal.h
+++ b/src/libac3/ac3_internal.h
@@ -26,29 +26,27 @@
#define LEVEL_45DB 0.5946035575013605
#define LEVEL_6DB 0.5
-/* Exponent strategy constants */
#define EXP_REUSE (0)
#define EXP_D15 (1)
#define EXP_D25 (2)
#define EXP_D45 (3)
-/* Delta bit allocation constants */
#define DELTA_BIT_REUSE (0)
#define DELTA_BIT_NEW (1)
#define DELTA_BIT_NONE (2)
#define DELTA_BIT_RESERVED (3)
-/* samples work structure */
-typedef float stream_samples_t[6][256];
-
void bit_allocate (ac3_state_t * state, ac3_ba_t * ba, int bndstart,
int start, int end, int fastleak, int slowleak,
uint8_t * exp, int8_t * bap);
-int downmix_init (int input, int flags, float * level, float clev, float slev);
-void downmix (float * samples, int acmod, int output, float level, float bias,
- float clev, float slev);
+int downmix_init (int input, int flags, sample_t * level,
+ sample_t clev, sample_t slev);
+void downmix (sample_t * samples, int acmod, int output,
+ sample_t level, sample_t bias, sample_t clev, sample_t slev);
void imdct_init (void);
-extern void (* imdct_256) (float data[], float delay[]);
-extern void (* imdct_512) (float data[], float delay[]);
+extern void (* imdct_256) (sample_t * data, sample_t * delay);
+extern void (* imdct_512) (sample_t * data, sample_t * delay);
+void imdct_do_256_mlib (sample_t * data, sample_t * delay);
+void imdct_do_512_mlib (sample_t * data, sample_t * delay);
diff --git a/src/libac3/bit_allocate.c b/src/libac3/bit_allocate.c
index 307c0074c..f3eaa1def 100644
--- a/src/libac3/bit_allocate.c
+++ b/src/libac3/bit_allocate.c
@@ -21,9 +21,10 @@
*
*/
+#include "config.h"
+
#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
+
#include "ac3.h"
#include "ac3_internal.h"
diff --git a/src/libac3/bitstream.h b/src/libac3/bitstream.h
index f290f7f66..84f3287c8 100644
--- a/src/libac3/bitstream.h
+++ b/src/libac3/bitstream.h
@@ -21,8 +21,6 @@
*
*/
-#include "config.h"
-
//My new and improved vego-matic endian swapping routine
//(stolen from the kernel)
#ifdef WORDS_BIGENDIAN
diff --git a/src/libac3/downmix.c b/src/libac3/downmix.c
index 9e7fbfb8b..498471798 100644
--- a/src/libac3/downmix.c
+++ b/src/libac3/downmix.c
@@ -25,18 +25,18 @@
*
*/
+#include "config.h"
+
#include <inttypes.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
+
#include "ac3.h"
#include "ac3_internal.h"
#define CONVERT(acmod,output) (((output) << 3) + (acmod))
-int downmix_init (int input, int flags, float * level, float clev, float slev)
+int downmix_init (int input, int flags, sample_t * level,
+ sample_t clev, sample_t slev)
{
static uint8_t table[11][8] = {
{AC3_CHANNEL, AC3_DOLBY, AC3_STEREO, AC3_STEREO,
@@ -150,12 +150,12 @@ int downmix_init (int input, int flags, float * level, float clev, float slev)
case CONVERT (AC3_3F2R, AC3_DOLBY):
*level *= 1 / (1 + 3 * LEVEL_3DB);
break;
- }
+ }
return output;
}
-static void mix1to1 (float * samples, float level, float bias)
+static void mix1to1 (sample_t * samples, sample_t level, sample_t bias)
{
int i;
@@ -163,7 +163,8 @@ static void mix1to1 (float * samples, float level, float bias)
samples[i] = samples[i] * level + bias;
}
-static void move1to1 (float * src, float * dest, float level, float bias)
+static void move1to1 (sample_t * src, sample_t * dest,
+ sample_t level, sample_t bias)
{
int i;
@@ -171,7 +172,7 @@ static void move1to1 (float * src, float * dest, float level, float bias)
dest[i] = src[i] * level + bias;
}
-static void mix2to1 (float * samples, float level, float bias)
+static void mix2to1 (sample_t * samples, sample_t level, sample_t bias)
{
int i;
@@ -179,7 +180,8 @@ static void mix2to1 (float * samples, float level, float bias)
samples[i] = (samples[i] + samples[i + 256]) * level + bias;
}
-static void move2to1 (float * src, float * dest, float level, float bias)
+static void move2to1 (sample_t * src, sample_t * dest,
+ sample_t level, sample_t bias)
{
int i;
@@ -187,7 +189,8 @@ static void move2to1 (float * src, float * dest, float level, float bias)
dest[i] = (src[i] + src[i + 256]) * level + bias;
}
-static void mix3to1 (float * samples, float level, float clev, float bias)
+static void mix3to1 (sample_t * samples, sample_t level, sample_t clev,
+ sample_t bias)
{
int i;
@@ -196,7 +199,8 @@ static void mix3to1 (float * samples, float level, float clev, float bias)
samples[i + 256] * clev + bias);
}
-static void mix21to1 (float * samples, float level, float slev, float bias)
+static void mix21to1 (sample_t * samples, sample_t level, sample_t slev,
+ sample_t bias)
{
int i;
@@ -205,8 +209,8 @@ static void mix21to1 (float * samples, float level, float slev, float bias)
samples[i + 512] * slev + bias);
}
-static void mix31to1 (float * samples, float level, float clev, float slev,
- float bias)
+static void mix31to1 (sample_t * samples, sample_t level,
+ sample_t clev, sample_t slev, sample_t bias)
{
int i;
@@ -216,7 +220,8 @@ static void mix31to1 (float * samples, float level, float clev, float slev,
bias);
}
-static void mix22to1 (float * samples, float level, float slev, float bias)
+static void mix22to1 (sample_t * samples, sample_t level, sample_t slev,
+ sample_t bias)
{
int i;
@@ -225,8 +230,8 @@ static void mix22to1 (float * samples, float level, float slev, float bias)
(samples[i + 512] + samples[i + 768]) * slev + bias);
}
-static void mix32to1 (float * samples, float level, float clev, float slev,
- float bias)
+static void mix32to1 (sample_t * samples, sample_t level,
+ sample_t clev, sample_t slev, sample_t bias)
{
int i;
@@ -236,7 +241,8 @@ static void mix32to1 (float * samples, float level, float clev, float slev,
(samples[i + 768] + samples[i + 1024]) * slev + bias);
}
-static void mix1to2 (float * src, float * dest, float level, float bias)
+static void mix1to2 (sample_t * src, sample_t * dest,
+ sample_t level, sample_t bias)
{
int i;
@@ -244,10 +250,11 @@ static void mix1to2 (float * src, float * dest, float level, float bias)
dest[i] = src[i] = src[i] * level + bias;
}
-static void mix3to2 (float * samples, float level, float clev, float bias)
+static void mix3to2 (sample_t * samples, sample_t level, sample_t clev,
+ sample_t bias)
{
int i;
- float common;
+ sample_t common;
for (i = 0; i < 256; i++) {
common = samples[i + 256] * clev + bias;
@@ -256,11 +263,11 @@ static void mix3to2 (float * samples, float level, float clev, float bias)
}
}
-static void mix21to2 (float * left, float * right, float level, float slev,
- float bias)
+static void mix21to2 (sample_t * left, sample_t * right,
+ sample_t level, sample_t slev, sample_t bias)
{
int i;
- float common;
+ sample_t common;
for (i = 0; i < 256; i++) {
common = right[i + 256] * slev + bias;
@@ -269,8 +276,8 @@ static void mix21to2 (float * left, float * right, float level, float slev,
}
}
-static void mix11to1 (float * front, float * rear, float level, float slev,
- float bias)
+static void mix11to1 (sample_t * front, sample_t * rear,
+ sample_t level, sample_t slev, sample_t bias)
{
int i;
@@ -278,11 +285,11 @@ static void mix11to1 (float * front, float * rear, float level, float slev,
front[i] = front[i] * level + rear[i] * slev + bias;
}
-static void mix31to2 (float * samples, float level, float clev, float slev,
- float bias)
+static void mix31to2 (sample_t * samples, sample_t level,
+ sample_t clev, sample_t slev, sample_t bias)
{
int i;
- float common;
+ sample_t common;
for (i = 0; i < 256; i++) {
common = samples[i + 256] * clev + samples[i + 768] * slev + bias;
@@ -291,11 +298,11 @@ static void mix31to2 (float * samples, float level, float clev, float slev,
}
}
-static void mix32to2 (float * samples, float level, float clev, float slev,
- float bias)
+static void mix32to2 (sample_t * samples, sample_t level,
+ sample_t clev, sample_t slev, sample_t bias)
{
int i;
- float common;
+ sample_t common;
for (i = 0; i < 256; i++) {
common = samples[i + 256] * clev + bias;
@@ -305,10 +312,11 @@ static void mix32to2 (float * samples, float level, float clev, float slev,
}
}
-static void mix21toS (float * samples, float level, float level3db, float bias)
+static void mix21toS (sample_t * samples,
+ sample_t level, sample_t level3db, sample_t bias)
{
int i;
- float surround;
+ sample_t surround;
for (i = 0; i < 256; i++) {
surround = samples[i + 512] * level3db;
@@ -317,10 +325,11 @@ static void mix21toS (float * samples, float level, float level3db, float bias)
}
}
-static void mix22toS (float * samples, float level, float level3db, float bias)
+static void mix22toS (sample_t * samples,
+ sample_t level, sample_t level3db, sample_t bias)
{
int i;
- float surround;
+ sample_t surround;
for (i = 0; i < 256; i++) {
surround = (samples[i + 512] + samples[i + 768]) * level3db;
@@ -329,10 +338,11 @@ static void mix22toS (float * samples, float level, float level3db, float bias)
}
}
-static void mix31toS (float * samples, float level, float level3db, float bias)
+static void mix31toS (sample_t * samples,
+ sample_t level, sample_t level3db, sample_t bias)
{
int i;
- float common, surround;
+ sample_t common, surround;
for (i = 0; i < 256; i++) {
common = samples[i + 256] * level3db + bias;
@@ -342,10 +352,11 @@ static void mix31toS (float * samples, float level, float level3db, float bias)
}
}
-static void mix32toS (float * samples, float level, float level3db, float bias)
+static void mix32toS (sample_t * samples,
+ sample_t level, sample_t level3db, sample_t bias)
{
int i;
- float common, surround;
+ sample_t common, surround;
for (i = 0; i < 256; i++) {
common = samples[i + 256] * level3db + bias;
@@ -355,8 +366,8 @@ static void mix32toS (float * samples, float level, float level3db, float bias)
}
}
-void downmix (float * samples, int acmod, int output, float level, float bias,
- float clev, float slev)
+void downmix (sample_t * samples, int acmod, int output,
+ sample_t level, sample_t bias, sample_t clev, sample_t slev)
{
switch (CONVERT (acmod, output & AC3_CHANNEL_MASK)) {
@@ -380,8 +391,7 @@ void downmix (float * samples, int acmod, int output, float level, float bias,
break;
case CONVERT (AC3_CHANNEL, AC3_CHANNEL2):
- mix_1to1_b:
- mix1to1 (samples + 256, level, bias);
+ move1to1 (samples + 256, samples, level, bias);
break;
case CONVERT (AC3_STEREO, AC3_MONO):
@@ -490,7 +500,8 @@ void downmix (float * samples, int acmod, int output, float level, float bias,
goto mix_3to3;
mix11to1 (samples, samples + 768, level, level * slev, bias);
mix11to1 (samples + 512, samples + 1024, level, level * slev, bias);
- goto mix_1to1_b;
+ mix1to1 (samples + 256, level, bias);
+ break;
case CONVERT (AC3_2F1R, AC3_2F2R):
mix1to2 (samples + 512, samples + 768, level * LEVEL_3DB, bias);
@@ -528,6 +539,8 @@ void downmix (float * samples, int acmod, int output, float level, float bias,
move1to1 (samples + 768, samples + 512, level, bias);
move1to1 (samples + 1024, samples + 768, level, bias);
break;
-
}
+
+ if (output & AC3_LFE)
+ mix1to1 (samples - 256, level, bias);
}
diff --git a/src/libac3/imdct.c b/src/libac3/imdct.c
index 030026a54..7cc221c89 100644
--- a/src/libac3/imdct.c
+++ b/src/libac3/imdct.c
@@ -25,19 +25,17 @@
#include "config.h"
#include <inttypes.h>
-#include <stdlib.h>
-#include <stdio.h>
#include <math.h>
+
#include "ac3.h"
#include "ac3_internal.h"
-void (* imdct_256) (float data[], float delay[]);
-void (* imdct_512) (float data[], float delay[]);
+void (* imdct_256) (sample_t data[], sample_t delay[]);
+void (* imdct_512) (sample_t data[], sample_t delay[]);
-typedef struct complex_s
-{
- float real;
- float imag;
+typedef struct complex_s {
+ sample_t real;
+ sample_t imag;
} complex_t;
@@ -83,13 +81,13 @@ static complex_t w_64[64];
static complex_t * w[7] = {w_1, w_2, w_4, w_8, w_16, w_32, w_64};
/* Twiddle factors for IMDCT */
-static float xcos1[128];
-static float xsin1[128];
-static float xcos2[64];
-static float xsin2[64];
+static sample_t xcos1[128];
+static sample_t xsin1[128];
+static sample_t xcos2[64];
+static sample_t xsin2[64];
/* Windowing function for Modified DCT - Thank you acroread */
-float imdct_window[] = {
+sample_t imdct_window[] = {
0.00014, 0.00024, 0.00037, 0.00051, 0.00067, 0.00086, 0.00107, 0.00130,
0.00157, 0.00187, 0.00220, 0.00256, 0.00297, 0.00341, 0.00390, 0.00443,
0.00501, 0.00564, 0.00632, 0.00706, 0.00785, 0.00871, 0.00962, 0.01061,
@@ -146,7 +144,7 @@ static inline complex_t cmplx_mult(complex_t a, complex_t b)
}
void
-imdct_do_512(float data[],float delay[])
+imdct_do_512(sample_t data[],sample_t delay[])
{
int i,k;
int p,q;
@@ -154,14 +152,14 @@ imdct_do_512(float data[],float delay[])
int two_m;
int two_m_plus_one;
- float tmp_a_i;
- float tmp_a_r;
- float tmp_b_i;
- float tmp_b_r;
+ sample_t tmp_a_i;
+ sample_t tmp_a_r;
+ sample_t tmp_b_i;
+ sample_t tmp_b_r;
- float *data_ptr;
- float *delay_ptr;
- float *window_ptr;
+ sample_t *data_ptr;
+ sample_t *delay_ptr;
+ sample_t *window_ptr;
//
// 512 IMDCT with source and dest data in 'data'
@@ -245,7 +243,7 @@ imdct_do_512(float data[],float delay[])
}
void
-imdct_do_256(float data[],float delay[])
+imdct_do_256(sample_t data[],sample_t delay[])
{
int i,k;
int p,q;
@@ -253,14 +251,14 @@ imdct_do_256(float data[],float delay[])
int two_m;
int two_m_plus_one;
- float tmp_a_i;
- float tmp_a_r;
- float tmp_b_i;
- float tmp_b_r;
+ sample_t tmp_a_i;
+ sample_t tmp_a_r;
+ sample_t tmp_b_i;
+ sample_t tmp_b_r;
- float *data_ptr;
- float *delay_ptr;
- float *window_ptr;
+ sample_t *data_ptr;
+ sample_t *delay_ptr;
+ sample_t *window_ptr;
complex_t *buf_1, *buf_2;
@@ -375,9 +373,6 @@ imdct_do_256(float data[],float delay[])
void imdct_init (void)
{
#ifdef LIBAC3_MLIB
- void imdct_do_256_mlib(float data[],float delay[]);
- void imdct_do_512_mlib(float data[],float delay[]);
-
imdct_512 = imdct_do_512_mlib;
imdct_256 = imdct_do_256_mlib;
#else
diff --git a/src/libac3/imdct_mlib.c b/src/libac3/imdct_mlib.c
index eca0139ee..1ba783359 100644
--- a/src/libac3/imdct_mlib.c
+++ b/src/libac3/imdct_mlib.c
@@ -24,29 +24,28 @@
#ifdef LIBAC3_MLIB
-#include <stdlib.h>
-#include <stdio.h>
-#include <math.h>
-
+#include <inttypes.h>
#include <mlib_types.h>
#include <mlib_status.h>
#include <mlib_signal.h>
+#include "ac3.h"
+#include "ac3_internal.h"
-extern float imdct_window[];
+extern sample_t imdct_window[];
void
-imdct_do_512_mlib(float data[], float delay[])
+imdct_do_512_mlib(sample_t data[], sample_t delay[])
{
- float *buf_real;
- float *buf_imag;
- float *data_ptr;
- float *delay_ptr;
- float *window_ptr;
- float tmp[256] __attribute__ ((__aligned__ (16)));
+ sample_t *buf_real;
+ sample_t *buf_imag;
+ sample_t *data_ptr;
+ sample_t *delay_ptr;
+ sample_t *window_ptr;
+ sample_t tmp[256] __attribute__ ((__aligned__ (16)));
int i;
- memcpy(tmp, data, 256 * sizeof(float));
+ memcpy(tmp, data, 256 * sizeof(sample_t));
if(mlib_SignalIMDCT_F32(tmp) != MLIB_SUCCESS) {
fprintf(stderr, "mediaLib failure\n");
exit(-1);
@@ -88,17 +87,17 @@ imdct_do_512_mlib(float data[], float delay[])
}
void
-imdct_do_256_mlib(float data[], float delay[])
+imdct_do_256_mlib(sample_t data[], sample_t delay[])
{
- float *buf1_real, *buf1_imag;
- float *buf2_real, *buf2_imag;
- float *data_ptr;
- float *delay_ptr;
- float *window_ptr;
- float tmp[256] __attribute__ ((__aligned__ (16)));
+ sample_t *buf1_real, *buf1_imag;
+ sample_t *buf2_real, *buf2_imag;
+ sample_t *data_ptr;
+ sample_t *delay_ptr;
+ sample_t *window_ptr;
+ sample_t tmp[256] __attribute__ ((__aligned__ (16)));
int i;
- memcpy(tmp, data, 256 * sizeof(float));
+ memcpy(tmp, data, 256 * sizeof(sample_t));
if(mlib_SignalIMDCT_F32(tmp) != MLIB_SUCCESS) {
fprintf(stderr, "mediaLib failure\n");
exit(-1);
diff --git a/src/libac3/parse.c b/src/libac3/parse.c
index 98ee09012..d200a2be1 100644
--- a/src/libac3/parse.c
+++ b/src/libac3/parse.c
@@ -22,18 +22,16 @@
*
*/
+#include "config.h"
+
#include <inttypes.h>
#include <string.h>
#include "ac3.h"
#include "ac3_internal.h"
-
#include "bitstream.h"
#include "tables.h"
-extern stream_samples_t samples; // FIXME
-static float delay[6][256];
-
void ac3_init (void)
{
imdct_init ();
@@ -62,8 +60,8 @@ int ac3_syncinfo (uint8_t * buf, int * flags,
// acmod, dsurmod and lfeon
acmod = buf[6] >> 5;
- *flags = (((buf[6] & 0xf8) == 0x50) ? AC3_DOLBY : acmod) |
- ((buf[6] & lfeon[acmod]) ? AC3_LFE : 0);
+ *flags = ((((buf[6] & 0xf8) == 0x50) ? AC3_DOLBY : acmod) |
+ ((buf[6] & lfeon[acmod]) ? AC3_LFE : 0));
frmsizecod = buf[4] & 63;
if (frmsizecod >= 38)
@@ -86,11 +84,11 @@ int ac3_syncinfo (uint8_t * buf, int * flags,
}
}
-int ac3_frame (ac3_state_t * state, uint8_t * buf, int * flags, float * level,
- float bias)
+int ac3_frame (ac3_state_t * state, uint8_t * buf, int * flags,
+ sample_t * level, sample_t bias, sample_t * delay)
{
- static float clev[4] = {LEVEL_3DB, LEVEL_45DB, LEVEL_6DB, LEVEL_45DB};
- static float slev[4] = {LEVEL_3DB, LEVEL_6DB, 0, LEVEL_6DB};
+ static sample_t clev[4] = {LEVEL_3DB, LEVEL_45DB, LEVEL_6DB, LEVEL_45DB};
+ static sample_t slev[4] = {LEVEL_3DB, LEVEL_6DB, 0, LEVEL_6DB};
int chaninfo;
int acmod;
@@ -114,12 +112,16 @@ int ac3_frame (ac3_state_t * state, uint8_t * buf, int * flags, float * level,
state->output = downmix_init (acmod, *flags, level,
state->clev, state->slev);
- if (state->output < 0) {
+ if (state->output < 0)
return 1;
+ if (state->lfeon && (*flags & AC3_LFE)) {
+ state->output |= AC3_LFE;
+ delay += 256;
}
*flags = state->output;
state->level = *level;
state->bias = bias;
+ state->delay = delay;
chaninfo = !acmod;
do {
@@ -242,9 +244,9 @@ static inline int zero_snr_offsets (int nfchans, ac3_state_t * state)
return 1;
}
-static float q_1[2];
-static float q_2[2];
-static float q_4;
+static sample_t q_1[2];
+static sample_t q_2[2];
+static sample_t q_4;
static int q_1_pointer;
static int q_2_pointer;
static int q_4_pointer;
@@ -333,7 +335,7 @@ static inline int16_t dither_gen(void)
return ((state * (int) (LEVEL_3DB * 256)) >> 8);
}
-static void coeff_get (float * coeff, uint8_t * exp, int8_t * bap,
+static void coeff_get (sample_t * coeff, uint8_t * exp, int8_t * bap,
int dither, int end)
{
int i;
@@ -360,7 +362,7 @@ static void coeff_get (float * coeff, uint8_t * exp, int8_t * bap,
i++; \
continue;
-int ac3_block (ac3_state_t * state)
+int ac3_block (ac3_state_t * state, sample_t samples[][256])
{
static const uint8_t nfchans_tbl[8] = {2, 1, 2, 3, 3, 4, 4, 5};
static int rematrix_band[4] = {25, 37, 61, 253};
@@ -585,6 +587,9 @@ int ac3_block (ac3_state_t * state)
bitstream_get (8);
}
+ if (state->output & AC3_LFE)
+ samples++; // shift for LFE channel
+
q_1_pointer = q_2_pointer = q_4_pointer = -1;
done_cpl = 0;
@@ -597,7 +602,7 @@ int ac3_block (ac3_state_t * state)
if (state->cplinu && state->chincpl[i]) {
if (!done_cpl) {
int i, i_end, bnd, sub_bnd, ch;
- float cplcoeff;
+ sample_t cplcoeff;
done_cpl = 1;
@@ -649,7 +654,7 @@ int ac3_block (ac3_state_t * state)
if (band > end)
band = end;
do {
- float tmp0, tmp1;
+ sample_t tmp0, tmp1;
tmp0 = samples[0][j];
tmp1 = samples[1][j];
@@ -660,23 +665,19 @@ int ac3_block (ac3_state_t * state)
}
if (state->lfeon) {
- coeff_get (samples[5], state->lfe_exp, state->lfe_bap, 0, 7);
-#if 0
- for (i = 7; i < 256; i++)
- samples[5][i] = 0;
-#endif
+ coeff_get (samples[-1], state->lfe_exp, state->lfe_bap, 0, 7);
+ if (state->output & AC3_LFE) {
+ for (i = 7; i < 256; i++)
+ samples[-1][i] = 0;
+ imdct_512 (samples[-1], state->delay - 256);
+ }
}
for (i = 0; i < nfchans; i++)
if (blksw[i])
- imdct_256 (samples[i], delay[i]);
+ imdct_256 (samples[i], state->delay + i * 256);
else
- imdct_512 (samples[i], delay[i]);
-
-#if 0
- if (state->lfeon)
- imdct_512 (samples[5], delay[5]);
-#endif
+ imdct_512 (samples[i], state->delay + i * 256);
downmix (*samples, state->acmod, state->output, state->level, state->bias,
state->clev, state->slev);
diff --git a/src/libac3/tables.h b/src/libac3/tables.h
index 5825f9326..28f030895 100644
--- a/src/libac3/tables.h
+++ b/src/libac3/tables.h
@@ -51,21 +51,21 @@ static int8_t exp_3[128] = {
#define Q1 (0)
#define Q2 ((2 << 15) / 3.0)
-static const float q_1_0[ 32 ] = {
+static const sample_t q_1_0[32] = {
Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,
Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,
Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,
0,0,0,0,0
};
-static const float q_1_1[ 32 ] = {
+static const sample_t q_1_1[32] = {
Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2,
Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2,
Q0,Q0,Q0,Q1,Q1,Q1,Q2,Q2,Q2,
0,0,0,0,0
};
-static const float q_1_2[ 32 ] = {
+static const sample_t q_1_2[32] = {
Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2,
Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2,
Q0,Q1,Q2,Q0,Q1,Q2,Q0,Q1,Q2,
@@ -82,7 +82,7 @@ static const float q_1_2[ 32 ] = {
#define Q3 ((2 << 15) / 5.0)
#define Q4 ((4 << 15) / 5.0)
-static const float q_2_0[ 128 ] = {
+static const sample_t q_2_0[128] = {
Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,Q0,
Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,Q1,
Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,Q2,
@@ -91,7 +91,7 @@ static const float q_2_0[ 128 ] = {
0,0,0
};
-static const float q_2_1[ 128 ] = {
+static const sample_t q_2_1[128] = {
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
Q0,Q0,Q0,Q0,Q0,Q1,Q1,Q1,Q1,Q1,Q2,Q2,Q2,Q2,Q2,Q3,Q3,Q3,Q3,Q3,Q4,Q4,Q4,Q4,Q4,
@@ -100,7 +100,7 @@ static const float q_2_1[ 128 ] = {
0,0,0
};
-static const float q_2_2[ 128 ] = {
+static const sample_t q_2_2[128] = {
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,Q0,Q1,Q2,Q3,Q4,
@@ -115,7 +115,7 @@ static const float q_2_2[ 128 ] = {
#undef Q3
#undef Q4
-static const float q_3[8] = {
+static const sample_t q_3[8] = {
(-6 << 15)/7.0, (-4 << 15)/7.0, (-2 << 15)/7.0, 0,
( 2 << 15)/7.0, ( 4 << 15)/7.0, ( 6 << 15)/7.0, 0
};
@@ -132,7 +132,7 @@ static const float q_3[8] = {
#define Q9 ((8 << 15) / 11.0)
#define QA ((10 << 15) / 11.0)
-static const float q_4_0[ 128 ] = {
+static const sample_t q_4_0[128] = {
Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0, Q0,
Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1, Q1,
Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2, Q2,
@@ -147,7 +147,7 @@ static const float q_4_0[ 128 ] = {
0, 0, 0, 0, 0, 0, 0
};
-static const float q_4_1[ 128 ] = {
+static const sample_t q_4_1[128] = {
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, QA,
@@ -174,7 +174,7 @@ static const float q_4_1[ 128 ] = {
#undef Q9
#undef QA
-static const float q_5[16] = {
+static const sample_t q_5[16] = {
(-14 << 15)/15.0,(-12 << 15)/15.0,(-10 << 15)/15.0,
( -8 << 15)/15.0,( -6 << 15)/15.0,( -4 << 15)/15.0,
( -2 << 15)/15.0, 0 ,( 2 << 15)/15.0,
@@ -183,37 +183,34 @@ static const float q_5[16] = {
0
};
-static const uint32_t u32_scale_factors[25] =
-{
- 0x38000000, //2 ^ -(0 + 15)
- 0x37800000, //2 ^ -(1 + 15)
- 0x37000000, //2 ^ -(2 + 15)
- 0x36800000, //2 ^ -(3 + 15)
- 0x36000000, //2 ^ -(4 + 15)
- 0x35800000, //2 ^ -(5 + 15)
- 0x35000000, //2 ^ -(6 + 15)
- 0x34800000, //2 ^ -(7 + 15)
- 0x34000000, //2 ^ -(8 + 15)
- 0x33800000, //2 ^ -(9 + 15)
- 0x33000000, //2 ^ -(10 + 15)
- 0x32800000, //2 ^ -(11 + 15)
- 0x32000000, //2 ^ -(12 + 15)
- 0x31800000, //2 ^ -(13 + 15)
- 0x31000000, //2 ^ -(14 + 15)
- 0x30800000, //2 ^ -(15 + 15)
- 0x30000000, //2 ^ -(16 + 15)
- 0x2f800000, //2 ^ -(17 + 15)
- 0x2f000000, //2 ^ -(18 + 15)
- 0x2e800000, //2 ^ -(19 + 15)
- 0x2e000000, //2 ^ -(20 + 15)
- 0x2d800000, //2 ^ -(21 + 15)
- 0x2d000000, //2 ^ -(22 + 15)
- 0x2c800000, //2 ^ -(23 + 15)
- 0x2c000000 //2 ^ -(24 + 15)
+static sample_t scale_factor[25] = {
+ 0.000030517578125,
+ 0.0000152587890625,
+ 0.00000762939453125,
+ 0.000003814697265625,
+ 0.0000019073486328125,
+ 0.00000095367431640625,
+ 0.000000476837158203125,
+ 0.0000002384185791015625,
+ 0.00000011920928955078125,
+ 0.000000059604644775390625,
+ 0.0000000298023223876953125,
+ 0.00000001490116119384765625,
+ 0.000000007450580596923828125,
+ 0.0000000037252902984619140625,
+ 0.00000000186264514923095703125,
+ 0.000000000931322574615478515625,
+ 0.0000000004656612873077392578125,
+ 0.00000000023283064365386962890625,
+ 0.000000000116415321826934814453125,
+ 0.0000000000582076609134674072265625,
+ 0.00000000002910383045673370361328125,
+ 0.000000000014551915228366851806640625,
+ 0.0000000000072759576141834259033203125,
+ 0.00000000000363797880709171295166015625,
+ 0.000000000001818989403545856475830078125
};
-static float * scale_factor = (float *) u32_scale_factors;
-
static const uint16_t dither_lut[256] = {
0x0000, 0xa011, 0xe033, 0x4022, 0x6077, 0xc066, 0x8044, 0x2055,
0xc0ee, 0x60ff, 0x20dd, 0x80cc, 0xa099, 0x0088, 0x40aa, 0xe0bb,
diff --git a/src/libac3/xine_decoder.c b/src/libac3/xine_decoder.c
index 72909c58e..0bd12e5e2 100644
--- a/src/libac3/xine_decoder.c
+++ b/src/libac3/xine_decoder.c
@@ -17,15 +17,11 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: xine_decoder.c,v 1.15 2001/07/17 15:22:20 jkeil Exp $
+ * $Id: xine_decoder.c,v 1.16 2001/07/20 22:37:56 guenter Exp $
*
* stuff needed to turn libac3 into a xine decoder plugin
*/
-/*
- * FIXME: libac3 uses global variables (that are written to)
- */
-
#include <stdlib.h>
#include <unistd.h>
@@ -42,9 +38,7 @@
#define FRAME_SIZE 4096
-stream_samples_t samples;
-
-/* int ac3file; */
+int ac3file;
typedef struct ac3dec_decoder_s {
audio_decoder_t audio_decoder;
@@ -63,11 +57,14 @@ typedef struct ac3dec_decoder_s {
int ac3_bit_rate;
int ac3_sample_rate;
float ac3_level;
+ int have_lfe;
int ac3_flags_map[8];
int ao_flags_map[8];
- int16_t samples [6 * 256];
+ int16_t int_samples [6 * 256];
+ sample_t delay[6*256];
+ sample_t samples[6][256];
ao_functions_t *audio_out;
int audio_caps;
@@ -125,7 +122,14 @@ void ac3dec_init (audio_decoder_t *this_gen, ao_functions_t *audio_out) {
this->ao_flags_map[AC3_3F2R] = AO_CAP_MODE_STEREO;
/* find best mode */
- if (this->audio_caps & AO_CAP_MODE_5CHANNEL) {
+ if (this->audio_caps & AO_CAP_MODE_5_1CHANNEL) {
+
+ this->ac3_flags_map[AC3_2F2R] = AC3_2F2R;
+ this->ac3_flags_map[AC3_3F2R] = AC3_3F2R | AC3_LFE;
+ this->ao_flags_map[AC3_2F2R] = AO_CAP_MODE_4CHANNEL;
+ this->ao_flags_map[AC3_3F2R] = AO_CAP_MODE_5CHANNEL;
+
+ } else if (this->audio_caps & AO_CAP_MODE_5CHANNEL) {
this->ac3_flags_map[AC3_2F2R] = AC3_2F2R;
this->ac3_flags_map[AC3_3F2R] = AC3_3F2R;
@@ -167,7 +171,7 @@ void ac3dec_init (audio_decoder_t *this_gen, ao_functions_t *audio_out) {
for (i = 0; i<8; i++)
this->ac3_flags_map[i] |= AC3_ADJUST_LEVEL;
*/
- /* ac3file = open ("test.ac3", O_CREAT); */
+ ac3file = open ("test.ac3", O_CREAT | O_WRONLY | O_TRUNC, 0644);
}
@@ -214,12 +218,16 @@ static void ac3dec_decode_frame (ac3dec_decoder_t *this, uint32_t pts) {
if (ac3_frame (&this->ac3_state,
this->frame_buffer,
&ac3_output_flags,
- &level, 384)) {
+ &level, 384, this->delay)) {
printf ("libac3: ac3_frame error\n");
return;
}
- output_mode = this->ao_flags_map[ac3_output_flags];
+ this->have_lfe = ac3_output_flags & AC3_LFE;
+ if (this->have_lfe)
+ output_mode = AO_CAP_MODE_5_1CHANNEL;
+ else
+ output_mode = this->ao_flags_map[ac3_output_flags];
/*
* (re-)open output device
@@ -250,31 +258,39 @@ static void ac3dec_decode_frame (ac3dec_decoder_t *this, uint32_t pts) {
*/
for (i = 0; i < 6; i++) {
- if (ac3_block (&this->ac3_state)) {
+ if (ac3_block (&this->ac3_state, this->samples)) {
printf ("libac3: ac3_block error\n");
- return;
+ return;
}
switch (output_mode) {
case AO_CAP_MODE_MONO:
- float_to_int (*samples, this->samples, 1);
+ float_to_int (this->samples[0], this->int_samples, 1);
break;
case AO_CAP_MODE_STEREO:
- float_to_int (samples[0], this->samples, 2);
- float_to_int (samples[1], this->samples+1, 2);
+ float_to_int (this->samples[0], this->int_samples, 2);
+ float_to_int (this->samples[1], this->int_samples+1, 2);
break;
case AO_CAP_MODE_4CHANNEL:
- float_to_int (samples[0], this->samples, 4);
- float_to_int (samples[1], this->samples+1, 4);
- float_to_int (samples[2], this->samples+2, 4);
- float_to_int (samples[3], this->samples+3, 4);
+ float_to_int (this->samples[0], this->int_samples, 4);
+ float_to_int (this->samples[1], this->int_samples+1, 4);
+ float_to_int (this->samples[2], this->int_samples+2, 4);
+ float_to_int (this->samples[3], this->int_samples+3, 4);
break;
case AO_CAP_MODE_5CHANNEL:
- float_to_int (samples[0], this->samples, 5);
- float_to_int (samples[1], this->samples+1, 5);
- float_to_int (samples[2], this->samples+2, 5);
- float_to_int (samples[3], this->samples+3, 5);
- float_to_int (samples[4], this->samples+4, 5);
+ float_to_int (this->samples[0], this->int_samples, 5);
+ float_to_int (this->samples[1], this->int_samples+1, 5);
+ float_to_int (this->samples[2], this->int_samples+2, 5);
+ float_to_int (this->samples[3], this->int_samples+3, 5);
+ float_to_int (this->samples[4], this->int_samples+4, 5);
+ break;
+ case AO_CAP_MODE_5_1CHANNEL:
+ float_to_int (this->samples[0], this->int_samples, 6);
+ float_to_int (this->samples[1], this->int_samples+1, 6);
+ float_to_int (this->samples[2], this->int_samples+2, 6);
+ float_to_int (this->samples[3], this->int_samples+3, 6);
+ float_to_int (this->samples[4], this->int_samples+4, 6);
+ float_to_int (this->samples[5], this->int_samples+5, 6);
break;
default:
printf ("libac3: help - unsupported mode %08x\n", output_mode);
@@ -283,7 +299,7 @@ static void ac3dec_decode_frame (ac3dec_decoder_t *this, uint32_t pts) {
/* output decoded samples */
this->audio_out->write_audio_data (this->audio_out,
- this->samples,
+ this->int_samples,
256,
pts);
pts = 0;
@@ -341,6 +357,7 @@ void ac3dec_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
if ( (this->sync_todo == 0) && (this->frame_todo == 0) ) {
ac3dec_decode_frame (this, this->pts);
+ write (ac3file, this->frame_buffer, this->frame_length);
this->pts = 0;
this->sync_todo = 7;
this->syncword = 0;
@@ -374,7 +391,13 @@ void ac3dec_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
&this->ac3_flags,
&this->ac3_sample_rate,
&this->ac3_bit_rate);
- this->frame_todo = this->frame_length - 7;
+ if (this->frame_length) {
+ this->frame_todo = this->frame_length - 7;
+ } else {
+ this->sync_todo = 7;
+ this->syncword = 0;
+ printf ("libac3: skip frame of zero length\n");
+ }
}
@@ -406,7 +429,7 @@ void ac3dec_close (audio_decoder_t *this_gen) {
this->output_open = 0;
- /* close (ac3file); */
+ close (ac3file);
}
static char *ac3dec_get_id(void) {
diff --git a/src/xine-engine/audio_out.h b/src/xine-engine/audio_out.h
index e66419271..c3e1fffbc 100644
--- a/src/xine-engine/audio_out.h
+++ b/src/xine-engine/audio_out.h
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: audio_out.h,v 1.7 2001/07/18 21:38:17 f1rmb Exp $
+ * $Id: audio_out.h,v 1.8 2001/07/20 22:37:56 guenter Exp $
*/
#ifndef HAVE_AUDIO_OUT_H
#define HAVE_AUDIO_OUT_H
@@ -132,17 +132,19 @@ struct ao_functions_s {
#define AO_CAP_NOCAP 0x00000000 /* driver has no capabilities */
#define AO_CAP_MODE_AC3 0x00000001 /* driver supports AC3 output */
#define AO_CAP_MODE_AC5 0x00000002 /* driver supports AC5 output */
-/* 1 sample == 2 bytes */
+/* 1 sample == 2 bytes (C) */
#define AO_CAP_MODE_MONO 0x00000004 /* driver supports mono output */
- /* 1 sample == 4 bytes */
+/* 1 sample == 4 bytes (L,R) */
#define AO_CAP_MODE_STEREO 0x00000008 /* driver supports stereo output */
- /* 1 sample == 8 bytes */
+/* 1 sample == 8 bytes (L,R,LR,RR) */
#define AO_CAP_MODE_4CHANNEL 0x00000010 /* driver supports 4 channels */
-/* 1 sample == 10 bytes */
+/* 1 sample == 10 bytes (L,R,LR,RR,C) */
#define AO_CAP_MODE_5CHANNEL 0x00000020 /* driver supports 5 channels */
-#define AO_CAP_MIXER_VOL 0x00000040 /* driver supports mixer control */
-#define AO_CAP_PCM_VOL 0x00000080 /* driver supports pcm control */
-#define AO_CAP_MUTE_VOL 0x00000100 /* driver can mute volume */
+/* 1 sample == 12 bytes (L,R,LR,RR,C,LFE) */
+#define AO_CAP_MODE_5_1CHANNEL 0x00000040 /* driver supports 5.1 channels */
+#define AO_CAP_MIXER_VOL 0x00000080 /* driver supports mixer control */
+#define AO_CAP_PCM_VOL 0x00000100 /* driver supports pcm control */
+#define AO_CAP_MUTE_VOL 0x00000200 /* driver can mute volume */
/* properties supported by get/set_property() */
#define AO_PROP_MIXER_VOL 0