timeline-object: Add TrackObject to the Track after the TimelineObject
[platform/upstream/gstreamer.git] / ges / ges-track-audio-transition.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2010 Brandon Lewis <brandon.lewis@collabora.co.uk>
3  *               2010 Nokia Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * SECTION:ges-track-audio-transition
23  * @short_description: implements audio crossfade transition
24  */
25
26 #include "ges-internal.h"
27 #include "ges-track-object.h"
28 #include "ges-track-audio-transition.h"
29
30 G_DEFINE_TYPE (GESTrackAudioTransition, ges_track_audio_transition,
31     GES_TYPE_TRACK_TRANSITION);
32
33 struct _GESTrackAudioTransitionPrivate
34 {
35   /* these enable volume interpolation. Unlike video, both inputs are adjusted
36    * simultaneously */
37   GstController *a_controller;
38   GstInterpolationControlSource *a_control_source;
39
40   GstController *b_controller;
41   GstInterpolationControlSource *b_control_source;
42
43 };
44
45 enum
46 {
47   PROP_0,
48 };
49
50
51 #define fast_element_link(a,b) gst_element_link_pads_full((a),"src",(b),"sink",GST_PAD_LINK_CHECK_NOTHING)
52
53 static void
54 ges_track_audio_transition_duration_changed (GESTrackObject * self, guint64);
55
56 static GstElement *ges_track_audio_transition_create_element (GESTrackObject
57     * self);
58
59 static void ges_track_audio_transition_dispose (GObject * object);
60
61 static void ges_track_audio_transition_finalize (GObject * object);
62
63 static void ges_track_audio_transition_get_property (GObject * object, guint
64     property_id, GValue * value, GParamSpec * pspec);
65
66 static void ges_track_audio_transition_set_property (GObject * object, guint
67     property_id, const GValue * value, GParamSpec * pspec);
68
69 static void
70 ges_track_audio_transition_class_init (GESTrackAudioTransitionClass * klass)
71 {
72   GObjectClass *object_class;
73   GESTrackObjectClass *toclass;
74
75   g_type_class_add_private (klass, sizeof (GESTrackAudioTransitionPrivate));
76
77   object_class = G_OBJECT_CLASS (klass);
78   toclass = GES_TRACK_OBJECT_CLASS (klass);
79
80   object_class->get_property = ges_track_audio_transition_get_property;
81   object_class->set_property = ges_track_audio_transition_set_property;
82   object_class->dispose = ges_track_audio_transition_dispose;
83   object_class->finalize = ges_track_audio_transition_finalize;
84
85   toclass->duration_changed = ges_track_audio_transition_duration_changed;
86
87   toclass->create_element = ges_track_audio_transition_create_element;
88
89 }
90
91 static void
92 ges_track_audio_transition_init (GESTrackAudioTransition * self)
93 {
94
95   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
96       GES_TYPE_TRACK_AUDIO_TRANSITION, GESTrackAudioTransitionPrivate);
97
98   self->priv->a_controller = NULL;
99   self->priv->a_control_source = NULL;
100
101   self->priv->b_controller = NULL;
102   self->priv->b_control_source = NULL;
103 }
104
105 static void
106 ges_track_audio_transition_dispose (GObject * object)
107 {
108   GESTrackAudioTransition *self;
109
110   self = GES_TRACK_AUDIO_TRANSITION (object);
111
112   if (self->priv->a_controller) {
113     g_object_unref (self->priv->a_controller);
114     self->priv->a_controller = NULL;
115     if (self->priv->a_control_source)
116       gst_object_unref (self->priv->a_control_source);
117     self->priv->a_control_source = NULL;
118   }
119
120   if (self->priv->b_controller) {
121     g_object_unref (self->priv->b_controller);
122     self->priv->b_controller = NULL;
123     if (self->priv->b_control_source)
124       gst_object_unref (self->priv->b_control_source);
125     self->priv->b_control_source = NULL;
126   }
127
128   G_OBJECT_CLASS (ges_track_audio_transition_parent_class)->dispose (object);
129 }
130
131 static void
132 ges_track_audio_transition_finalize (GObject * object)
133 {
134   G_OBJECT_CLASS (ges_track_audio_transition_parent_class)->finalize (object);
135 }
136
137 static void
138 ges_track_audio_transition_get_property (GObject * object,
139     guint property_id, GValue * value, GParamSpec * pspec)
140 {
141   switch (property_id) {
142     default:
143       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
144   }
145 }
146
147 static void
148 ges_track_audio_transition_set_property (GObject * object,
149     guint property_id, const GValue * value, GParamSpec * pspec)
150 {
151   switch (property_id) {
152     default:
153       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
154   }
155 }
156
157 static GObject *
158 link_element_to_mixer_with_volume (GstBin * bin, GstElement * element,
159     GstElement * mixer)
160 {
161   GstElement *volume = gst_element_factory_make ("volume", NULL);
162   gst_bin_add (bin, volume);
163
164   if (!fast_element_link (element, volume) ||
165       !gst_element_link_pads_full (volume, "src", mixer, "sink%d",
166           GST_PAD_LINK_CHECK_NOTHING))
167     GST_ERROR_OBJECT (bin, "Error linking volume to mixer");
168
169   return G_OBJECT (volume);
170 }
171
172 static GstElement *
173 ges_track_audio_transition_create_element (GESTrackObject * object)
174 {
175   GESTrackAudioTransition *self;
176   GstElement *topbin, *iconva, *iconvb, *oconv;
177   GObject *atarget, *btarget = NULL;
178   const gchar *propname = "volume";
179   GstElement *mixer = NULL;
180   GstPad *sinka_target, *sinkb_target, *src_target, *sinka, *sinkb, *src;
181   GstController *acontroller, *bcontroller;
182   GstInterpolationControlSource *acontrol_source, *bcontrol_source;
183
184   self = GES_TRACK_AUDIO_TRANSITION (object);
185
186
187   GST_LOG ("creating an audio bin");
188
189   topbin = gst_bin_new ("transition-bin");
190   iconva = gst_element_factory_make ("audioconvert", "tr-aconv-a");
191   iconvb = gst_element_factory_make ("audioconvert", "tr-aconv-b");
192   oconv = gst_element_factory_make ("audioconvert", "tr-aconv-output");
193
194   gst_bin_add_many (GST_BIN (topbin), iconva, iconvb, oconv, NULL);
195
196   mixer = gst_element_factory_make ("adder", NULL);
197   gst_bin_add (GST_BIN (topbin), mixer);
198
199   atarget = link_element_to_mixer_with_volume (GST_BIN (topbin), iconva, mixer);
200   btarget = link_element_to_mixer_with_volume (GST_BIN (topbin), iconvb, mixer);
201
202   g_assert (atarget && btarget);
203
204   fast_element_link (mixer, oconv);
205
206   sinka_target = gst_element_get_static_pad (iconva, "sink");
207   sinkb_target = gst_element_get_static_pad (iconvb, "sink");
208   src_target = gst_element_get_static_pad (oconv, "src");
209
210   sinka = gst_ghost_pad_new ("sinka", sinka_target);
211   sinkb = gst_ghost_pad_new ("sinkb", sinkb_target);
212   src = gst_ghost_pad_new ("src", src_target);
213
214   gst_element_add_pad (topbin, src);
215   gst_element_add_pad (topbin, sinka);
216   gst_element_add_pad (topbin, sinkb);
217
218   /* set up interpolation */
219
220   gst_object_unref (sinka_target);
221   gst_object_unref (sinkb_target);
222   gst_object_unref (src_target);
223
224
225   //g_object_set(atarget, propname, (gdouble) 0, NULL);
226   //g_object_set(btarget, propname, (gdouble) 0, NULL);
227
228   acontroller = gst_object_control_properties (atarget, propname, NULL);
229   bcontroller = gst_object_control_properties (btarget, propname, NULL);
230
231   g_assert (acontroller && bcontroller);
232
233   acontrol_source = gst_interpolation_control_source_new ();
234   gst_controller_set_control_source (acontroller,
235       propname, GST_CONTROL_SOURCE (acontrol_source));
236   gst_interpolation_control_source_set_interpolation_mode (acontrol_source,
237       GST_INTERPOLATE_LINEAR);
238
239   bcontrol_source = gst_interpolation_control_source_new ();
240   gst_controller_set_control_source (bcontroller,
241       propname, GST_CONTROL_SOURCE (bcontrol_source));
242   gst_interpolation_control_source_set_interpolation_mode (bcontrol_source,
243       GST_INTERPOLATE_LINEAR);
244
245   self->priv->a_controller = acontroller;
246   self->priv->b_controller = bcontroller;
247   self->priv->a_control_source = acontrol_source;
248   self->priv->b_control_source = bcontrol_source;
249
250   return topbin;
251 }
252
253 static void
254 ges_track_audio_transition_duration_changed (GESTrackObject * object,
255     guint64 duration)
256 {
257   GESTrackAudioTransition *self;
258   GstElement *gnlobj = ges_track_object_get_gnlobject (object);
259
260   GValue zero = { 0, };
261   GValue one = { 0, };
262
263   self = GES_TRACK_AUDIO_TRANSITION (object);
264
265   GST_LOG ("updating controller: gnlobj (%p) acontroller(%p) bcontroller(%p)",
266       gnlobj, self->priv->a_controller, self->priv->b_controller);
267
268   if (G_UNLIKELY ((!gnlobj || !self->priv->a_control_source ||
269               !self->priv->b_control_source)))
270     return;
271
272   GST_INFO ("duration: %" G_GUINT64_FORMAT, duration);
273   g_value_init (&zero, G_TYPE_DOUBLE);
274   g_value_init (&one, G_TYPE_DOUBLE);
275   g_value_set_double (&zero, 0.0);
276   g_value_set_double (&one, 1.0);
277
278   GST_LOG ("setting values on controller");
279
280   gst_interpolation_control_source_unset_all (self->priv->a_control_source);
281   gst_interpolation_control_source_set (self->priv->a_control_source, 0, &one);
282   gst_interpolation_control_source_set (self->priv->a_control_source,
283       duration, &zero);
284
285   gst_interpolation_control_source_unset_all (self->priv->b_control_source);
286   gst_interpolation_control_source_set (self->priv->b_control_source, 0, &zero);
287   gst_interpolation_control_source_set (self->priv->b_control_source, duration,
288       &one);
289
290   GST_LOG ("done updating controller");
291 }
292
293 /**
294  * ges_track_audio_transition_new:
295  *
296  * Creates a new #GESTrackAudioTransition.
297  *
298  * Returns: The newly created #GESTrackAudioTransition.
299  */
300 GESTrackAudioTransition *
301 ges_track_audio_transition_new (void)
302 {
303   return g_object_new (GES_TYPE_TRACK_AUDIO_TRANSITION, NULL);
304 }