/* Author: Max Howell , (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) */ /* need access to port_ticket */ #ifndef XINE_ENGINE_INTERNAL # define XINE_ENGINE_INTERNAL #endif #include "config.h" #include "xinescope.h" #include #include 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 = (MyNode *) 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 = (int16_t *) malloc(num_samples * 2); memcpy(new_node->mem, buf->mem, num_samples * 2); { int64_t K = 32768; /*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 *post) { MyNode *list = ((scope_plugin_t*)post)->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(post); } /************************ * plugin init function * ************************/ xine_post_t *scope_plugin_new(xine_t *xine, xine_audio_port_t *audio_target) { scope_plugin_t *scope_plugin = (scope_plugin_t *) 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 = (MyNode *) 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; }