diff options
-rw-r--r-- | gst/playondemand/.gitignore | 1 | ||||
-rw-r--r-- | gst/playondemand/demo-mp3.c | 139 | ||||
-rw-r--r-- | gst/playondemand/filter.func | 93 | ||||
-rw-r--r-- | gst/playondemand/gstplayondemand.c | 662 | ||||
-rw-r--r-- | gst/playondemand/gstplayondemand.h | 77 |
5 files changed, 456 insertions, 516 deletions
diff --git a/gst/playondemand/.gitignore b/gst/playondemand/.gitignore index 9c65c4cd..d0f3de02 100644 --- a/gst/playondemand/.gitignore +++ b/gst/playondemand/.gitignore @@ -1,2 +1 @@ -demo-mp3 demo_mp3 diff --git a/gst/playondemand/demo-mp3.c b/gst/playondemand/demo-mp3.c index 11fdd6c8..1c23805b 100644 --- a/gst/playondemand/demo-mp3.c +++ b/gst/playondemand/demo-mp3.c @@ -3,14 +3,25 @@ #include <gtk/gtk.h> #include <gst/gst.h> -#include "gstplayondemand.h" - -guint channels; -GtkWidget *window, *vbox, *play_button, *reset_button, *quit_button; -GtkWidget *hbox, *measure1_button, *measure2_button, *measure3_button, \ - *measure4_button, *measure5_button, *measure6_button, *speed_scale; +#define NUM_BEATS 16 +#define SPEED 1e-9 + +GtkWidget *window, *vbox, *beat_box, *button_box; +GtkWidget *play_button, *clear_button, *reset_button, *quit_button; +GtkWidget **beat_button; +GtkWidget *speed_scale; +GtkObject *speed_adj; GstElement *src, *mad, *pod, *osssink, *pipeline; GstClock *element_clock; +GSList *beats; + +void +played (GstElement *pod, gpointer data) +{ + g_print("Played beat at %u\n", + ((guint) (gst_clock_get_time(element_clock) * + (GTK_ADJUSTMENT(speed_adj))->value * SPEED)) % NUM_BEATS); +} void play (GtkButton *button, gpointer data) @@ -19,22 +30,35 @@ play (GtkButton *button, gpointer data) } void +clear (GtkButton *button, gpointer data) +{ + g_signal_emit_by_name(G_OBJECT(pod), "clear", NULL, NULL); +} + +void reset (GtkButton *button, gpointer data) { + guint i; g_signal_emit_by_name(G_OBJECT(pod), "reset", NULL, NULL); + for (i = 0; i < NUM_BEATS; i++) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(beat_button[i]), 0); } void -measure (GtkToggleButton *button, gpointer data) +beat (GtkToggleButton *button, gpointer data) { - gst_play_on_demand_toggle_beat(GST_PLAYONDEMAND(pod), - GPOINTER_TO_UINT(data), 0); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) + beats = g_slist_append(beats, data); + else + beats = g_slist_remove(beats, data); + g_object_set(G_OBJECT(pod), "tick-list", beats, NULL); } void -speed (GtkAdjustment *scale, gpointer data) +speed (GtkAdjustment *adjustment, gpointer data) { - gst_clock_set_speed(element_clock, gtk_adjustment_get_value(scale)); + g_object_set(G_OBJECT(pod), "clock-speed", adjustment->value * SPEED, NULL); + /*gst_clock_set_speed(element_clock, adjustment->value * SPEED);*/ } void @@ -46,9 +70,9 @@ setup_pipeline (gchar *filename) osssink = gst_element_factory_make("osssink", "osssink"); g_object_set(G_OBJECT(src), "location", filename, NULL); - g_object_set(G_OBJECT(pod), "silent", FALSE, NULL); g_object_set(G_OBJECT(osssink), "fragment", 0x00180008, NULL); - g_object_get(G_OBJECT(osssink), "channels", &channels, NULL); + g_object_set(G_OBJECT(pod), "total-ticks", NUM_BEATS, + "clock-speed", SPEED, NULL); pipeline = gst_pipeline_new("app"); @@ -57,69 +81,79 @@ setup_pipeline (gchar *filename) element_clock = gst_bin_get_clock(GST_BIN(pipeline)); gst_element_set_clock(GST_ELEMENT(pod), element_clock); - /* gst_clock_set_speed(element_clock, 0.00001); */ } void setup_gui (void) { + guint i; + + beat_button = g_new(GtkWidget *, NUM_BEATS); + /* initialize gui elements ... */ window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_set_border_width(GTK_CONTAINER(window), 12); + vbox = gtk_vbox_new(TRUE, 0); - hbox = gtk_hbox_new(TRUE, 0); - play_button = gtk_button_new_with_label("play"); - reset_button = gtk_button_new_with_label("reset"); - quit_button = gtk_button_new_with_label("quit"); - measure1_button = gtk_toggle_button_new_with_label("one"); - measure2_button = gtk_toggle_button_new_with_label("two"); - measure3_button = gtk_toggle_button_new_with_label("three"); - measure4_button = gtk_toggle_button_new_with_label("four"); - measure5_button = gtk_toggle_button_new_with_label("five"); - measure6_button = gtk_toggle_button_new_with_label("six"); - speed_scale = gtk_hscale_new_with_range(0.0, 0.001, 0.000001); - /* gtk_adjustment_set_value(GTK_ADJUSTMENT(speed_scale), 0.00001); */ + gtk_box_set_spacing(GTK_BOX(vbox), 12); + + beat_box = gtk_hbox_new(TRUE, 0); + button_box = gtk_hbox_new(TRUE, 0); + + play_button = gtk_button_new_with_label("Play"); + clear_button = gtk_button_new_with_label("Reset Sound"); + reset_button = gtk_button_new_with_label("Reset All"); + quit_button = gtk_button_new_with_label("Quit"); + + for (i = 0; i < NUM_BEATS; i++) + beat_button[i] = gtk_toggle_button_new_with_label(g_strdup_printf("%2d", i)); + + speed_adj = gtk_adjustment_new(1, 0.0, 2, 0.01, 0.1, 0.0); + speed_scale = gtk_hscale_new(GTK_ADJUSTMENT(speed_adj)); + gtk_scale_set_digits(GTK_SCALE(speed_scale), 4); + gtk_range_set_update_policy(GTK_RANGE(speed_scale), GTK_UPDATE_DISCONTINUOUS); /* do the packing stuff ... */ gtk_window_set_default_size(GTK_WINDOW(window), 96, 96); gtk_container_add(GTK_CONTAINER(window), vbox); - gtk_box_pack_start(GTK_BOX(vbox), play_button, TRUE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(vbox), reset_button, TRUE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, FALSE, 2); - gtk_box_pack_start(GTK_BOX(hbox), measure1_button, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(hbox), measure2_button, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(hbox), measure3_button, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(hbox), measure4_button, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(hbox), measure5_button, TRUE, TRUE, 2); - gtk_box_pack_start(GTK_BOX(hbox), measure6_button, TRUE, TRUE, 2); - /*gtk_box_pack_start(GTK_BOX(vbox), speed_scale, TRUE, FALSE, 2);*/ - gtk_box_pack_start(GTK_BOX(vbox), quit_button, TRUE, FALSE, 2); + + gtk_box_pack_start(GTK_BOX(button_box), play_button, TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX(button_box), clear_button, TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX(button_box), reset_button, TRUE, TRUE, 2); + gtk_box_pack_start(GTK_BOX(button_box), quit_button, TRUE, TRUE, 2); + + for (i = 0; i < NUM_BEATS; i++) + gtk_box_pack_start(GTK_BOX(beat_box), beat_button[i], TRUE, TRUE, 2); + + gtk_box_pack_start(GTK_BOX(vbox), button_box, TRUE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(vbox), beat_box, TRUE, FALSE, 2); + gtk_box_pack_start(GTK_BOX(vbox), speed_scale, TRUE, FALSE, 2); /* connect things ... */ g_signal_connect(G_OBJECT(play_button), "clicked", G_CALLBACK(play), NULL); + g_signal_connect(G_OBJECT(clear_button), "clicked", G_CALLBACK(clear), NULL); g_signal_connect(G_OBJECT(reset_button), "clicked", G_CALLBACK(reset), NULL); g_signal_connect(G_OBJECT(quit_button), "clicked", gtk_main_quit, NULL); - g_signal_connect(G_OBJECT(measure1_button), "toggled", G_CALLBACK(measure), GUINT_TO_POINTER(0)); - g_signal_connect(G_OBJECT(measure2_button), "toggled", G_CALLBACK(measure), GUINT_TO_POINTER(1)); - g_signal_connect(G_OBJECT(measure3_button), "toggled", G_CALLBACK(measure), GUINT_TO_POINTER(2)); - g_signal_connect(G_OBJECT(measure4_button), "toggled", G_CALLBACK(measure), GUINT_TO_POINTER(3)); - g_signal_connect(G_OBJECT(measure5_button), "toggled", G_CALLBACK(measure), GUINT_TO_POINTER(4)); - g_signal_connect(G_OBJECT(measure6_button), "toggled", G_CALLBACK(measure), GUINT_TO_POINTER(5)); - /*g_signal_connect(G_OBJECT(speed_scale), "value-changed", G_CALLBACK(speed), NULL);*/ + g_signal_connect(G_OBJECT(pod), "played", G_CALLBACK(played), NULL); + g_signal_connect(G_OBJECT(speed_adj), "value_changed", G_CALLBACK(speed), NULL); + for (i = 0; i < NUM_BEATS; i++) + g_signal_connect(G_OBJECT(beat_button[i]), "toggled", G_CALLBACK(beat), GUINT_TO_POINTER(i)); /* show the gui. */ gtk_widget_show(play_button); + gtk_widget_show(clear_button); gtk_widget_show(reset_button); gtk_widget_show(quit_button); - gtk_widget_show(measure1_button); - gtk_widget_show(measure2_button); - gtk_widget_show(measure3_button); - gtk_widget_show(measure4_button); - gtk_widget_show(measure5_button); - gtk_widget_show(measure6_button); - gtk_widget_show(hbox); - /*gtk_widget_show(speed_scale);*/ + + for (i = 0; i < NUM_BEATS; i++) + gtk_widget_show(beat_button[i]); + + gtk_widget_show(beat_box); + gtk_widget_show(button_box); + gtk_widget_show(speed_scale); gtk_widget_show(vbox); gtk_widget_show(window); + gtk_idle_add((GtkFunction)gst_bin_iterate, pipeline); } @@ -138,5 +172,6 @@ main(int argc, char **argv) gst_element_set_state(pipeline, GST_STATE_PLAYING); setup_gui(); gtk_main(); + g_free(beat_button); return 0; } diff --git a/gst/playondemand/filter.func b/gst/playondemand/filter.func index 2d77189f..038ad119 100644 --- a/gst/playondemand/filter.func +++ b/gst/playondemand/filter.func @@ -3,18 +3,19 @@ _TYPE_ *data_in, *data_out, *filter_data; filter_data = (_TYPE_ *) filter->buffer; -num_filter = filter->buffer_size / sizeof(_TYPE_); -max_filter = (filter->play_from_beginning) ? num_filter : G_MAXUINT; +num_filter = filter->buffer_bytes / sizeof(_TYPE_); /******************************************************************************/ /* see if we've got any events coming through ... */ do { - GST_DEBUG(0, "--- going to events"); - - while (! filter->eos && GST_IS_EVENT(in)) { + while (GST_IS_EVENT(in)) { if (GST_EVENT_TYPE(in) == GST_EVENT_EOS) { filter->eos = TRUE; + } else if ((GST_EVENT_TYPE(in) == GST_EVENT_SEEK) || + (GST_EVENT_TYPE(in) == GST_EVENT_FLUSH)) { + filter->eos = FALSE; + filter->write = 0; } else { gst_pad_push(filter->srcpad, in); } @@ -25,8 +26,6 @@ do { /****************************************************************************/ /* first handle data from the input buffer. */ - GST_DEBUG(0, "--- done with events, going to input"); - /* only update the input if there hasn't been an eos yet. */ if (! filter->eos) { data_in = (_TYPE_ *) GST_BUFFER_DATA(in); @@ -35,27 +34,13 @@ do { w = filter->write; /* copy the input data to the filter's internal buffer. */ - for (j = 0; (j < num_in) && ((w + j) < max_filter); j++) { + for (j = 0; (j < num_in) && ((w + j) < num_filter); j++) filter_data[(w + j) % num_filter] = data_in[j]; - } filter->write = (w + j) % num_filter; - if ((w + j) >= num_filter) { - filter->buffer_filled_once = TRUE; - - /* if we're not playing from the end of the stream, the buffer is not a - ring buffer, so it has a fixed size. we need to set eos here because - we've passed that limit. */ - if (filter->play_from_beginning) { - filter->eos = TRUE; - } - } - - /* update the start pointer */ - if ((! filter->play_from_beginning) && filter->buffer_filled_once) { - filter->start = (filter->write + 1) % num_filter; - } + if ((w + j) >= num_filter) + filter->eos = TRUE; out = in; } else { @@ -68,56 +53,58 @@ do { /****************************************************************************/ /* check to see if we have to add a new play pointer. */ - GST_DEBUG(0, "--- done with input, checking clock before output"); - - play_on_demand_update_plays_from_clock(filter); + if (filter->clock) { + current_tick = ((guint) (gst_clock_get_time(filter->clock) * + filter->clock_speed)) % filter->total_ticks; + + if (current_tick != last_tick) { + /* now we go through the tick list and play samples */ + tick_list = filter->tick_list; + while (tick_list) { + tick = GPOINTER_TO_UINT(tick_list->data); + if (current_tick == tick) + play_on_demand_add_play_pointer(filter, 0); + else if (GST_POD_TICK_ELAPSED(tick, current_tick, last_tick)) + play_on_demand_add_play_pointer(filter, GST_POD_SAMPLE_OFFSET(filter, current_tick - tick)); + tick_list = g_slist_next(tick_list); + } + last_tick = current_tick; + } + } /****************************************************************************/ /* now handle output data. */ - GST_DEBUG(0, "--- done with clock, going to output"); - data_out = (_TYPE_ *) GST_BUFFER_DATA(out); num_out = GST_BUFFER_SIZE(out) / sizeof(_TYPE_); - for (k = 0; k < num_out; k++) { + for (k = 0; k < num_out; k++) data_out[k] = zero; - } /* output play pointer data. */ - for (t = 0; t < GST_POD_MAX_PLAY_PTRS; t++) { - offset = filter->plays[t]; - - if (offset != G_MAXUINT) { - if (! filter->play_from_beginning) { - for (k = 0; k < num_out; k++) { - data_out[k] = CLAMP(data_out[k] + filter_data[(offset + k) % num_filter], min, max); - } - } else { - for (k = 0; (k < num_out) && (k < (w + j - offset)); k++) { + if (! filter->mute) + for (t = 0; t < filter->max_plays; t++) { + offset = filter->plays[t]; + + if (offset != G_MAXUINT) { + for (k = 0; (k < num_out) && (offset + k < num_filter); k++) data_out[k] = CLAMP(data_out[k] + filter_data[offset + k], min, max); - } - } - if ((! filter->play_from_beginning) || ((offset + k) < (w + j))) { - filter->plays[t] = (offset + k) % num_filter; - } else { - filter->plays[t] = G_MAXUINT; + if ((offset + k) == num_filter) + filter->plays[t] = G_MAXUINT; + else + filter->plays[t] = offset + k; } } - } /****************************************************************************/ /* push out the buffer. */ - GST_DEBUG(0, "--- done with output, pushing buffer %p", out); - gst_pad_push(filter->srcpad, out); - if (! filter->eos) { + if (! filter->eos) in = gst_pad_pull(filter->sinkpad); - } - gst_element_yield (GST_ELEMENT (filter)); + gst_element_interrupt (GST_ELEMENT (filter)); } while (TRUE); diff --git a/gst/playondemand/gstplayondemand.c b/gst/playondemand/gstplayondemand.c index 1784cb86..82375539 100644 --- a/gst/playondemand/gstplayondemand.c +++ b/gst/playondemand/gstplayondemand.c @@ -17,24 +17,25 @@ * Boston, MA 02111-1307, USA. */ + #include <string.h> #include <gst/gst.h> #include <gst/audio/audio.h> + #include "gstplayondemand.h" -#define GST_POD_MAX_PLAY_PTRS 128 /* maximum number of simultaneous plays */ -#define GST_POD_NUM_MEASURES 8 /* default number of measures */ -#define GST_POD_NUM_BEATS 16 /* default number of beats in a measure */ -#define GST_POD_BUFPOOL_SIZE 4096 /* gstreamer buffer size to use if no - bufferpool is available, must be divisible - by sizeof(gfloat) */ -#define GST_POD_BUFPOOL_NUM 6 /* number of buffers to allocate per chunk in - sink buffer pool */ -#define GST_POD_BUFFER_SIZE 882000 /* enough space for 5 seconds of 32-bit float - audio at 44100 samples per second ... */ +/* some default values */ +#define GST_POD_MAX_PLAYS 100 /* maximum simultaneous plays */ +#define GST_POD_BUFFER_TIME 5.0 /* buffer length in seconds */ +#define GST_POD_CLOCK_SPEED 1e-8 /* 0.1 sec/tick default */ + +/* buffer pool fallback values ... use if no buffer pool is available */ +#define GST_POD_BUFPOOL_SIZE 4096 +#define GST_POD_BUFPOOL_NUM 6 -/* elementfactory information */ + +/* element factory information */ static GstElementDetails play_on_demand_details = { "Play On Demand", "Filter/Audio/Effect", @@ -42,29 +43,10 @@ static GstElementDetails play_on_demand_details = { "Plays a stream at specific times, or when it receives a signal", VERSION, "Leif Morgan Johnson <leif@ambient.2y.net>", - "(C) 2001", + "(C) 2002", }; -/* Filter signals and args */ -enum { - /* FILL ME */ - PLAY_SIGNAL, - RESET_SIGNAL, - LAST_SIGNAL -}; - -static guint gst_pod_filter_signals[LAST_SIGNAL] = { 0 }; - -enum { - PROP_0, - PROP_SILENT, - PROP_PLAYFROMBEGINNING, - PROP_BUFFERSIZE, - PROP_NUM_BEATS, - PROP_NUM_MEASURES -}; - static GstPadTemplate* play_on_demand_sink_factory (void) { @@ -73,15 +55,16 @@ play_on_demand_sink_factory (void) if (!template) { template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - gst_caps_append(gst_caps_new ("sink_int", "audio/raw", - GST_AUDIO_INT_PAD_TEMPLATE_PROPS), - gst_caps_new ("sink_float", "audio/raw", - GST_AUDIO_FLOAT_MONO_PAD_TEMPLATE_PROPS)), - NULL); + gst_caps_append(gst_caps_new ("sink_int", "audio/raw", + GST_AUDIO_INT_PAD_TEMPLATE_PROPS), + gst_caps_new ("sink_float", "audio/raw", + GST_AUDIO_FLOAT_MONO_PAD_TEMPLATE_PROPS)), + NULL); } return template; } + static GstPadTemplate* play_on_demand_src_factory (void) { @@ -99,97 +82,27 @@ play_on_demand_src_factory (void) return template; } + +/* GObject functionality */ static void play_on_demand_class_init (GstPlayOnDemandClass *klass); static void play_on_demand_init (GstPlayOnDemand *filter); +static void play_on_demand_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void play_on_demand_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -static void play_on_demand_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void play_on_demand_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - -static GstPadLinkReturn play_on_demand_pad_connect (GstPad *pad, GstCaps *caps); - -static void play_on_demand_loop (GstElement *elem); - -static void play_on_demand_set_clock (GstElement *elem, GstClock *clock); +/* GStreamer functionality */ +static GstBufferPool* play_on_demand_get_bufferpool (GstPad *pad); +static GstPadLinkReturn play_on_demand_pad_link (GstPad *pad, GstCaps *caps); +static void play_on_demand_loop (GstElement *elem); +static void play_on_demand_set_clock (GstElement *elem, GstClock *clock); +/* signal handlers */ static void play_on_demand_play_handler (GstElement *elem); -static void play_on_demand_add_play_ptr (GstPlayOnDemand *filter, guint pos); +static void play_on_demand_clear_handler (GstElement *elem); static void play_on_demand_reset_handler (GstElement *elem); -static void play_on_demand_update_plays_from_clock (GstPlayOnDemand *filter); - -static GstElementClass *parent_class = NULL; - -static GstBufferPool* -play_on_demand_get_bufferpool (GstPad *pad) -{ - GstPlayOnDemand *filter; - - filter = GST_PLAYONDEMAND(gst_pad_get_parent(pad)); - - return gst_pad_get_bufferpool(filter->srcpad); -} - -static GstPadLinkReturn -play_on_demand_pad_connect (GstPad *pad, GstCaps *caps) -{ - const gchar *format; - GstPlayOnDemand *filter; - - g_return_val_if_fail(caps != NULL, GST_PAD_LINK_DELAYED); - g_return_val_if_fail(pad != NULL, GST_PAD_LINK_DELAYED); - - filter = GST_PLAYONDEMAND(GST_PAD_PARENT(pad)); - - gst_caps_get_string(caps, "format", &format); - - gst_caps_get_int(caps, "rate", &filter->rate); - gst_caps_get_int(caps, "channels", &filter->channels); - - if (strcmp(format, "int") == 0) { - filter->format = GST_PLAYONDEMAND_FORMAT_INT; - gst_caps_get_int (caps, "width", &filter->width); - gst_caps_get_int (caps, "depth", &filter->depth); - gst_caps_get_int (caps, "law", &filter->law); - gst_caps_get_int (caps, "endianness", &filter->endianness); - gst_caps_get_boolean (caps, "signed", &filter->is_signed); - - if (!filter->silent) { - g_print ("PlayOnDemand : channels %d, rate %d\n", - filter->channels, filter->rate); - g_print ("PlayOnDemand : format int, bit width %d, endianness %d, signed %s\n", - filter->width, filter->endianness, filter->is_signed ? "yes" : "no"); - } - - filter->buffer_samples = filter->buffer_size; - filter->buffer_samples /= (filter->width) ? filter->width / 8 : 1; - filter->buffer_samples /= (filter->channels) ? filter->channels : 1; -} else if (strcmp(format, "float") == 0) { - filter->format = GST_PLAYONDEMAND_FORMAT_FLOAT; - gst_caps_get_string (caps, "layout", &filter->layout); - gst_caps_get_float (caps, "intercept", &filter->intercept); - gst_caps_get_float (caps, "slope", &filter->slope); - - if (!filter->silent) { - g_print ("PlayOnDemand : channels %d, rate %d\n", - filter->channels, filter->rate); - g_print ("PlayOnDemand : format float, layout %s, intercept %f, slope %f\n", - filter->layout, filter->intercept, filter->slope); - } - - filter->buffer_samples = filter->buffer_size / sizeof(gfloat); - filter->buffer_samples /= (filter->channels) ? filter->channels : 1; - } - - if (GST_CAPS_IS_FIXED (caps)) - return gst_pad_try_set_caps (filter->srcpad, caps); - return GST_PAD_LINK_DELAYED; -} +/* utility functions */ +static void play_on_demand_add_play_pointer (GstPlayOnDemand *filter, guint pos); +static void play_on_demand_resize_buffer (GstPlayOnDemand *filter); GType gst_play_on_demand_get_type (void) @@ -215,6 +128,31 @@ gst_play_on_demand_get_type (void) return play_on_demand_type; } + +/* signals and properties */ +enum { + /* add signals here */ + PLAYED_SIGNAL, + PLAY_SIGNAL, + CLEAR_SIGNAL, + RESET_SIGNAL, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_MUTE, + PROP_BUFFER_TIME, + PROP_MAX_PLAYS, + PROP_CLOCK_SPEED, + PROP_TOTAL_TICKS, + PROP_TICK_LIST, +}; + +static guint gst_pod_filter_signals[LAST_SIGNAL] = { 0 }; + +static GstElementClass *parent_class = NULL; + static void play_on_demand_class_init (GstPlayOnDemandClass *klass) { @@ -224,6 +162,15 @@ play_on_demand_class_init (GstPlayOnDemandClass *klass) gobject_class = (GObjectClass *) klass; gstelement_class = (GstElementClass *) klass; + gst_pod_filter_signals[PLAYED_SIGNAL] = + g_signal_new("played", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GstPlayOnDemandClass, played), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + gst_pod_filter_signals[PLAY_SIGNAL] = g_signal_new("play", G_TYPE_FROM_CLASS(klass), @@ -233,6 +180,15 @@ play_on_demand_class_init (GstPlayOnDemandClass *klass) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + gst_pod_filter_signals[CLEAR_SIGNAL] = + g_signal_new("clear", + G_TYPE_FROM_CLASS(klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(GstPlayOnDemandClass, clear), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + gst_pod_filter_signals[RESET_SIGNAL] = g_signal_new("reset", G_TYPE_FROM_CLASS(klass), @@ -243,34 +199,45 @@ play_on_demand_class_init (GstPlayOnDemandClass *klass) G_TYPE_NONE, 0); klass->play = play_on_demand_play_handler; + klass->clear = play_on_demand_clear_handler; klass->reset = play_on_demand_reset_handler; parent_class = g_type_class_ref(GST_TYPE_ELEMENT); - g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_SILENT, - g_param_spec_boolean("silent","silent","silent", - TRUE, G_PARAM_READWRITE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_PLAYFROMBEGINNING, - g_param_spec_boolean("play-from-beginning","play-from-beginning","play-from-beginning", - TRUE, G_PARAM_READWRITE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_BUFFERSIZE, - g_param_spec_uint("buffer-size","buffer-size","buffer-size", - 0, G_MAXUINT - 1, GST_POD_BUFFER_SIZE, G_PARAM_READWRITE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_NUM_BEATS, - g_param_spec_uint("num-beats","num-beats","num-beats", - 0, G_MAXUINT - 1, GST_POD_NUM_BEATS, G_PARAM_READWRITE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_NUM_MEASURES, - g_param_spec_uint("num-measures","num-measures","num-measures", - 0, G_MAXUINT - 1, GST_POD_NUM_MEASURES, G_PARAM_READWRITE)); - gobject_class->set_property = play_on_demand_set_property; gobject_class->get_property = play_on_demand_get_property; gstelement_class->set_clock = play_on_demand_set_clock; + + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_MUTE, + g_param_spec_boolean("mute", "Silence output", + "Do not output any sound", + FALSE, G_PARAM_READWRITE)); + + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_BUFFER_TIME, + g_param_spec_float("buffer-time", "Buffer length in seconds", + "Number of seconds of audio the buffer holds", + 0.0, G_MAXUINT - 2, GST_POD_BUFFER_TIME, G_PARAM_READWRITE)); + + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_MAX_PLAYS, + g_param_spec_uint("plays", "Maximum simultaneous playback", + "Maximum allowed number of simultaneous plays from the buffer", + 1, G_MAXUINT, GST_POD_MAX_PLAYS, G_PARAM_READWRITE)); + + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_CLOCK_SPEED, + g_param_spec_float("clock-speed", "Clock speed (ticks/second)", + "The relative speed of a musical tick", + 0, G_MAXFLOAT, 1, G_PARAM_READWRITE)); + + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_TOTAL_TICKS, + g_param_spec_uint("total-ticks", "Total number of ticks", + "Total number of ticks (only relevant for tick lists)", + 1, G_MAXUINT, 1, G_PARAM_READWRITE)); + + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_TICK_LIST, + g_param_spec_pointer("tick-list", "List of ticks to play", + "A list of ticks (musical times) at which to play the sample", + G_PARAM_READWRITE)); } static void @@ -282,51 +249,184 @@ play_on_demand_init (GstPlayOnDemand *filter) filter->sinkpad = gst_pad_new_from_template(play_on_demand_sink_factory(), "sink"); gst_pad_set_bufferpool_function(filter->sinkpad, play_on_demand_get_bufferpool); - gst_pad_set_link_function(filter->sinkpad, play_on_demand_pad_connect); + gst_pad_set_link_function(filter->sinkpad, play_on_demand_pad_link); gst_element_add_pad(GST_ELEMENT(filter), filter->sinkpad); gst_element_add_pad(GST_ELEMENT(filter), filter->srcpad); gst_element_set_loop_function(GST_ELEMENT(filter), play_on_demand_loop); - filter->buffer = g_new(gchar, GST_POD_BUFFER_SIZE); - filter->buffer_size = GST_POD_BUFFER_SIZE; - filter->start = 0; - filter->write = 0; + filter->clock = NULL; + + /* filter properties */ + filter->mute = FALSE; + filter->buffer_time = GST_POD_BUFFER_TIME; + filter->max_plays = GST_POD_MAX_PLAYS; + filter->clock_speed = GST_POD_CLOCK_SPEED; + filter->total_ticks = 1; + filter->tick_list = NULL; + /* internal buffer stuff */ + play_on_demand_resize_buffer(filter); filter->eos = FALSE; - filter->buffer_filled_once = FALSE; - filter->play_from_beginning = TRUE; - filter->silent = TRUE; - - filter->clock = NULL; - filter->last_time = 0; - - filter->num_beats = GST_POD_NUM_BEATS; - filter->num_measures = GST_POD_NUM_MEASURES; - filter->total_beats = filter->num_beats * filter->num_measures; - filter->times = g_new(guint64, filter->num_measures); - for (i = 0; i < filter->num_measures; i++) { - filter->times[i] = 0; - } - /* the plays are stored as an array of buffer offsets. this initializes the - array to `blank' values (G_MAXUINT is the `invalid' index). */ - filter->plays = g_new(guint, GST_POD_MAX_PLAY_PTRS); - for (i = 0; i < GST_POD_MAX_PLAY_PTRS; i++) { + /* play pointers, stored as an array of buffer offsets */ + filter->write = 0; + filter->plays = g_new(guint, filter->max_plays); + for (i = 0; i < filter->max_plays; i++) filter->plays[i] = G_MAXUINT; +} + +static void +play_on_demand_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + GstPlayOnDemand *filter; + register guint i; + guint new_size, min_size, *new_plays; + + g_return_if_fail(GST_IS_PLAYONDEMAND(object)); + filter = GST_PLAYONDEMAND(object); + + switch (prop_id) { + case PROP_MUTE: + filter->mute = g_value_get_boolean(value); + break; + case PROP_BUFFER_TIME: + filter->buffer_time = g_value_get_float(value); + play_on_demand_resize_buffer(filter); + + /* clear out now-invalid play pointers, if there are any. */ + for (i = 0; i < filter->max_plays; i++) + if (filter->plays[i] > filter->buffer_bytes) + filter->plays[i] = G_MAXUINT; + + break; + case PROP_MAX_PLAYS: + new_size = g_value_get_uint(value); + min_size = (new_size < filter->max_plays) ? new_size : filter->max_plays; + + new_plays = g_new(guint, new_size); + for (i = 0; i < min_size; i++) new_plays[i] = filter->plays[i]; + for (i = min_size; i < filter->max_plays; i++) new_plays[i] = G_MAXUINT; + + g_free(filter->plays); + filter->plays = new_plays; + filter->max_plays = new_size; + + break; + case PROP_CLOCK_SPEED: + filter->clock_speed = g_value_get_float(value); + break; + case PROP_TOTAL_TICKS: + filter->total_ticks = g_value_get_uint(value); + break; + case PROP_TICK_LIST: + filter->tick_list = (GSList *) g_value_get_pointer(value); + break; + default: + break; } } static void +play_on_demand_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + GstPlayOnDemand *filter; + + g_return_if_fail(GST_IS_PLAYONDEMAND(object)); + filter = GST_PLAYONDEMAND(object); + + switch (prop_id) { + case PROP_MUTE: + g_value_set_boolean(value, filter->mute); + break; + case PROP_BUFFER_TIME: + g_value_set_float(value, filter->buffer_time); + break; + case PROP_MAX_PLAYS: + g_value_set_uint(value, filter->max_plays); + break; + case PROP_CLOCK_SPEED: + g_value_set_float(value, filter->clock_speed); + break; + case PROP_TOTAL_TICKS: + g_value_set_uint(value, filter->total_ticks); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static GstBufferPool* +play_on_demand_get_bufferpool (GstPad *pad) +{ + GstPlayOnDemand *filter; + filter = GST_PLAYONDEMAND(gst_pad_get_parent(pad)); + return gst_pad_get_bufferpool(filter->srcpad); +} + +static GstPadLinkReturn +play_on_demand_pad_link (GstPad *pad, GstCaps *caps) +{ + const gchar *format; + GstPlayOnDemand *filter; + + g_return_val_if_fail(caps != NULL, GST_PAD_LINK_DELAYED); + g_return_val_if_fail(pad != NULL, GST_PAD_LINK_DELAYED); + + filter = GST_PLAYONDEMAND(GST_PAD_PARENT(pad)); + + gst_caps_get_string(caps, "format", &format); + gst_caps_get_int(caps, "rate", &filter->rate); + gst_caps_get_int(caps, "channels", &filter->channels); + + if (strcmp(format, "int") == 0) { + filter->format = GST_PLAYONDEMAND_FORMAT_INT; + gst_caps_get_int (caps, "width", &filter->width); + } else if (strcmp(format, "float") == 0) { + filter->format = GST_PLAYONDEMAND_FORMAT_FLOAT; + } + + play_on_demand_resize_buffer(filter); + + if (GST_CAPS_IS_FIXED (caps)) + return gst_pad_try_set_caps (filter->srcpad, caps); + return GST_PAD_LINK_DELAYED; +} + +/* clock check macros. in these macros, + f == filter + t == tick in question + c == current tick (from the clock) + l == last tick (last tick when clock was checked) + dt == ticks between c and t */ +#define GST_POD_SAMPLE_OFFSET(f, dt) \ + ((guint) (dt * (f)->rate / (f)->clock_speed)) + +/* play a sample if the tick in question came between the last time we checked + the clock and the current clock time. only looks complicated because the last + clock time could have been at the end of the total_ticks, so the clock might + have wrapped around ... */ +#define GST_POD_TICK_ELAPSED(t, c, l) \ + (((l < c) && (l < t) && (t < c)) || ((l > c) && ((l < t) || (t < c)))) + +static void play_on_demand_loop (GstElement *elem) { GstPlayOnDemand *filter = GST_PLAYONDEMAND(elem); - guint num_in, num_out, num_filter, max_filter; + guint num_in, num_out, num_filter; GstBuffer *in, *out; register guint j, k, t; guint w, offset; + /* variables for clock check. */ + static guint last_tick = 0; + GSList *tick_list; + guint tick, current_tick; + g_return_if_fail(filter != NULL); g_return_if_fail(GST_IS_PLAYONDEMAND(filter)); @@ -369,9 +469,10 @@ static void play_on_demand_set_clock (GstElement *elem, GstClock *clock) { GstPlayOnDemand *filter; + + g_return_if_fail(elem != NULL); g_return_if_fail(GST_IS_PLAYONDEMAND(elem)); filter = GST_PLAYONDEMAND(elem); - g_return_if_fail(filter != NULL); filter->clock = clock; } @@ -381,233 +482,86 @@ play_on_demand_play_handler (GstElement *elem) { GstPlayOnDemand *filter; + g_return_if_fail(elem != NULL); g_return_if_fail(GST_IS_PLAYONDEMAND(elem)); filter = GST_PLAYONDEMAND(elem); - g_return_if_fail(filter != NULL); - play_on_demand_add_play_ptr(filter, filter->start); + play_on_demand_add_play_pointer(filter, 0); } static void -play_on_demand_add_play_ptr (GstPlayOnDemand *filter, guint pos) +play_on_demand_clear_handler (GstElement *elem) { - register guint i; + GstPlayOnDemand *filter; - for (i = 0; i < GST_POD_MAX_PLAY_PTRS; i++) { - if (filter->plays[i] == G_MAXUINT) { - filter->plays[i] = pos; - return; - } - } + g_return_if_fail(elem != NULL); + g_return_if_fail(GST_IS_PLAYONDEMAND(elem)); + filter = GST_PLAYONDEMAND(elem); + + filter->write = 0; + filter->eos = FALSE; } static void -play_on_demand_reset_handler(GstElement *elem) +play_on_demand_reset_handler (GstElement *elem) { GstPlayOnDemand *filter; register guint i; + g_return_if_fail(elem != NULL); g_return_if_fail(GST_IS_PLAYONDEMAND(elem)); filter = GST_PLAYONDEMAND(elem); - g_return_if_fail(filter != NULL); - for (i = 0; i < GST_POD_MAX_PLAY_PTRS; i++) { + for (i = 0; i < filter->max_plays; i++) { filter->plays[i] = G_MAXUINT; } - filter->start = 0; filter->write = 0; filter->eos = FALSE; - filter->buffer_filled_once = FALSE; - - for (i = 0; i < filter->num_measures; i++) { - filter->times[i] = 0; - } } -#define GST_POD_SAMPLE_OFFSET(f, dt) (((f)->start - ((dt) / (f)->rate)) % (f)->buffer_samples) - static void -play_on_demand_update_plays_from_clock(GstPlayOnDemand *filter) +play_on_demand_add_play_pointer (GstPlayOnDemand *filter, guint pos) { - register guint t; - guint total, beats, last, time; - - g_return_if_fail(GST_IS_PLAYONDEMAND(filter)); - g_return_if_fail(filter != NULL); - - if (filter->clock) { - total = filter->total_beats; - beats = filter->num_beats; - - last = filter->last_time; - time = (guint) ((gst_clock_get_time(filter->clock) / 10000000LL) % total); - filter->last_time = time; - - GST_DEBUG(0, "--- clock time %u, last %u, total %u", time, last, total); - - /* if the current time is less than the last time, the clock has wrapped - around the total number of beats ... we need to count back to 0 and then - wrap around to the end. */ - if (time < last) { - for (t = time; t != G_MAXUINT; t--) { - if (filter->times[t / beats] & ((guint64) 1 << (t % beats))) { - play_on_demand_add_play_ptr(filter, - GST_POD_SAMPLE_OFFSET(filter, time - t)); - } - } - - time = total - 1; - } + register guint i; - for (t = time; t > last; t--) { - if (filter->times[t / beats] & ((guint64) 1 << (t % beats))) { - play_on_demand_add_play_ptr(filter, - GST_POD_SAMPLE_OFFSET(filter, time - t)); + if (filter->rate && ((filter->buffer_time * filter->rate) > pos)) + for (i = 0; i < filter->max_plays; i++) + if (filter->plays[i] == G_MAXUINT) { + filter->plays[i] = pos; + /* emit a signal to indicate a sample being played */ + g_signal_emit(filter, gst_pod_filter_signals[PLAYED_SIGNAL], 0); + return; } - } - } -} - -void -gst_play_on_demand_set_beat(GstPlayOnDemand *filter, const guint measure, - const guint beat, const gboolean value) -{ - g_return_if_fail(GST_IS_PLAYONDEMAND(filter)); - g_return_if_fail(filter != NULL); - g_return_if_fail(filter->num_measures > measure); - g_return_if_fail(filter->total_beats < (filter->num_beats * measure + beat)); - - if (value) { - filter->times[measure] |= (1 << beat); - } else { - filter->times[measure] &= (((guint64) -1) ^ (1 << beat)); - } -} - -gboolean -gst_play_on_demand_get_beat(GstPlayOnDemand *filter, const guint measure, - const guint beat) -{ - g_return_val_if_fail(GST_IS_PLAYONDEMAND(filter), FALSE); - g_return_val_if_fail(filter != NULL, FALSE); - g_return_val_if_fail(filter->num_measures > measure, FALSE); - g_return_val_if_fail(filter->total_beats > - (filter->num_beats * measure + beat), FALSE); - - return ((filter->times[measure] >> beat) & ((guint64) 1)); -} - -void -gst_play_on_demand_toggle_beat(GstPlayOnDemand *filter, const guint measure, - const guint beat) -{ - g_return_if_fail(GST_IS_PLAYONDEMAND(filter)); - g_return_if_fail(filter != NULL); - g_return_if_fail(filter->num_measures > measure); - g_return_if_fail(filter->total_beats > (filter->num_beats * measure + beat)); - - filter->times[measure] ^= (1 << beat); } static void -play_on_demand_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) +play_on_demand_resize_buffer (GstPlayOnDemand *filter) { - GstPlayOnDemand *filter; - register guchar c; register guint i; + guint new_size, min_size; gchar *new_buffer; - guint64 *new_measures; - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail(GST_IS_PLAYONDEMAND(object)); - filter = GST_PLAYONDEMAND(object); - g_return_if_fail(filter != NULL); + /* use a default sample rate of 44100, 1 channel, 1 byte per sample if caps + haven't been set yet */ + new_size = (guint) filter->buffer_time; + new_size *= (filter->rate) ? filter->rate : 44100; + new_size *= (filter->channels) ? filter->channels : 1; - switch (prop_id) { - case PROP_BUFFERSIZE: - filter->buffer_size = g_value_get_uint(value); - - if (filter->format == GST_PLAYONDEMAND_FORMAT_FLOAT) { - filter->buffer_samples = filter->buffer_size \ - / sizeof(gfloat) / filter->channels; - } else { - filter->buffer_samples = filter->buffer_size \ - / filter->width / filter->channels; - } + if (filter->format && filter->format == GST_PLAYONDEMAND_FORMAT_FLOAT) + new_size *= sizeof(gfloat); + else + new_size *= (filter->width) ? filter->width / 8 : 1; - /* allocate space for a new buffer, copy old data, remove invalid play - pointers. */ - new_buffer = g_new(gchar, filter->buffer_size); - for (c = 0; c < filter->buffer_size; c++) { - new_buffer[c] = filter->buffer[c]; - } + min_size = (new_size < filter->buffer_bytes) ? new_size : filter->buffer_bytes; - g_free(filter->buffer); - filter->buffer = new_buffer; + new_buffer = g_new(gchar, new_size); + for (i = 0; i < min_size; i++) new_buffer[i] = filter->buffer[i]; + for (i = min_size; i < filter->buffer_bytes; i++) new_buffer[i] = 0; - for (i = 0; i < GST_POD_MAX_PLAY_PTRS; i++) { - if (filter->plays[i] > filter->buffer_size) { - filter->plays[i] = G_MAXUINT; - } - } - break; - case PROP_NUM_BEATS: - filter->num_beats = g_value_get_uint(value); - filter->total_beats = filter->num_measures * filter->num_beats; - break; - case PROP_NUM_MEASURES: - filter->num_measures = g_value_get_uint(value); - filter->total_beats = filter->num_measures * filter->num_beats; - - /* reallocate space for beat information, copy old data. this will remove - measures at the end if the number of measures shrinks. */ - new_measures = g_new(guint64, filter->num_measures); - for (i = 0; i < filter->num_measures; i++) { - new_measures[i] = filter->times[i]; - } - - g_free(filter->times); - filter->times = new_measures; - break; - case PROP_SILENT: - filter->silent = g_value_get_boolean(value); - break; - case PROP_PLAYFROMBEGINNING: - filter->play_from_beginning = g_value_get_boolean(value); - play_on_demand_reset_handler(GST_ELEMENT(filter)); - break; - default: - break; - } -} - -static void -play_on_demand_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - GstPlayOnDemand *filter; - - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail(GST_IS_PLAYONDEMAND(object)); - filter = GST_PLAYONDEMAND(object); - g_return_if_fail(filter != NULL); - - switch (prop_id) { - case PROP_BUFFERSIZE: - g_value_set_uint(value, filter->buffer_size); - break; - case PROP_SILENT: - g_value_set_boolean(value, filter->silent); - break; - case PROP_PLAYFROMBEGINNING: - g_value_set_boolean(value, filter->play_from_beginning); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } + g_free(filter->buffer); + filter->buffer = new_buffer; + filter->buffer_bytes = new_size; } static gboolean @@ -616,8 +570,8 @@ plugin_init (GModule *module, GstPlugin *plugin) GstElementFactory *factory; factory = gst_element_factory_new("playondemand", - GST_TYPE_PLAYONDEMAND, - &play_on_demand_details); + GST_TYPE_PLAYONDEMAND, + &play_on_demand_details); g_return_val_if_fail(factory != NULL, FALSE); gst_element_factory_add_pad_template(factory, play_on_demand_src_factory()); diff --git a/gst/playondemand/gstplayondemand.h b/gst/playondemand/gstplayondemand.h index d34c0c6f..b48d6c8a 100644 --- a/gst/playondemand/gstplayondemand.h +++ b/gst/playondemand/gstplayondemand.h @@ -55,80 +55,45 @@ enum _GstPlayOnDemandFormat { struct _GstPlayOnDemand { GstElement element; - GstPad *sinkpad, *srcpad; GstBufferPool *bufpool; + GstPad *sinkpad, *srcpad; + GstClock *clock; + + /* filter properties */ + gboolean mute; + gfloat buffer_time; + guint max_plays; + gfloat clock_speed; + guint total_ticks; + GSList *tick_list; - /* these next data elements are for the filter's internal buffers and list of - play pointers (offsets in the internal buffers). there are also flags for - repeating from the beginning or end of the input stream, and a max buffer - size. */ + /* internal buffer info */ gchar *buffer; - guint buffer_size; - guint buffer_samples; + guint buffer_bytes; + gboolean eos; + /* play pointers == internal buffer offsets for producing output sound */ guint *plays; guint write; - guint start; - - gboolean play_from_beginning; - gboolean buffer_filled_once; - - gboolean eos; - gboolean silent; - /* the playondemand filter needs to keep track of a number of 'measures' - consisting of 'beats'. these are represented as an array of guint64s, with - each guint64 being one measure, and the bits in each measure being beats - (lower order bits come first). each measure can therefore have a maximum of - 64 beats, though there are a potentially unlimited number of measures. - - this is basically a way to figure out when incoming clock signals should - add a play pointer. */ - GstClock *clock; - guint last_time; - - guint64 *times; - guint num_measures; - guint num_beats; - guint total_beats; - - /* the next three are valid for both int and float */ + /* audio format info (used to calculate buffer_samples) */ GstPlayOnDemandFormat format; - guint rate; - guint channels; - - /* the next five are valid only for format == GST_PLAYONDEMAND_FORMAT_INT */ + guint rate; + guint channels; guint width; - guint depth; - guint endianness; - guint law; - gboolean is_signed; - - /* the next three are valid only for format == GST_PLAYONDEMAND_FORMAT_FLOAT */ - const gchar *layout; - gfloat slope; - gfloat intercept; }; struct _GstPlayOnDemandClass { GstElementClass parent_class; - void (*play) (GstElement *elem); - void (*reset) (GstElement *elem); + void (*play) (GstElement *elem); + void (*clear) (GstElement *elem); + void (*reset) (GstElement *elem); + void (*played) (GstElement *elem); }; GType gst_play_on_demand_get_type(void); -void gst_play_on_demand_set_beat (GstPlayOnDemand *filter, - const guint measure, - const guint beat, - const gboolean value); -gboolean gst_play_on_demand_get_beat (GstPlayOnDemand *filter, - const guint measure, - const guint beat); -void gst_play_on_demand_toggle_beat (GstPlayOnDemand *filter, - const guint measure, - const guint beat); #ifdef __cplusplus } |