summaryrefslogtreecommitdiff
path: root/gst/playondemand/gstplayondemand.c
diff options
context:
space:
mode:
authorLeif Johnson <leif@ambient.2y.net>2003-01-17 14:04:39 +0000
committerLeif Johnson <leif@ambient.2y.net>2003-01-17 14:04:39 +0000
commit6b785348c45a7c24b50ebd0a209bbd94d46db5f4 (patch)
treec411bec6ce7f975f13c087350ac00149f2a60c3f /gst/playondemand/gstplayondemand.c
parentb2d148685a2f73524c422beb2ab8d120165f19f5 (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.c662
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());