You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
amarok/amarok/src/engine/xine/xine-scope.c

235 lines
7.0 KiB

/* Author: Max Howell <max.howell@methylblue.com>, (C) 2004
Copyright: See COPYING file that comes with this distribution
This has to be a c file or for some reason it won't link! (GCC 3.4.1)
*/
/* gcc doesn't like inline for me */
#define inline
/* need access to port_ticket */
#define XINE_ENGINE_INTERNAL
#include "xine-scope.h"
#include <xine/post.h>
#include <xine/xine_internal.h>
typedef struct scope_plugin_s scope_plugin_t;
struct scope_plugin_s
{
post_plugin_t post;
int64_t pts_per_smpls;
int channels;
MyNode *list;
};
/*************************
* post plugin functions *
*************************/
static int
scope_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;
scope_plugin_t *this = (scope_plugin_t*)port->post;
_x_post_rewire( (post_plugin_t*)port->post );
_x_post_inc_usage( port );
port->stream = stream;
port->bits = bits;
port->rate = rate;
port->mode = mode;
this->channels = _x_ao_mode2channels( mode );
int ret = port->original_port->open( port->original_port, stream, bits, rate, mode );
#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \
(XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10)
this->pts_per_smpls = ((uint32_t)90000 * (uint32_t)32768) / rate;
#else
this->pts_per_smpls = stream->metronom->pts_per_smpls;
#endif
return ret;
}
static void
scope_port_close( xine_audio_port_t *port_gen, xine_stream_t *stream )
{
post_audio_port_t *port = (post_audio_port_t *)port_gen;
scope_plugin_t *this = (scope_plugin_t*)port->post;
/* ensure the buffers are deleted during the next XineEngine::timerEvent() */
MyNode *node;
for( node = this->list->next; node != this->list; node = node->next )
{
node->vpts = node->vpts_end = -1;
}
port->stream = NULL;
port->original_port->close( port->original_port, stream );
_x_post_dec_usage( port );
}
static void
scope_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;
scope_plugin_t *this = (scope_plugin_t*)port->post;
/* FIXME With 8-bit samples the scope won't work correctly. For a special 8-bit code path,
the sample size could be checked like this: if( port->bits == 8 ) */
const int num_samples = buf->num_frames * this->channels;
MyNode *new_node;
new_node = malloc( sizeof(MyNode) );
#ifdef METRONOM_VPTS
new_node->vpts = stream->metronom->get_option(stream->metronom, METRONOM_VPTS);
#else
new_node->vpts = stream->metronom->got_audio_samples( stream->metronom, 0, 0 );
#endif
new_node->num_frames = buf->num_frames;
new_node->mem = malloc( num_samples * 2 );
memcpy( new_node->mem, buf->mem, num_samples * 2 );
{
int64_t
K = this->pts_per_smpls;
K *= num_samples;
K /= (1<<16);
K += new_node->vpts;
new_node->vpts_end = K;
}
port->original_port->put_buffer( port->original_port, buf, stream );
/* finally we should append the current buffer to the list
* this is thread-safe due to the way we handle the list in the GUI thread */
new_node->next = this->list->next;
this->list->next = new_node;
}
static void
scope_dispose( post_plugin_t *this )
{
MyNode *list = ((scope_plugin_t*)this)->list;
MyNode *prev;
MyNode *node = list;
/* Free all elements of the list (a ring buffer) */
do {
prev = node->next;
free( node->mem );
free( node );
node = prev;
}
while( node != list );
free( this );
}
/************************
* plugin init function *
************************/
#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \
(XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10)
static post_plugin_t* scope_plugin_new( post_class_t *class_gen, int inputs, xine_audio_port_t *audio_target[], xine_video_port_t *video_target[] )
#else
xine_post_t* scope_plugin_new( xine_t *xine, xine_audio_port_t *audio_target )
#endif
{
scope_plugin_t *scope_plugin = calloc( 1, sizeof(scope_plugin_t) );
post_plugin_t *post_plugin = (post_plugin_t*)scope_plugin;
{
post_in_t *input;
post_out_t *output;
post_audio_port_t *port;
_x_post_init( post_plugin, 1, 0 );
#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \
(XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10)
port = _x_post_intercept_audio_port( post_plugin, audio_target[0], &input, &output );
#else
port = _x_post_intercept_audio_port( post_plugin, audio_target, &input, &output );
#endif
port->new_port.open = scope_port_open;
port->new_port.close = scope_port_close;
port->new_port.put_buffer = scope_port_put_buffer;
post_plugin->xine_post.audio_input[0] = &port->new_port;
post_plugin->xine_post.type = PLUGIN_POST;
post_plugin->dispose = scope_dispose;
}
#if XINE_MAJOR_VERSION < 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION < 2) || \
(XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION < 10)
/* code is straight from xine_init_post()
can't use that function as it only dlopens the plugins
and our plugin is statically linked in */
post_plugin->running_ticket = xine->port_ticket;
post_plugin->xine = xine;
#endif
/* scope_plugin_t init */
scope_plugin->list = calloc( 1, sizeof(MyNode) );
scope_plugin->list->next = scope_plugin->list;
#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \
(XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10)
return post_plugin;
#else
return &post_plugin->xine_post;
#endif
}
MyNode* scope_plugin_list( void *post )
{
return ((scope_plugin_t*)post)->list;
}
int scope_plugin_channels( void *post )
{
return ((scope_plugin_t*)post)->channels;
}
int64_t scope_plugin_pts_per_smpls( void *post )
{
return ((scope_plugin_t*)post)->pts_per_smpls;
}
#if XINE_MAJOR_VERSION > 1 || (XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION > 2) || \
(XINE_MAJOR_VERSION == 1 && XINE_MINOR_VERSION == 2 && XINE_SUB_VERSION >= 10)
static void *scope_init_plugin(xine_t *xine, const void *data)
{
static const post_class_t post_scope_class = {
.open_plugin = scope_plugin_new,
.identifier = "amarok-scope",
.description = "Amarok Scope",
.dispose = NULL,
};
(void)xine;
(void)data;
return (void*)&post_scope_class;
}
static const post_info_t scope_special_info = {
.type = XINE_POST_TYPE_AUDIO_VISUALIZATION,
};
const plugin_info_t scope_plugin_info[] = {
{ PLUGIN_POST, 10, "amarok-scope", XINE_VERSION_CODE, &scope_special_info, scope_init_plugin },
{ PLUGIN_NONE, 0, NULL, 0, NULL, NULL }
};
#endif