diff options
author | Leif Johnson <leif@ambient.2y.net> | 2003-01-17 14:04:39 +0000 |
---|---|---|
committer | Leif Johnson <leif@ambient.2y.net> | 2003-01-17 14:04:39 +0000 |
commit | 6b785348c45a7c24b50ebd0a209bbd94d46db5f4 (patch) | |
tree | c411bec6ce7f975f13c087350ac00149f2a60c3f /gst/playondemand/gstplayondemand.c | |
parent | b2d148685a2f73524c422beb2ab8d120165f19f5 (diff) |
+ modifying playondemand to behave a little more like a sequencer
Original commit message from CVS:
+ modifying playondemand to behave a little more like a sequencer
Diffstat (limited to 'gst/playondemand/gstplayondemand.c')
-rw-r--r-- | gst/playondemand/gstplayondemand.c | 662 |
1 files changed, 308 insertions, 354 deletions
diff --git a/gst/playondemand/gstplayondemand.c b/gst/playondemand/gstplayondemand.c index 1784cb863..823755397 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()); |