summaryrefslogtreecommitdiff
path: root/src/post/audio/upmix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/post/audio/upmix.c')
-rw-r--r--src/post/audio/upmix.c138
1 files changed, 68 insertions, 70 deletions
diff --git a/src/post/audio/upmix.c b/src/post/audio/upmix.c
index 777f552de..58c0ec55e 100644
--- a/src/post/audio/upmix.c
+++ b/src/post/audio/upmix.c
@@ -23,7 +23,7 @@
* process. It simply paints the screen a solid color and rotates through
* colors on each iteration.
*
- * $Id: upmix.c,v 1.1 2004/05/15 15:32:47 jcdutton Exp $
+ * $Id: upmix.c,v 1.2 2004/05/15 18:22:26 jcdutton Exp $
*
*/
@@ -32,6 +32,7 @@
#include "xine_internal.h"
#include "xineutils.h"
#include "post.h"
+#include "dsp.h"
#define FPS 20
@@ -49,6 +50,39 @@ struct post_class_upmix_s {
xine_t *xine;
};
+
+/* Q value for low-pass filter */
+#define Q 1.0
+
+/* Analog domain biquad section */
+typedef struct{
+ float a[3]; // Numerator coefficients
+ float b[3]; // Denominator coefficients
+} biquad_t;
+
+/* S-parameters for designing 4th order Butterworth filter */
+static biquad_t s_param[2] = {{{1.0,0.0,0.0},{1.0,0.765367,1.0}},
+ {{1.0,0.0,0.0},{1.0,1.847759,1.0}}};
+
+/* Data for specific instances of this filter */
+typedef struct af_sub_s
+{
+ float w[2][4]; /* Filter taps for low-pass filter */
+ float q[2][2]; /* Circular queues */
+ float fc; /* Cutoff frequency [Hz] for low-pass filter */
+ float k; /* Filter gain */
+}af_sub_t;
+
+#ifndef IIR
+#define IIR(in,w,q,out) { \
+ float h0 = (q)[0]; \
+ float h1 = (q)[1]; \
+ float hn = (in) - h0 * (w)[0] - h1 * (w)[1]; \
+ out = hn + h0 * (w)[2] + h1 * (w)[3]; \
+ (q)[1] = h0; \
+ (q)[0] = hn; \
+}
+#endif
struct post_plugin_upmix_s {
post_plugin_t post;
@@ -65,6 +99,7 @@ struct post_plugin_upmix_s {
int data_idx;
short data [2][NUMSAMPLES];
audio_buffer_t *buf; /* dummy buffer just to hold a copy of audio data */
+ af_sub_t *sub;
int channels;
int channels_out;
@@ -129,6 +164,22 @@ static int upmix_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
} else {
this->channels_out=2;
}
+
+ this->sub = xine_xmalloc(sizeof(af_sub_t));
+ if (!this->sub) {
+ return 0;
+ }
+ this->sub->fc = 60; /* LFE Cutoff frequency 60Hz */
+ this->sub->k = 1.0;
+ if((-1 == szxform(s_param[0].a, s_param[0].b, Q, this->sub->fc,
+ (float)rate, &this->sub->k, this->sub->w[0])) ||
+ (-1 == szxform(s_param[1].a, s_param[1].b, Q, this->sub->fc,
+ (float)rate, &this->sub->k, this->sub->w[1]))) {
+ free(this->sub);
+ this->sub=NULL;
+ return 0;
+ }
+
this->samples_per_frame = rate / FPS;
this->data_idx = 0;
@@ -153,7 +204,7 @@ static void upmix_port_close(xine_audio_port_t *port_gen, xine_stream_t *stream
_x_post_dec_usage(port);
}
-int upmix_frames_2to51_16bit(uint8_t *dst8, uint8_t *src8, int num_frames) {
+static int upmix_frames_2to51_16bit(uint8_t *dst8, uint8_t *src8, int num_frames, af_sub_t *sub) {
int16_t *dst=(int16_t *)dst8;
int16_t *src=(int16_t *)src8;
@@ -163,16 +214,26 @@ int upmix_frames_2to51_16bit(uint8_t *dst8, uint8_t *src8, int num_frames) {
int dst_num_channels=6;
int src_frame;
int dst_frame;
+ float sample;
+ int32_t sum;
for (frame=0;frame < num_frames; frame++) {
dst_frame=frame*dst_num_channels*bytes_per_sample;
src_frame=frame*src_num_channels*bytes_per_sample;
dst[dst_frame] = src[src_frame];
dst[dst_frame+(1*bytes_per_sample)] = src[src_frame+(1*bytes_per_sample)];
- dst[dst_frame+(2*bytes_per_sample)] = (src[src_frame] - src[src_frame+(1*bytes_per_sample)]) / 2; /* try a bit of dolby */
+ /* try a bit of dolby */
+ /* FIXME: Dobly surround is a bit more complicated than this, but this is a start. */
+ dst[dst_frame+(2*bytes_per_sample)] = (src[src_frame] - src[src_frame+(1*bytes_per_sample)]) / 2;
dst[dst_frame+(3*bytes_per_sample)] = (src[src_frame] - src[src_frame+(1*bytes_per_sample)]) / 2;
- dst[dst_frame+(4*bytes_per_sample)] = (src[src_frame] + src[src_frame+(1*bytes_per_sample)]) / 2;
- dst[dst_frame+(5*bytes_per_sample)] = 0;
+ sum = ((int32_t)src[src_frame] + (int32_t)src[src_frame+(1*bytes_per_sample)]) / 2;
+ dst[dst_frame+(4*bytes_per_sample)] = (int16_t)sum;
+ /* Create the LFE channel using a low pass filter */
+ /* filter feature ported from mplayer */
+ sample = (1.0/SHRT_MAX)*((float)sum);
+ IIR(sample * sub->k, sub->w[0], sub->q[0], sample);
+ IIR(sample , sub->w[1], sub->q[1], sample);
+ dst[dst_frame+(5*bytes_per_sample)] = (int16_t)(sample * SHRT_MAX);
}
return frame;
}
@@ -213,8 +274,6 @@ static void upmix_port_put_buffer (xine_audio_port_t *port_gen,
this->buf->format.rate = port->rate;
this->buf->format.mode = AO_CAP_MODE_5_1CHANNEL;
_x_extra_info_merge( this->buf->extra_info, buf->extra_info);
- // xine_stream_t *stream; /* stream that send that buffer */
- /* FIXME: This does 2 to 5.1 channel upmix */
step_channel = this->buf->format.bits>>3;
dst_step_frame = this->channels_out*step_channel;
src_step_frame = this->channels*step_channel;
@@ -226,78 +285,18 @@ static void upmix_port_put_buffer (xine_audio_port_t *port_gen,
data8src=(int8_t*)buf->mem;
data8src+=num_frames_processed*src_step_frame;
data8dst=(int8_t*)this->buf->mem;
- num_frames_done = upmix_frames_2to51_16bit(data8dst, data8src, num_frames);
+ num_frames_done = upmix_frames_2to51_16bit(data8dst, data8src, num_frames, this->sub);
this->buf->num_frames = num_frames_done;
num_frames_processed+= num_frames_done;
/* pass data to original port */
port->original_port->put_buffer(port->original_port, this->buf, stream );
}
}
- //printf("num_frames_done=%d, num_frames=%d\n",num_frames_done, num_frames);
/* free data from origial buffer */
buf->num_frames=0; /* UNDOCUMENTED, but hey, it works! Force old audio_out buffer free. */
port->original_port->put_buffer(port->original_port, buf, stream );
- /* pass data to original port */
- /* we must not use original data anymore, it should have already being moved
- * to the fifo of free audio buffers. just use our private copy instead.
- */
-
return;
-
- buf = this->buf;
-
- this->sample_counter += buf->num_frames;
-
- j = (this->channels >= 2) ? 1 : 0;
-
- do {
-
- if( port->bits == 8 ) {
- data8 = (int8_t *)buf->mem;
- data8 += samples_used * this->channels;
-
- /* scale 8 bit data to 16 bits and convert to signed as well */
- for( i = 0; i < buf->num_frames && this->data_idx < NUMSAMPLES;
- i++, this->data_idx++, data8 += this->channels ) {
- this->data[0][this->data_idx] = ((int16_t)data8[0] << 8) - 0x8000;
- this->data[1][this->data_idx] = ((int16_t)data8[j] << 8) - 0x8000;
- }
- } else {
- data = buf->mem;
- data += samples_used * this->channels;
-
- for( i = 0; i < buf->num_frames && this->data_idx < NUMSAMPLES;
- i++, this->data_idx++, data += this->channels ) {
- this->data[0][this->data_idx] = data[0];
- this->data[1][this->data_idx] = data[j];
- }
- }
-
- if( this->sample_counter >= this->samples_per_frame &&
- this->data_idx == NUMSAMPLES ) {
-
- this->data_idx = 0;
- samples_used += this->samples_per_frame;
-
- frame = this->vo_port->get_frame (this->vo_port, FOO_WIDTH, FOO_HEIGHT,
- this->ratio, XINE_IMGFMT_YUY2,
- VO_BOTH_FIELDS);
- frame->extra_info->invalid = 1;
- frame->bad_frame = 0;
- frame->duration = 90000 * this->samples_per_frame / port->rate;
- frame->pts = pts;
- this->metronom->got_video_frame(this->metronom, frame);
-
- this->sample_counter -= this->samples_per_frame;
-
- memset(frame->base[0], this->current_yuv_byte, FOO_WIDTH * FOO_HEIGHT * 2);
- this->current_yuv_byte += 3;
-
- frame->draw(frame, NULL);
- frame->free(frame);
- }
- } while( this->sample_counter >= this->samples_per_frame );
}
static void upmix_dispose(post_plugin_t *this_gen)
@@ -305,9 +304,8 @@ static void upmix_dispose(post_plugin_t *this_gen)
post_plugin_upmix_t *this = (post_plugin_upmix_t *)this_gen;
if (_x_post_dispose(this_gen)) {
-
this->metronom->exit(this->metronom);
-
+ if (this->sub) free(this->sub);
free(this);
}
}