soundtouch: Don't assume output buffer timestamps
[platform/upstream/gstreamer.git] / ext / soundtouch / gstpitch.cc
1 /* GStreamer pitch controller element
2  * Copyright (C) 2006 Wouter Paesen <wouter@blue-gate.be>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include <config.h>
22 #endif
23
24 /* FIXME: workaround for SoundTouch.h of version 1.3.1 defining those
25  * variables while it shouldn't. */
26 #undef VERSION
27 #undef PACKAGE_VERSION
28 #undef PACKAGE_TARNAME
29 #undef PACKAGE_STRING
30 #undef PACKAGE_NAME
31 #undef PACKAGE_BUGREPORT
32 #undef PACKAGE
33
34 #define FLOAT_SAMPLES 1
35 #include <soundtouch/SoundTouch.h>
36
37 #include <gst/gst.h>
38 #include <gst/audio/audio.h>
39
40 #include "gstpitch.hh"
41 #include <math.h>
42
43 GST_DEBUG_CATEGORY_STATIC (pitch_debug);
44 #define GST_CAT_DEFAULT pitch_debug
45
46 #define GST_PITCH_GET_PRIVATE(o) (o->priv)
47 struct _GstPitchPrivate
48 {
49   gfloat stream_time_ratio;
50
51   GstEvent *pending_segment;
52
53     soundtouch::SoundTouch * st;
54 };
55
56 enum
57 {
58   ARG_0,
59   ARG_OUT_RATE,
60   ARG_RATE,
61   ARG_TEMPO,
62   ARG_PITCH
63 };
64
65 #define SUPPORTED_CAPS \
66   "audio/x-raw, " \
67     "format = (string) " GST_AUDIO_NE (F32) ", " \
68     "rate = (int) [ 8000, MAX ], " \
69     "channels = (int) [ 1, 2 ]"
70
71 static GstStaticPadTemplate gst_pitch_sink_template =
72 GST_STATIC_PAD_TEMPLATE ("sink",
73     GST_PAD_SINK,
74     GST_PAD_ALWAYS,
75     GST_STATIC_CAPS (SUPPORTED_CAPS));
76
77 static GstStaticPadTemplate gst_pitch_src_template =
78 GST_STATIC_PAD_TEMPLATE ("src",
79     GST_PAD_SRC,
80     GST_PAD_ALWAYS,
81     GST_STATIC_CAPS (SUPPORTED_CAPS));
82
83 static void gst_pitch_dispose (GObject * object);
84 static void gst_pitch_set_property (GObject * object,
85     guint prop_id, const GValue * value, GParamSpec * pspec);
86 static void gst_pitch_get_property (GObject * object,
87     guint prop_id, GValue * value, GParamSpec * pspec);
88
89
90 static gboolean gst_pitch_setcaps (GstPitch * pitch, GstCaps * caps);
91 static GstFlowReturn gst_pitch_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer);
92 static GstStateChangeReturn gst_pitch_change_state (GstElement * element,
93     GstStateChange transition);
94 static gboolean gst_pitch_sink_event (GstPad * pad, GstObject * parent, GstEvent * event);
95 static gboolean gst_pitch_src_event (GstPad * pad, GstObject * parent, GstEvent * event);
96
97 static gboolean gst_pitch_src_query (GstPad * pad, GstObject * parent, GstQuery * query);
98
99 #define gst_pitch_parent_class parent_class
100 G_DEFINE_TYPE (GstPitch, gst_pitch, GST_TYPE_ELEMENT);
101
102 static void
103 gst_pitch_class_init (GstPitchClass * klass)
104 {
105   GObjectClass *gobject_class;
106   GstElementClass *element_class;
107
108   gobject_class = G_OBJECT_CLASS (klass);
109   element_class = GST_ELEMENT_CLASS (klass);
110
111   GST_DEBUG_CATEGORY_INIT (pitch_debug, "pitch", 0,
112       "audio pitch control element");
113
114   g_type_class_add_private (gobject_class, sizeof (GstPitchPrivate));
115
116   gobject_class->set_property = gst_pitch_set_property;
117   gobject_class->get_property = gst_pitch_get_property;
118   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_pitch_dispose);
119
120   g_object_class_install_property (gobject_class, ARG_PITCH,
121       g_param_spec_float ("pitch", "Pitch",
122           "Audio stream pitch", 0.1, 10.0, 1.0,
123           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)));
124
125   g_object_class_install_property (gobject_class, ARG_TEMPO,
126       g_param_spec_float ("tempo", "Tempo",
127           "Audio stream tempo", 0.1, 10.0, 1.0,
128           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)));
129
130   g_object_class_install_property (gobject_class, ARG_RATE,
131       g_param_spec_float ("rate", "Rate",
132           "Audio stream rate", 0.1, 10.0, 1.0,
133           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)));
134
135   g_object_class_install_property (gobject_class, ARG_OUT_RATE,
136       g_param_spec_float ("output-rate", "Output Rate",
137           "Output rate on downstream segment events", 0.1, 10.0, 1.0,
138           (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS)));
139
140   element_class->change_state = GST_DEBUG_FUNCPTR (gst_pitch_change_state);
141
142   gst_element_class_add_pad_template (element_class,
143       gst_static_pad_template_get (&gst_pitch_src_template));
144   gst_element_class_add_pad_template (element_class,
145       gst_static_pad_template_get (&gst_pitch_sink_template));
146
147   gst_element_class_set_details_simple (element_class, "Pitch controller",
148       "Filter/Effect/Audio", "Control the pitch of an audio stream",
149       "Wouter Paesen <wouter@blue-gate.be>");
150 }
151
152 static void
153 gst_pitch_init (GstPitch * pitch)
154 {
155   pitch->priv =
156       G_TYPE_INSTANCE_GET_PRIVATE ((pitch), GST_TYPE_PITCH, GstPitchPrivate);
157
158   pitch->sinkpad =
159       gst_pad_new_from_static_template (&gst_pitch_sink_template, "sink");
160   gst_pad_set_chain_function (pitch->sinkpad,
161       GST_DEBUG_FUNCPTR (gst_pitch_chain));
162   gst_pad_set_event_function (pitch->sinkpad,
163       GST_DEBUG_FUNCPTR (gst_pitch_sink_event));
164   GST_PAD_SET_PROXY_CAPS (pitch->sinkpad);
165   gst_element_add_pad (GST_ELEMENT (pitch), pitch->sinkpad);
166
167   pitch->srcpad =
168       gst_pad_new_from_static_template (&gst_pitch_src_template, "src");
169   gst_pad_set_event_function (pitch->srcpad,
170       GST_DEBUG_FUNCPTR (gst_pitch_src_event));
171   gst_pad_set_query_function (pitch->srcpad,
172       GST_DEBUG_FUNCPTR (gst_pitch_src_query));
173   GST_PAD_SET_PROXY_CAPS (pitch->sinkpad);
174   gst_element_add_pad (GST_ELEMENT (pitch), pitch->srcpad);
175
176   pitch->priv->st = new soundtouch::SoundTouch ();
177
178   pitch->tempo = 1.0;
179   pitch->rate = 1.0;
180   pitch->out_seg_rate = 1.0;
181   pitch->seg_arate = 1.0;
182   pitch->pitch = 1.0;
183   pitch->next_buffer_time = GST_CLOCK_TIME_NONE;
184   pitch->next_buffer_offset = 0;
185
186   pitch->priv->st->setRate (pitch->rate);
187   pitch->priv->st->setTempo (pitch->tempo * pitch->seg_arate);
188   pitch->priv->st->setPitch (pitch->pitch);
189
190   pitch->priv->stream_time_ratio = 1.0;
191   pitch->min_latency = pitch->max_latency = 0;
192 }
193
194
195 static void
196 gst_pitch_dispose (GObject * object)
197 {
198   GstPitch *pitch = GST_PITCH (object);
199
200   if (pitch->priv->st) {
201     delete pitch->priv->st;
202
203     pitch->priv->st = NULL;
204   }
205
206   G_OBJECT_CLASS (parent_class)->dispose (object);
207 }
208
209 static void
210 gst_pitch_update_duration (GstPitch * pitch)
211 {
212   GstMessage *m;
213
214   m = gst_message_new_duration (GST_OBJECT (pitch), GST_FORMAT_TIME, -1);
215   gst_element_post_message (GST_ELEMENT (pitch), m);
216 }
217
218 static void
219 gst_pitch_set_property (GObject * object, guint prop_id,
220     const GValue * value, GParamSpec * pspec)
221 {
222   GstPitch *pitch = GST_PITCH (object);
223
224   GST_OBJECT_LOCK (pitch);
225   switch (prop_id) {
226     case ARG_TEMPO:
227       pitch->tempo = g_value_get_float (value);
228       pitch->priv->stream_time_ratio = pitch->tempo * pitch->rate * pitch->seg_arate;
229       pitch->priv->st->setTempo (pitch->tempo * pitch->seg_arate);
230       GST_OBJECT_UNLOCK (pitch);
231       gst_pitch_update_duration (pitch);
232       break;
233     case ARG_RATE:
234       pitch->rate = g_value_get_float (value);
235       pitch->priv->stream_time_ratio = pitch->tempo * pitch->rate * pitch->seg_arate;
236       pitch->priv->st->setRate (pitch->rate);
237       GST_OBJECT_UNLOCK (pitch);
238       gst_pitch_update_duration (pitch);
239       break;
240     case ARG_OUT_RATE:
241       /* Has no effect until the next input segment */
242       pitch->out_seg_rate = g_value_get_float (value);
243       GST_OBJECT_UNLOCK (pitch);
244     case ARG_PITCH:
245       pitch->pitch = g_value_get_float (value);
246       pitch->priv->st->setPitch (pitch->pitch);
247       GST_OBJECT_UNLOCK (pitch);
248       break;
249     default:
250       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
251       GST_OBJECT_UNLOCK (pitch);
252       break;
253   }
254 }
255
256 static void
257 gst_pitch_get_property (GObject * object, guint prop_id,
258     GValue * value, GParamSpec * pspec)
259 {
260   GstPitch *pitch = GST_PITCH (object);
261
262   GST_OBJECT_LOCK (pitch);
263   switch (prop_id) {
264     case ARG_TEMPO:
265       g_value_set_float (value, pitch->tempo);
266       break;
267     case ARG_RATE:
268       g_value_set_float (value, pitch->rate);
269       break;
270     case ARG_OUT_RATE:
271       g_value_set_float (value, pitch->out_seg_rate);
272       break;
273     case ARG_PITCH:
274       g_value_set_float (value, pitch->pitch);
275       break;
276     default:
277       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
278       break;
279   }
280   GST_OBJECT_UNLOCK (pitch);
281 }
282
283 static gboolean
284 gst_pitch_setcaps (GstPitch * pitch, GstCaps * caps)
285 {
286   GstPitchPrivate *priv;
287   GstStructure *structure;
288   gint rate, channels;
289
290   priv = GST_PITCH_GET_PRIVATE (pitch);
291
292   structure = gst_caps_get_structure (caps, 0);
293
294   if (!gst_structure_get_int (structure, "rate", &rate) ||
295       !gst_structure_get_int (structure, "channels", &channels)) {
296     return FALSE;
297   }
298
299   GST_OBJECT_LOCK (pitch);
300
301   pitch->samplerate = rate;
302   pitch->channels = channels;
303
304   /* notify the soundtouch instance of this change */
305   priv->st->setSampleRate (rate);
306   priv->st->setChannels (channels);
307
308   /* calculate sample size */
309   pitch->sample_size = (sizeof (gfloat) * channels);
310
311   GST_OBJECT_UNLOCK (pitch);
312
313   return TRUE;
314 }
315
316 /* send a buffer out */
317 static GstFlowReturn
318 gst_pitch_forward_buffer (GstPitch * pitch, GstBuffer * buffer)
319 {
320   gint samples;
321
322   GST_BUFFER_TIMESTAMP (buffer) = pitch->next_buffer_time;
323   pitch->next_buffer_time += GST_BUFFER_DURATION (buffer);
324
325   samples = GST_BUFFER_OFFSET (buffer);
326   GST_BUFFER_OFFSET (buffer) = pitch->next_buffer_offset;
327   pitch->next_buffer_offset += samples;
328   GST_BUFFER_OFFSET_END (buffer) = pitch->next_buffer_offset;
329
330   GST_LOG ("pushing buffer [%" GST_TIME_FORMAT "]-[%" GST_TIME_FORMAT
331       "] (%d samples)", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)),
332       GST_TIME_ARGS (pitch->next_buffer_time), samples);
333
334   return gst_pad_push (pitch->srcpad, buffer);
335 }
336
337 /* extract a buffer from soundtouch */
338 static GstBuffer *
339 gst_pitch_prepare_buffer (GstPitch * pitch)
340 {
341   GstPitchPrivate *priv;
342   guint samples;
343   GstBuffer *buffer;
344   GstMapInfo info;
345
346   priv = GST_PITCH_GET_PRIVATE (pitch);
347
348   GST_LOG_OBJECT (pitch, "preparing buffer");
349
350   samples = pitch->priv->st->numSamples ();
351   if (samples == 0)
352     return NULL;
353
354   buffer = gst_buffer_new_and_alloc (samples * pitch->sample_size);
355
356   gst_buffer_map (buffer, &info, (GstMapFlags) GST_MAP_READWRITE);
357   samples =
358       priv->st->receiveSamples ((gfloat *) info.data, samples);
359   gst_buffer_unmap (buffer, &info);
360
361   if (samples <= 0) {
362     gst_buffer_unref (buffer);
363     return NULL;
364   }
365
366   GST_BUFFER_DURATION (buffer) =
367       gst_util_uint64_scale (samples, GST_SECOND, pitch->samplerate);
368   /* temporary store samples here, to avoid having to recalculate this */
369   GST_BUFFER_OFFSET (buffer) = (gint64) samples;
370
371   return buffer;
372 }
373
374 /* process the last samples, in a later stage we should make sure no more
375  * samples are sent out here as strictly necessary, because soundtouch could
376  * append zero samples, which could disturb looping.  */
377 static GstFlowReturn
378 gst_pitch_flush_buffer (GstPitch * pitch, gboolean send)
379 {
380   GstBuffer *buffer;
381
382   GST_DEBUG_OBJECT (pitch, "flushing buffer");
383
384   if (pitch->next_buffer_offset == 0)
385     return GST_FLOW_OK;
386
387   pitch->priv->st->flush ();
388   if (!send)
389     return GST_FLOW_OK;
390
391   buffer = gst_pitch_prepare_buffer (pitch);
392
393   if (!buffer)
394     return GST_FLOW_OK;
395
396   return gst_pitch_forward_buffer (pitch, buffer);
397 }
398
399 static gboolean
400 gst_pitch_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
401 {
402   GstPitch *pitch;
403   gboolean res;
404
405   pitch = GST_PITCH (parent);
406
407   GST_DEBUG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
408
409   switch (GST_EVENT_TYPE (event)) {
410     case GST_EVENT_SEEK:{
411       /* transform the event upstream, according to the playback rate */
412       gdouble rate;
413       GstFormat format;
414       GstSeekFlags flags;
415       GstSeekType cur_type, stop_type;
416       gint64 cur, stop;
417       gfloat stream_time_ratio;
418
419       GST_OBJECT_LOCK (pitch);
420       stream_time_ratio = pitch->priv->stream_time_ratio;
421       GST_OBJECT_UNLOCK (pitch);
422
423       gst_event_parse_seek (event, &rate, &format, &flags,
424           &cur_type, &cur, &stop_type, &stop);
425
426       gst_event_unref (event);
427
428       if (format == GST_FORMAT_TIME || format == GST_FORMAT_DEFAULT) {
429         cur = (gint64) (cur * stream_time_ratio);
430         if (stop != -1)
431           stop = (gint64) (stop * stream_time_ratio);
432
433         event = gst_event_new_seek (rate, format, flags,
434             cur_type, cur, stop_type, stop);
435         res = gst_pad_event_default (pad, parent, event);
436       } else {
437         GST_WARNING_OBJECT (pitch,
438             "Seeking only supported in TIME or DEFAULT format");
439         res = FALSE;
440       }
441       break;
442     }
443     default:
444       res = gst_pad_event_default (pad, parent, event);
445       break;
446   }
447   return res;
448 }
449
450 /* generic convert function based on caps, no rate 
451  * used here 
452  */
453 static gboolean
454 gst_pitch_convert (GstPitch * pitch,
455     GstFormat src_format, gint64 src_value,
456     GstFormat * dst_format, gint64 * dst_value)
457 {
458   gboolean res = TRUE;
459   guint sample_size;
460   gint samplerate;
461
462   g_return_val_if_fail (dst_format && dst_value, FALSE);
463
464   GST_OBJECT_LOCK (pitch);
465   sample_size = pitch->sample_size;
466   samplerate = pitch->samplerate;
467   GST_OBJECT_UNLOCK (pitch);
468
469   if (sample_size == 0 || samplerate == 0) {
470     return FALSE;
471   }
472
473   if (src_format == *dst_format || src_value == -1) {
474     *dst_value = src_value;
475     return TRUE;
476   }
477
478   switch (src_format) {
479     case GST_FORMAT_BYTES:
480       switch (*dst_format) {
481         case GST_FORMAT_TIME:
482           *dst_value =
483               gst_util_uint64_scale_int (src_value, GST_SECOND,
484               sample_size * samplerate);
485           break;
486         case GST_FORMAT_DEFAULT:
487           *dst_value = gst_util_uint64_scale_int (src_value, 1, sample_size);
488           break;
489         default:
490           res = FALSE;
491           break;
492       }
493       break;
494     case GST_FORMAT_TIME:
495       switch (*dst_format) {
496         case GST_FORMAT_BYTES:
497           *dst_value =
498               gst_util_uint64_scale_int (src_value, samplerate * sample_size,
499               GST_SECOND);
500           break;
501         case GST_FORMAT_DEFAULT:
502           *dst_value =
503               gst_util_uint64_scale_int (src_value, samplerate, GST_SECOND);
504           break;
505         default:
506           res = FALSE;
507           break;
508       }
509       break;
510     case GST_FORMAT_DEFAULT:
511       switch (*dst_format) {
512         case GST_FORMAT_BYTES:
513           *dst_value = gst_util_uint64_scale_int (src_value, sample_size, 1);
514           break;
515         case GST_FORMAT_TIME:
516           *dst_value =
517               gst_util_uint64_scale_int (src_value, GST_SECOND, samplerate);
518           break;
519         default:
520           res = FALSE;
521           break;
522       }
523       break;
524     default:
525       res = FALSE;
526       break;
527   }
528
529   return res;
530 }
531
532 static gboolean
533 gst_pitch_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
534 {
535   GstPitch *pitch;
536   gboolean res = FALSE;
537   gfloat stream_time_ratio;
538   gint64 next_buffer_offset;
539   GstClockTime next_buffer_time;
540
541   pitch = GST_PITCH (parent);
542
543   GST_LOG ("%s query", GST_QUERY_TYPE_NAME (query));
544
545   GST_OBJECT_LOCK (pitch);
546   stream_time_ratio = pitch->priv->stream_time_ratio;
547   next_buffer_time = pitch->next_buffer_time;
548   next_buffer_offset = pitch->next_buffer_offset;
549   GST_OBJECT_UNLOCK (pitch);
550
551   switch (GST_QUERY_TYPE (query)) {
552     case GST_QUERY_DURATION:{
553       GstFormat format;
554       gint64 duration;
555
556       if (!gst_pad_query_default (pad, parent, query)) {
557         GST_DEBUG_OBJECT (pitch, "upstream provided no duration");
558         break;
559       }
560
561       gst_query_parse_duration (query, &format, &duration);
562
563       if (format != GST_FORMAT_TIME && format != GST_FORMAT_DEFAULT) {
564         GST_DEBUG_OBJECT (pitch, "not TIME or DEFAULT format");
565         break;
566       }
567       GST_LOG_OBJECT (pitch, "upstream duration: %" G_GINT64_FORMAT, duration);
568       duration = (gint64) (duration / stream_time_ratio);
569       GST_LOG_OBJECT (pitch, "our duration: %" G_GINT64_FORMAT, duration);
570       gst_query_set_duration (query, format, duration);
571       res = TRUE;
572       break;
573     }
574     case GST_QUERY_POSITION:{
575       GstFormat dst_format;
576       gint64 dst_value;
577
578       gst_query_parse_position (query, &dst_format, &dst_value);
579
580       if (dst_format != GST_FORMAT_TIME && dst_format != GST_FORMAT_DEFAULT) {
581         GST_DEBUG_OBJECT (pitch, "not TIME or DEFAULT format");
582         break;
583       }
584
585       if (dst_format == GST_FORMAT_TIME) {
586         dst_value = next_buffer_time;
587         res = TRUE;
588       } else {
589         dst_value = next_buffer_offset;
590         res = TRUE;
591       }
592
593       if (res) {
594         GST_LOG_OBJECT (pitch, "our position: %" G_GINT64_FORMAT, dst_value);
595         gst_query_set_position (query, dst_format, dst_value);
596       }
597       break;
598     }
599     case GST_QUERY_CONVERT:{
600       GstFormat src_format, dst_format;
601       gint64 src_value, dst_value;
602
603       gst_query_parse_convert (query, &src_format, &src_value,
604           &dst_format, NULL);
605
606       res = gst_pitch_convert (pitch, src_format, src_value,
607           &dst_format, &dst_value);
608
609       if (res) {
610         gst_query_set_convert (query, src_format, src_value,
611             dst_format, dst_value);
612       }
613       break;
614     }
615     case GST_QUERY_LATENCY:
616     {
617       GstClockTime min, max;
618       gboolean live;
619       GstPad *peer;
620
621       if ((peer = gst_pad_get_peer (pitch->sinkpad))) {
622         if ((res = gst_pad_query (peer, query))) {
623           gst_query_parse_latency (query, &live, &min, &max);
624
625           GST_DEBUG ("Peer latency: min %"
626               GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
627               GST_TIME_ARGS (min), GST_TIME_ARGS (max));
628
629           /* add our own latency */
630
631           GST_DEBUG ("Our latency: min %" GST_TIME_FORMAT
632               ", max %" GST_TIME_FORMAT,
633               GST_TIME_ARGS (pitch->min_latency),
634               GST_TIME_ARGS (pitch->max_latency));
635
636           min += pitch->min_latency;
637           if (max != GST_CLOCK_TIME_NONE)
638             max += pitch->max_latency;
639           else
640             max = pitch->max_latency;
641
642           GST_DEBUG ("Calculated total latency : min %"
643               GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
644               GST_TIME_ARGS (min), GST_TIME_ARGS (max));
645           gst_query_set_latency (query, live, min, max);
646         }
647         gst_object_unref (peer);
648       }
649       break;
650     }
651     default:
652       res = gst_pad_query_default (pad, parent, query);
653       break;
654   }
655
656   return res;
657 }
658
659 /* this function returns FALSE if not enough data is known to transform the
660  * segment into proper downstream values.  If the function does return false
661  * the sgement should be stalled until enough information is available.
662  * If the funtion returns TRUE, event will be replaced by the new downstream
663  * compatible event.
664  */
665 static gboolean
666 gst_pitch_process_segment (GstPitch * pitch, GstEvent ** event)
667 {
668   gdouble out_seg_rate, our_arate;
669   gfloat stream_time_ratio;
670   GstSegment seg;
671
672   g_return_val_if_fail (event, FALSE);
673
674   GST_OBJECT_LOCK (pitch);
675   stream_time_ratio = pitch->priv->stream_time_ratio;
676   out_seg_rate = pitch->out_seg_rate;
677   GST_OBJECT_UNLOCK (pitch);
678
679   gst_event_copy_segment (*event, &seg);
680
681   if (seg.format != GST_FORMAT_TIME && seg.format != GST_FORMAT_DEFAULT) {
682     GST_WARNING_OBJECT (pitch,
683         "Only NEWSEGMENT in TIME or DEFAULT format supported, sending"
684         "open ended NEWSEGMENT in TIME format.");
685     seg.format = GST_FORMAT_TIME;
686     seg.start = 0;
687     seg.stop = -1;
688     seg.time = 0;
689   }
690
691   /* Figure out how much of the incoming 'rate' we'll apply ourselves */
692   our_arate = seg.rate / out_seg_rate;
693   /* update the output rate variables */
694   seg.rate = out_seg_rate;
695   seg.applied_rate *= our_arate;
696
697   GST_LOG_OBJECT (pitch->sinkpad,
698       "segment %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT " (%d)", seg.start,
699       seg.stop, seg.format);
700
701   stream_time_ratio = pitch->tempo * pitch->rate * pitch->seg_arate;
702
703   if (stream_time_ratio == 0) {
704     GST_LOG_OBJECT (pitch->sinkpad, "stream_time_ratio is zero");
705     return FALSE;
706   }
707
708   /* Update the playback rate */
709   GST_OBJECT_LOCK (pitch);
710   pitch->seg_arate = our_arate;
711   pitch->priv->stream_time_ratio = stream_time_ratio;
712   pitch->priv->st->setTempo (pitch->tempo * pitch->seg_arate);
713   GST_OBJECT_UNLOCK (pitch);
714
715   seg.start = (gint64) (seg.start / stream_time_ratio);
716   if (seg.stop != (guint64) - 1)
717     seg.stop = (gint64) (seg.stop / stream_time_ratio);
718   seg.time = (gint64) (seg.time / stream_time_ratio);
719
720   gst_event_unref (*event);
721   *event = gst_event_new_segment (&seg);
722
723   return TRUE;
724 }
725
726 static gboolean
727 gst_pitch_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
728 {
729   gboolean res = TRUE;
730   GstPitch *pitch;
731
732   pitch = GST_PITCH (parent);
733
734   GST_LOG_OBJECT (pad, "received %s event", GST_EVENT_TYPE_NAME (event));
735
736   switch (GST_EVENT_TYPE (event)) {
737     case GST_EVENT_FLUSH_STOP:
738       gst_pitch_flush_buffer (pitch, FALSE);
739       pitch->priv->st->clear ();
740       pitch->next_buffer_offset = 0;
741       pitch->next_buffer_time = GST_CLOCK_TIME_NONE;
742       pitch->min_latency = pitch->max_latency = 0;
743       break;
744     case GST_EVENT_EOS:
745       gst_pitch_flush_buffer (pitch, TRUE);
746       pitch->priv->st->clear ();
747       pitch->min_latency = pitch->max_latency = 0;
748       break;
749     case GST_EVENT_SEGMENT:
750       if (!gst_pitch_process_segment (pitch, &event)) {
751         GST_LOG_OBJECT (pad, "not enough data known, stalling segment");
752         if (GST_PITCH_GET_PRIVATE (pitch)->pending_segment)
753           gst_event_unref (GST_PITCH_GET_PRIVATE (pitch)->pending_segment);
754         GST_PITCH_GET_PRIVATE (pitch)->pending_segment = event;
755         event = NULL;
756       }
757       pitch->priv->st->clear ();
758       pitch->min_latency = pitch->max_latency = 0;
759       break;
760     case GST_EVENT_CAPS:
761     {
762       GstCaps * caps;
763
764       gst_event_parse_caps (event, &caps);
765       res = gst_pitch_setcaps (pitch, caps);
766       if (!res) {
767         gst_event_unref (event);
768         goto done;
769       }
770     }
771     default:
772       break;
773   }
774
775   /* and forward it */
776   if (event)
777     res = gst_pad_event_default (pad, parent, event);
778
779 done:
780   return res;
781 }
782
783 static void
784 gst_pitch_update_latency (GstPitch * pitch, GstClockTime timestamp)
785 {
786   GstClockTimeDiff current_latency, min_latency, max_latency;
787
788   current_latency =
789       (GstClockTimeDiff) (timestamp / pitch->priv->stream_time_ratio) -
790       pitch->next_buffer_time;
791
792   min_latency = MIN (pitch->min_latency, current_latency);
793   max_latency = MAX (pitch->max_latency, current_latency);
794
795   if (pitch->min_latency != min_latency || pitch->max_latency != max_latency) {
796     pitch->min_latency = min_latency;
797     pitch->max_latency = max_latency;
798
799     /* FIXME: what about the LATENCY event? It only has
800      * one latency value, should it be current, min or max?
801      * Should it include upstream latencies?
802      */
803
804     gst_element_post_message (GST_ELEMENT (pitch),
805         gst_message_new_latency (GST_OBJECT (pitch)));
806   }
807 }
808
809 static GstFlowReturn
810 gst_pitch_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
811 {
812   GstPitch *pitch;
813   GstPitchPrivate *priv;
814   GstClockTime timestamp;
815   GstMapInfo info;
816
817   pitch = GST_PITCH (parent);
818   priv = GST_PITCH_GET_PRIVATE (pitch);
819
820   timestamp = GST_BUFFER_TIMESTAMP (buffer);
821
822   // Remember the first time and corresponding offset
823   if (!GST_CLOCK_TIME_IS_VALID (pitch->next_buffer_time)) {
824     GstFormat out_format = GST_FORMAT_DEFAULT;
825     pitch->next_buffer_time = timestamp;
826     gst_pitch_convert (pitch, GST_FORMAT_TIME, timestamp, &out_format,
827         &pitch->next_buffer_offset);
828   }
829
830   gst_object_sync_values (GST_OBJECT (pitch), pitch->next_buffer_time);
831
832   /* push the received samples on the soundtouch buffer */
833   GST_LOG_OBJECT (pitch, "incoming buffer (%d samples) %" GST_TIME_FORMAT,
834       (gint) (gst_buffer_get_size (buffer) / pitch->sample_size),
835       GST_TIME_ARGS (timestamp));
836
837   if (GST_PITCH_GET_PRIVATE (pitch)->pending_segment) {
838     GstEvent *event =
839         gst_event_copy (GST_PITCH_GET_PRIVATE (pitch)->pending_segment);
840
841     GST_LOG_OBJECT (pitch, "processing stalled segment");
842     if (!gst_pitch_process_segment (pitch, &event)) {
843       gst_buffer_unref (buffer);
844       gst_event_unref (event);
845       return GST_FLOW_ERROR;
846     }
847
848     if (!gst_pad_event_default (pitch->sinkpad, parent, event)) {
849       gst_buffer_unref (buffer);
850       gst_event_unref (event);
851       return GST_FLOW_ERROR;
852     }
853
854     gst_event_unref (GST_PITCH_GET_PRIVATE (pitch)->pending_segment);
855     GST_PITCH_GET_PRIVATE (pitch)->pending_segment = NULL;
856   }
857
858   gst_buffer_map (buffer, &info, GST_MAP_READ);
859   priv->st->putSamples ((gfloat *) info.data, info.size / pitch->sample_size);
860   gst_buffer_unmap (buffer, &info);
861   gst_buffer_unref (buffer);
862
863   /* Calculate latency */
864
865   gst_pitch_update_latency (pitch, timestamp);
866   /* and try to extract some samples from the soundtouch buffer */
867   if (!priv->st->isEmpty ()) {
868     GstBuffer *out_buffer;
869
870     out_buffer = gst_pitch_prepare_buffer (pitch);
871     if (out_buffer)
872       return gst_pitch_forward_buffer (pitch, out_buffer);
873   }
874
875   return GST_FLOW_OK;
876 }
877
878 static GstStateChangeReturn
879 gst_pitch_change_state (GstElement * element, GstStateChange transition)
880 {
881   GstStateChangeReturn ret;
882   GstPitch *pitch = GST_PITCH (element);
883
884   switch (transition) {
885     case GST_STATE_CHANGE_NULL_TO_READY:
886       break;
887     case GST_STATE_CHANGE_READY_TO_PAUSED:
888       pitch->next_buffer_time = 0;
889       pitch->next_buffer_offset = 0;
890       pitch->priv->st->clear ();
891       pitch->min_latency = pitch->max_latency = 0;
892       break;
893     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
894       break;
895     default:
896       break;
897   }
898
899   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
900   if (ret != GST_STATE_CHANGE_SUCCESS)
901     return ret;
902
903   switch (transition) {
904     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
905       break;
906     case GST_STATE_CHANGE_PAUSED_TO_READY:
907       if (GST_PITCH_GET_PRIVATE (pitch)->pending_segment) {
908         gst_event_unref (GST_PITCH_GET_PRIVATE (pitch)->pending_segment);
909         GST_PITCH_GET_PRIVATE (pitch)->pending_segment = NULL;
910       }
911       break;
912     case GST_STATE_CHANGE_READY_TO_NULL:
913     default:
914       break;
915   }
916
917   return ret;
918 }