summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel Freitas <miguelfreitas@users.sourceforge.net>2004-07-26 22:23:34 +0000
committerMiguel Freitas <miguelfreitas@users.sourceforge.net>2004-07-26 22:23:34 +0000
commitdfa7cc55e0b7646a82a21b0d6b7c8bb99ac42584 (patch)
tree2934417e2c281251089b7e4e311bf11a92c29ac3
parente7e06fffe8992cf912b62c8d6bf51581647471b1 (diff)
downloadxine-lib-dfa7cc55e0b7646a82a21b0d6b7c8bb99ac42584.tar.gz
xine-lib-dfa7cc55e0b7646a82a21b0d6b7c8bb99ac42584.tar.bz2
experimental time stretching plugin
CVS patchset: 6855 CVS date: 2004/07/26 22:23:34
-rw-r--r--src/post/audio/Makefile.am10
-rw-r--r--src/post/audio/audio_filters.c42
-rw-r--r--src/post/audio/stretch.c689
-rw-r--r--src/post/audio/upmix.c29
4 files changed, 738 insertions, 32 deletions
diff --git a/src/post/audio/Makefile.am b/src/post/audio/Makefile.am
index da2de7440..5268a1636 100644
--- a/src/post/audio/Makefile.am
+++ b/src/post/audio/Makefile.am
@@ -4,10 +4,10 @@ noinst_HEADERS = dsp.h filter.h window.h
libdir = $(XINE_PLUGINDIR)/post
-lib_LTLIBRARIES = xineplug_post_audio_filter_upmix.la
+lib_LTLIBRARIES = xineplug_post_audio_filters.la
-xineplug_post_audio_filter_upmix_la_SOURCES = \
- upmix.c filter.c window.c
-xineplug_post_audio_filter_upmix_la_LIBADD = $(XINE_LIB)
-xineplug_post_audio_filter_upmix_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ -lm
+xineplug_post_audio_filters_la_SOURCES = \
+ upmix.c filter.c window.c stretch.c audio_filters.c
+xineplug_post_audio_filters_la_LIBADD = $(XINE_LIB)
+xineplug_post_audio_filters_la_LDFLAGS = -avoid-version -module @XINE_PLUGIN_MIN_SYMS@ -lm
diff --git a/src/post/audio/audio_filters.c b/src/post/audio/audio_filters.c
new file mode 100644
index 000000000..23621e688
--- /dev/null
+++ b/src/post/audio/audio_filters.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2000-2004 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine 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 of the License, or
+ * (at your option) any later version.
+ *
+ * xine 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * $Id: audio_filters.c,v 1.1 2004/07/26 22:23:34 miguelfreitas Exp $
+ *
+ * catalog for audio filter plugins
+ */
+
+
+#include "xine_internal.h"
+#include "xineutils.h"
+#include "post.h"
+
+void *upmix_init_plugin(xine_t *xine, void *data);
+post_info_t upmix_special_info = { XINE_POST_TYPE_AUDIO_FILTER };
+
+void *stretch_init_plugin(xine_t *xine, void *data);
+post_info_t stretch_special_info = { XINE_POST_TYPE_AUDIO_FILTER };
+
+
+plugin_info_t xine_plugin_info[] = {
+ /* type, API, "name", version, special_info, init_function */
+ { PLUGIN_POST, 9, "upmix", XINE_VERSION_CODE, &upmix_special_info, &upmix_init_plugin },
+ { PLUGIN_POST, 9, "stretch", XINE_VERSION_CODE, &stretch_special_info, &stretch_init_plugin },
+ { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};
diff --git a/src/post/audio/stretch.c b/src/post/audio/stretch.c
new file mode 100644
index 000000000..f34172b72
--- /dev/null
+++ b/src/post/audio/stretch.c
@@ -0,0 +1,689 @@
+/*
+ * Copyright (C) 2000-2004 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine 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 of the License, or
+ * (at your option) any later version.
+ *
+ * xine 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Time stretch by a given factor, optionally preserving pitch
+ *
+ * $Id: stretch.c,v 1.1 2004/07/26 22:23:34 miguelfreitas Exp $
+ *
+ */
+
+#include <stdio.h>
+
+#include "xine_internal.h"
+#include "xineutils.h"
+#include "post.h"
+#include "dsp.h"
+#include "resample.h"
+
+
+#define AUDIO_FRAGMENT 120/1000 /* ms of audio */
+
+#define CLIP_INT16(s) ((s) < INT16_MIN) ? INT16_MIN : \
+ (((s) > INT16_MAX) ? INT16_MAX : (s))
+
+/*
+ * ***************************************************
+ * stretchable unix System Clock Reference
+ * use stretch factor to calculate speed
+ * ***************************************************
+ */
+
+struct stretchscr_s {
+ scr_plugin_t scr;
+
+ struct timeval cur_time;
+ int64_t cur_pts;
+ int xine_speed;
+ double speed_factor;
+ double *stretch_factor;
+
+ pthread_mutex_t lock;
+
+};
+
+typedef struct stretchscr_s stretchscr_t;
+
+static int stretchscr_get_priority (scr_plugin_t *scr) {
+ return 10; /* high priority */
+}
+
+/* Only call this when already mutex locked */
+static void stretchscr_set_pivot (stretchscr_t *this) {
+
+ struct timeval tv;
+ int64_t pts;
+ double pts_calc;
+
+ gettimeofday(&tv, NULL);
+ pts_calc = (tv.tv_sec - this->cur_time.tv_sec) * this->speed_factor;
+ pts_calc += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6;
+ pts = this->cur_pts + pts_calc;
+
+/* This next part introduces a one off inaccuracy
+ * to the scr due to rounding tv to pts.
+ */
+ this->cur_time.tv_sec=tv.tv_sec;
+ this->cur_time.tv_usec=tv.tv_usec;
+ this->cur_pts=pts;
+
+ return ;
+}
+
+static int stretchscr_set_speed (scr_plugin_t *scr, int speed) {
+ stretchscr_t *this = (stretchscr_t*) scr;
+
+ pthread_mutex_lock (&this->lock);
+
+ stretchscr_set_pivot( this );
+ this->xine_speed = speed;
+ this->speed_factor = (double) speed * 90000.0 / 4.0 /
+ (*this->stretch_factor);
+
+ pthread_mutex_unlock (&this->lock);
+
+ return speed;
+}
+
+static void stretchscr_adjust (scr_plugin_t *scr, int64_t vpts) {
+ stretchscr_t *this = (stretchscr_t*) scr;
+ struct timeval tv;
+
+ pthread_mutex_lock (&this->lock);
+
+ gettimeofday(&tv, NULL);
+ this->cur_time.tv_sec=tv.tv_sec;
+ this->cur_time.tv_usec=tv.tv_usec;
+ this->cur_pts = vpts;
+
+ pthread_mutex_unlock (&this->lock);
+}
+
+static void stretchscr_start (scr_plugin_t *scr, int64_t start_vpts) {
+ stretchscr_t *this = (stretchscr_t*) scr;
+
+ pthread_mutex_lock (&this->lock);
+
+ gettimeofday(&this->cur_time, NULL);
+ this->cur_pts = start_vpts;
+
+ pthread_mutex_unlock (&this->lock);
+
+ stretchscr_set_speed (&this->scr, XINE_SPEED_NORMAL);
+}
+
+static int64_t stretchscr_get_current (scr_plugin_t *scr) {
+ stretchscr_t *this = (stretchscr_t*) scr;
+
+ struct timeval tv;
+ int64_t pts;
+ double pts_calc;
+ pthread_mutex_lock (&this->lock);
+
+ gettimeofday(&tv, NULL);
+
+ pts_calc = (tv.tv_sec - this->cur_time.tv_sec) * this->speed_factor;
+ pts_calc += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6;
+
+ pts = this->cur_pts + pts_calc;
+
+ pthread_mutex_unlock (&this->lock);
+
+ return pts;
+}
+
+static void stretchscr_exit (scr_plugin_t *scr) {
+ stretchscr_t *this = (stretchscr_t*) scr;
+
+ pthread_mutex_destroy (&this->lock);
+ free(this);
+}
+
+static stretchscr_t* stretchscr_init (double *stretch_factor) {
+ stretchscr_t *this;
+
+ this = (stretchscr_t *) xine_xmalloc(sizeof(stretchscr_t));
+
+ this->scr.interface_version = 2;
+ this->scr.get_priority = stretchscr_get_priority;
+ this->scr.set_speed = stretchscr_set_speed;
+ this->scr.adjust = stretchscr_adjust;
+ this->scr.start = stretchscr_start;
+ this->scr.get_current = stretchscr_get_current;
+ this->scr.exit = stretchscr_exit;
+
+ pthread_mutex_init (&this->lock, NULL);
+
+ this->stretch_factor = stretch_factor;
+ stretchscr_set_speed (&this->scr, XINE_SPEED_PAUSE);
+
+ return this;
+}
+
+/*****************************************************/
+
+
+typedef struct post_plugin_stretch_s post_plugin_stretch_t;
+
+typedef struct post_class_stretch_s post_class_stretch_t;
+
+struct post_class_stretch_s {
+ post_class_t post_class;
+
+ xine_t *xine;
+};
+
+
+typedef struct stretch_parameters_s {
+ int preserve_pitch;
+ double factor;
+} stretch_parameters_t;
+
+/*
+ * description of params struct
+ */
+START_PARAM_DESCR( stretch_parameters_t )
+PARAM_ITEM( POST_PARAM_TYPE_BOOL, preserve_pitch, NULL, 0, 1, 0,
+ "Preserve pitch" )
+PARAM_ITEM( POST_PARAM_TYPE_DOUBLE, factor, NULL, 0.5, 1.5, 0,
+ "Time stretch factor (<1.0 shorten duration)" )
+END_PARAM_DESCR( param_descr )
+
+/* plugin structure */
+struct post_plugin_stretch_s {
+ post_plugin_t post;
+
+ stretchscr_t* scr;
+
+ /* private data */
+ stretch_parameters_t params;
+ xine_post_in_t params_input;
+ int params_changed;
+
+ int channels;
+ int bytes_per_frame;
+
+ void *audiofrag; /* audio fragment to work on */
+ void *outfrag; /* processed audio fragment */
+ _ftype_t *w;
+ int frames_per_frag;
+ int frames_per_outfrag;
+ int num_frames; /* current # of frames on audiofrag */
+
+ int64_t pts; /* pts for audiofrag */
+
+ pthread_mutex_t lock;
+};
+
+/**************************************************************************
+ * stretch parameters functions
+ *************************************************************************/
+static int set_parameters (xine_post_t *this_gen, void *param_gen) {
+ post_plugin_stretch_t *this = (post_plugin_stretch_t *)this_gen;
+ stretch_parameters_t *param = (stretch_parameters_t *)param_gen;
+
+ pthread_mutex_lock (&this->lock);
+ memcpy( &this->params, param, sizeof(stretch_parameters_t) );
+ this->params_changed = 1;
+ pthread_mutex_unlock (&this->lock);
+
+ return 1;
+}
+static int get_parameters (xine_post_t *this_gen, void *param_gen) {
+ post_plugin_stretch_t *this = (post_plugin_stretch_t *)this_gen;
+ stretch_parameters_t *param = (stretch_parameters_t *)param_gen;
+
+ pthread_mutex_lock (&this->lock);
+ memcpy( param, &this->params, sizeof(stretch_parameters_t) );
+ pthread_mutex_unlock (&this->lock);
+
+ return 1;
+}
+
+static xine_post_api_descr_t * get_param_descr (void) {
+ return &param_descr;
+}
+
+static char * get_help (void) {
+ return _("This filter will perform a time stretch, playing the "
+ "stream faster or slower by a factor. Pitch is optionally "
+ "preserved, so it is possible, for example, to use it to "
+ "watch a movie in less time than it was originaly shot.\n"
+ );
+}
+
+static xine_post_api_t post_api = {
+ set_parameters,
+ get_parameters,
+ get_param_descr,
+ get_help,
+};
+
+
+
+/**************************************************************************
+ * xine audio post plugin functions
+ *************************************************************************/
+
+static int stretch_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
+ uint32_t bits, uint32_t rate, int mode) {
+
+ post_audio_port_t *port = (post_audio_port_t *)port_gen;
+ post_plugin_stretch_t *this = (post_plugin_stretch_t *)port->post;
+ int64_t time;
+
+ _x_post_rewire(&this->post);
+ _x_post_inc_usage(port);
+
+ port->stream = stream;
+ port->bits = bits;
+ port->rate = rate;
+ port->mode = mode;
+
+ /* register our own scr provider */
+ time = port->stream->xine->clock->get_current_time(port->stream->xine->clock);
+ this->scr = stretchscr_init(&this->params.factor);
+ this->scr->scr.start(&this->scr->scr, time);
+ port->stream->xine->clock->register_scr(port->stream->xine->clock, &this->scr->scr);
+
+ /* force updating on stretch_port_put_buffer */
+ this->params_changed = 1;
+
+ return port->original_port->open(port->original_port, stream, bits, rate, mode);
+}
+
+static void stretch_port_close(xine_audio_port_t *port_gen, xine_stream_t *stream ) {
+
+ post_audio_port_t *port = (post_audio_port_t *)port_gen;
+ post_plugin_stretch_t *this = (post_plugin_stretch_t *)port->post;
+
+ if (this->scr) {
+ port->stream->xine->clock->unregister_scr(port->stream->xine->clock, &this->scr->scr);
+ this->scr->scr.exit(&this->scr->scr);
+ }
+
+ if(this->audiofrag) {
+ free(this->audiofrag);
+ this->audiofrag = NULL;
+ }
+
+ if(this->outfrag) {
+ free(this->outfrag);
+ this->outfrag = NULL;
+ }
+
+ if(this->w) {
+ free(this->w);
+ this->w = NULL;
+ }
+
+ port->stream = NULL;
+
+ port->original_port->close(port->original_port, stream );
+
+ _x_post_dec_usage(port);
+}
+
+static void stretch_process_fragment( post_audio_port_t *port,
+ xine_stream_t *stream, extra_info_t *extra_info )
+{
+ post_plugin_stretch_t *this = (post_plugin_stretch_t *)port->post;
+
+ audio_buffer_t *outbuf;
+ void *data_out = this->outfrag;
+ int num_frames_in = this->num_frames;
+ int num_frames_out = this->num_frames * this->frames_per_outfrag /
+ this->frames_per_frag;
+
+ if( !this->params.preserve_pitch ) {
+ if( this->channels == 2 )
+ _x_audio_out_resample_stereo(this->audiofrag, num_frames_in,
+ this->outfrag, num_frames_out);
+ else if( this->channels == 1 )
+ _x_audio_out_resample_mono(this->audiofrag, num_frames_in,
+ this->outfrag, num_frames_out);
+ } else {
+ if( num_frames_in > num_frames_out )
+ {
+ /*
+ * time compressing strategy
+ *
+ * input chunk has two halves, A and B.
+ * output chunk is composed as follow:
+ * - some frames copied directly from A
+ * - some frames copied from A merged with frames from B
+ * weighted by an increasing factor (0 -> 1.0)
+ * - frames from A weighted by a decreasing factor (1.0 -> 0)
+ * merged with frames copied from B
+ * - some frames copied directly from B
+ */
+
+ int merge_frames = num_frames_in - num_frames_out;
+ int copy_frames;
+ int16_t *src = this->audiofrag;
+ int16_t *dst = this->outfrag;
+ int i, j;
+
+ if( merge_frames > num_frames_out )
+ merge_frames = num_frames_out;
+ copy_frames = num_frames_out - merge_frames;
+
+ memcpy(dst, src, copy_frames/2 * this->bytes_per_frame);
+ dst += copy_frames/2 * this->channels;
+ src += copy_frames/2 * this->channels;
+
+ for( i = 0; i < merge_frames/2; i++ )
+ {
+ for( j = 0; j < this->channels; j++, src++, dst++ ) {
+
+ int32_t s = (int32_t) ((_ftype_t) src[0] +
+ src[merge_frames * this->channels] * this->w[i]);
+ *dst = CLIP_INT16(s);
+ }
+ }
+
+ for( ; i < merge_frames; i++ )
+ {
+ for( j = 0; j < this->channels; j++, src++, dst++ ) {
+
+ int32_t s = (int32_t) ((_ftype_t) src[0] * this->w[i] +
+ src[merge_frames * this->channels]);
+ *dst = CLIP_INT16(s);
+ }
+ }
+
+ src += merge_frames * this->channels;
+
+ memcpy(dst, src, (copy_frames - copy_frames/2) *
+ this->bytes_per_frame);
+
+ } else {
+ /*
+ * time expansion strategy
+ *
+ * output chunk is composed of two versions of the
+ * input chunk:
+ * - first part copied directly from input, and then
+ * merged with the second (delayed) part using a
+ * decreasing factor (1.0 -> 0)
+ * - the delayed version of the input is merged with
+ * an increasing factor (0 -> 1.0) and then (when
+ * factor reaches 1.0) just copied until the end.
+ */
+
+ int merge_frames = num_frames_out - num_frames_in;
+ int copy_frames = num_frames_out - merge_frames;
+ int16_t *src1 = this->audiofrag;
+ int16_t *src2;
+ int16_t *dst = this->outfrag;
+ int i, j;
+
+ memcpy(dst, src1, copy_frames/2 * this->bytes_per_frame);
+ dst += copy_frames/2 * this->channels;
+ src1 += copy_frames/2 * this->channels;
+ src2 = src1 - merge_frames * this->channels;
+
+ for( i = 0; i < merge_frames/2; i++ )
+ {
+ for( j = 0; j < this->channels; j++, src1++, src2++, dst++ ) {
+
+ int32_t s = (int32_t) ((_ftype_t) *src1 +
+ *src2 * this->w[i]);
+ *dst = CLIP_INT16(s);
+ }
+ }
+
+ for( ; i < merge_frames; i++ )
+ {
+ for( j = 0; j < this->channels; j++, src1++, src2++, dst++ ) {
+
+ int32_t s = (int32_t) ((_ftype_t) *src1 * this->w[i] +
+ *src2);
+ *dst = CLIP_INT16(s);
+ }
+ }
+
+ memcpy(dst, src2, (copy_frames - copy_frames/2) *
+ this->bytes_per_frame);
+
+ }
+ }
+
+ /* copy processed fragment into multiple audio buffers, if needed */
+ while( num_frames_out ) {
+ outbuf = port->original_port->get_buffer(port->original_port);
+
+ outbuf->num_frames = outbuf->mem_size / this->bytes_per_frame;
+ if( outbuf->num_frames > num_frames_out )
+ outbuf->num_frames = num_frames_out;
+
+ memcpy( outbuf->mem, data_out,
+ outbuf->num_frames * this->bytes_per_frame );
+ num_frames_out -= outbuf->num_frames;
+ data_out += outbuf->num_frames * this->bytes_per_frame;
+
+ outbuf->vpts = this->pts;
+ this->pts = 0;
+ outbuf->stream = stream;
+ outbuf->format.bits = port->bits;
+ outbuf->format.rate = port->rate;
+ outbuf->format.mode = port->mode;
+
+ _x_extra_info_merge( outbuf->extra_info, extra_info );
+
+ port->original_port->put_buffer(port->original_port, outbuf, stream );
+ }
+
+ this->num_frames = 0;
+}
+
+static void stretch_port_put_buffer (xine_audio_port_t *port_gen,
+ audio_buffer_t *buf, xine_stream_t *stream) {
+
+ post_audio_port_t *port = (post_audio_port_t *)port_gen;
+ post_plugin_stretch_t *this = (post_plugin_stretch_t *)port->post;
+ void *data_in;
+
+ pthread_mutex_lock (&this->lock);
+
+
+ if( this->params_changed ) {
+ int64_t audio_step;
+
+ if( this->num_frames && this->audiofrag && this->outfrag ) {
+ /* output whatever we have before changing parameters */
+ stretch_process_fragment( port, stream, buf->extra_info );
+ }
+
+ this->channels = _x_ao_mode2channels(port->mode);
+ this->bytes_per_frame = port->bits / 8 * this->channels;
+
+ audio_step = ((int64_t)90000 * (int64_t)32768) / (int64_t)port->rate;
+ audio_step = (int64_t) ((double)audio_step / this->params.factor);
+ stream->metronom->set_audio_rate(stream->metronom, audio_step);
+
+ stretchscr_set_speed(&this->scr->scr, this->scr->xine_speed);
+
+ if(this->audiofrag) {
+ free(this->audiofrag);
+ this->audiofrag = NULL;
+ }
+
+ if(this->outfrag) {
+ free(this->outfrag);
+ this->outfrag = NULL;
+ }
+
+ if(this->w) {
+ free(this->w);
+ this->w = NULL;
+ }
+
+ this->frames_per_frag = port->rate * AUDIO_FRAGMENT;
+ this->frames_per_outfrag = (int) ((double)this->params.factor * this->frames_per_frag);
+
+ if( this->frames_per_frag != this->frames_per_outfrag ) {
+ int wsize;
+
+ this->audiofrag = malloc( this->frames_per_frag * this->bytes_per_frame );
+ this->outfrag = malloc( this->frames_per_outfrag * this->bytes_per_frame );
+
+ if( this->frames_per_frag > this->frames_per_outfrag )
+ wsize = this->frames_per_frag - this->frames_per_outfrag;
+ else
+ wsize = this->frames_per_outfrag - this->frames_per_frag;
+
+ this->w = (_ftype_t*) malloc( wsize * sizeof(_ftype_t) );
+ triang(wsize, this->w);
+ }
+
+ this->num_frames = 0;
+ this->pts = 0;
+
+ this->params_changed = 0;
+ }
+
+ pthread_mutex_unlock (&this->lock);
+
+ /* just pass data through if we have nothing to do */
+ if( this->frames_per_frag == this->frames_per_outfrag ||
+ /* FIXME: we only handle 1 or 2 channels, 16 bits for now */
+ (this->channels != 1 && this->channels != 2) ||
+ port->bits != 16 ) {
+
+ port->original_port->put_buffer(port->original_port, buf, stream );
+
+ return;
+ }
+
+ /* update pts for our current audio fragment */
+ if( buf->vpts )
+ this->pts = buf->vpts - (this->num_frames * 90000 / port->rate);
+
+ data_in = buf->mem;
+ while( buf->num_frames ) {
+ int frames_to_copy = this->frames_per_frag - this->num_frames;
+
+ if( frames_to_copy > buf->num_frames )
+ frames_to_copy = buf->num_frames;
+
+ /* copy up to one fragment from input buf to our buffer */
+ memcpy( this->audiofrag + this->num_frames * this->bytes_per_frame,
+ data_in, frames_to_copy * this->bytes_per_frame );
+
+ data_in += frames_to_copy * this->bytes_per_frame;
+ this->num_frames += frames_to_copy;
+ buf->num_frames -= frames_to_copy;
+
+ /* check if we have a complete audio fragment to process */
+ if( this->num_frames == this->frames_per_frag ) {
+ stretch_process_fragment( port, stream, buf->extra_info );
+ }
+ }
+
+ 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 );
+
+ return;
+}
+
+static void stretch_dispose(post_plugin_t *this_gen)
+{
+ post_plugin_stretch_t *this = (post_plugin_stretch_t *)this_gen;
+
+ if (_x_post_dispose(this_gen)) {
+ free(this);
+ }
+}
+
+/* plugin class functions */
+static post_plugin_t *stretch_open_plugin(post_class_t *class_gen, int inputs,
+ xine_audio_port_t **audio_target,
+ xine_video_port_t **video_target)
+{
+ post_plugin_stretch_t *this = (post_plugin_stretch_t *)xine_xmalloc(sizeof(post_plugin_stretch_t));
+ post_in_t *input;
+ post_out_t *output;
+ xine_post_in_t *input_api;
+ post_audio_port_t *port;
+ stretch_parameters_t init_params;
+
+ if (!this || !audio_target || !audio_target[0] ) {
+ free(this);
+ return NULL;
+ }
+
+ _x_post_init(&this->post, 1, 0);
+
+ init_params.preserve_pitch = 1;
+ init_params.factor = 1.01;
+
+ pthread_mutex_init (&this->lock, NULL);
+
+ set_parameters ((xine_post_t *)&this->post, &init_params);
+
+ port = _x_post_intercept_audio_port(&this->post, audio_target[0], &input, &output);
+ port->new_port.open = stretch_port_open;
+ port->new_port.close = stretch_port_close;
+ port->new_port.put_buffer = stretch_port_put_buffer;
+
+ input_api = &this->params_input;
+ input_api->name = "parameters";
+ input_api->type = XINE_POST_DATA_PARAMETERS;
+ input_api->data = &post_api;
+ xine_list_append_content(this->post.input, input_api);
+
+ this->post.xine_post.audio_input[0] = &port->new_port;
+
+ this->post.dispose = stretch_dispose;
+
+ return &this->post;
+}
+
+static char *stretch_get_identifier(post_class_t *class_gen)
+{
+ return "stretch";
+}
+
+static char *stretch_get_description(post_class_t *class_gen)
+{
+ return "Time stretch by a given factor, optionally preserving pitch";
+}
+
+static void stretch_class_dispose(post_class_t *class_gen)
+{
+ free(class_gen);
+}
+
+/* plugin class initialization function */
+void *stretch_init_plugin(xine_t *xine, void *data)
+{
+ post_class_stretch_t *class = (post_class_stretch_t *)malloc(sizeof(post_class_stretch_t));
+
+ if (!class)
+ return NULL;
+
+ class->post_class.open_plugin = stretch_open_plugin;
+ class->post_class.get_identifier = stretch_get_identifier;
+ class->post_class.get_description = stretch_get_description;
+ class->post_class.dispose = stretch_class_dispose;
+
+ class->xine = xine;
+
+ return class;
+}
diff --git a/src/post/audio/upmix.c b/src/post/audio/upmix.c
index e08174995..2fb42a409 100644
--- a/src/post/audio/upmix.c
+++ b/src/post/audio/upmix.c
@@ -23,7 +23,7 @@
* It simply creates output channels to match the speaker arrangement.
* E.g. Converts Stereo into Surround 5.1
*
- * $Id: upmix.c,v 1.14 2004/05/29 14:45:25 mroi Exp $
+ * $Id: upmix.c,v 1.15 2004/07/26 22:23:34 miguelfreitas Exp $
*
*/
@@ -34,12 +34,6 @@
#include "post.h"
#include "dsp.h"
-#define FPS 20
-
-#define FOO_WIDTH 320
-#define FOO_HEIGHT 240
-
-#define NUMSAMPLES 512
typedef struct post_plugin_upmix_s post_plugin_upmix_t;
@@ -103,16 +97,10 @@ struct post_plugin_upmix_s {
pthread_mutex_t lock;
xine_post_in_t params_input;
upmix_parameters_t params;
- double ratio;
- 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;
- int sample_counter;
- int samples_per_frame;
-
};
/**************************************************************************
@@ -183,7 +171,6 @@ static int upmix_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
port->mode = mode;
capabilities = port->original_port->get_capabilities(port->original_port);
- this->ratio = (double)FOO_WIDTH/(double)FOO_HEIGHT;
this->channels = _x_ao_mode2channels(mode);
/* FIXME: Handle all desired output formats */
if ((capabilities & AO_CAP_MODE_5_1CHANNEL) && (capabilities & AO_CAP_FLOAT32)) {
@@ -212,8 +199,6 @@ static int upmix_port_open(xine_audio_port_t *port_gen, xine_stream_t *stream,
return 0;
}
- this->samples_per_frame = rate / FPS;
- this->data_idx = 0;
pthread_mutex_unlock (&this->lock);
return port->original_port->open(port->original_port, stream, bits, rate, mode );
@@ -446,7 +431,7 @@ static void upmix_class_dispose(post_class_t *class_gen)
}
/* plugin class initialization function */
-static void *upmix_init_plugin(xine_t *xine, void *data)
+void *upmix_init_plugin(xine_t *xine, void *data)
{
post_class_upmix_t *class = (post_class_upmix_t *)malloc(sizeof(post_class_upmix_t));
@@ -462,13 +447,3 @@ static void *upmix_init_plugin(xine_t *xine, void *data)
return class;
}
-
-/* plugin catalog information */
-/* post_info_t upmix_special_info = { XINE_POST_TYPE_AUDIO_VISUALIZATION }; */
-post_info_t upmix_special_info = { XINE_POST_TYPE_AUDIO_FILTER };
-
-plugin_info_t xine_plugin_info[] = {
- /* type, API, "name", version, special_info, init_function */
- { PLUGIN_POST, 9, "upmix", XINE_VERSION_CODE, &upmix_special_info, &upmix_init_plugin },
- { PLUGIN_NONE, 0, "", 0, NULL, NULL }
-};