187 lines
4.9 KiB
C
187 lines
4.9 KiB
C
/* 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;
|
|
|
|
metronom_t metronom;
|
|
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 )
|
|
{
|
|
#define port ((post_audio_port_t*)port_gen)
|
|
#define this ((scope_plugin_t*)((post_audio_port_t*)port_gen)->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 );
|
|
|
|
return port->original_port->open( port->original_port, stream, bits, rate, mode );
|
|
}
|
|
|
|
static void
|
|
scope_port_close( xine_audio_port_t *port_gen, xine_stream_t *stream )
|
|
{
|
|
MyNode *node;
|
|
|
|
/* ensure the buffers are deleted during the next XineEngine::timerEvent() */
|
|
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 )
|
|
{
|
|
/* 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;
|
|
metronom_t *myMetronom = &this->metronom;
|
|
MyNode *new_node;
|
|
|
|
/* I keep my own metronom because xine wouldn't for some reason */
|
|
memcpy( &this->metronom, stream->metronom, sizeof(metronom_t) );
|
|
|
|
new_node = malloc( sizeof(MyNode) );
|
|
new_node->vpts = myMetronom->got_audio_samples( myMetronom, buf->vpts, buf->num_frames );
|
|
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 = myMetronom->pts_per_smpls; /*smpls = 1<<16 samples*/
|
|
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;
|
|
|
|
#undef port
|
|
#undef this
|
|
}
|
|
|
|
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 *
|
|
************************/
|
|
|
|
xine_post_t*
|
|
scope_plugin_new( xine_t *xine, xine_audio_port_t *audio_target )
|
|
{
|
|
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 );
|
|
|
|
port = _x_post_intercept_audio_port( post_plugin, audio_target, &input, &output );
|
|
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;
|
|
}
|
|
|
|
/* 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;
|
|
|
|
/* scope_plugin_t init */
|
|
scope_plugin->list = calloc( 1, sizeof(MyNode) );
|
|
scope_plugin->list->next = scope_plugin->list;
|
|
|
|
return &post_plugin->xine_post;
|
|
}
|
|
|
|
MyNode*
|
|
scope_plugin_list( void *post )
|
|
{
|
|
return ((scope_plugin_t*)post)->list;
|
|
}
|
|
|
|
int
|
|
scope_plugin_channels( void *post )
|
|
{
|
|
return ((scope_plugin_t*)post)->channels;
|
|
}
|
|
|
|
metronom_t*
|
|
scope_plugin_metronom( void *post )
|
|
{
|
|
return &((scope_plugin_t*)post)->metronom;
|
|
}
|