configure.ac: say what CHECK flags we use
[platform/upstream/gstreamer.git] / libs / gst / controller / gstinterpolation.c
1 /* GStreamer
2  *
3  * Copyright (C) <2005> Stefan Kost <ensonic at users dot sf dot net>
4  *
5  * gstinterpolation.c: Interpolation methods for dynamic properties
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24 #include "gstcontroller.h"
25
26 #define GST_CAT_DEFAULT gst_controller_debug
27 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_DEFAULT);
28
29 /* common helper */
30
31 /*
32  * gst_controlled_property_find_timed_value_node:
33  * @prop: the controlled property to search in
34  * @timestamp: the search key
35  *
36  * Find last value before given timestamp in timed value list.
37  *
38  * Returns: the found #GList node or %NULL
39  */
40 GList *
41 gst_controlled_property_find_timed_value_node (GstControlledProperty * prop,
42     GstClockTime timestamp)
43 {
44   //GList *prev_node = NULL;
45   GList *prev_node = g_list_last (prop->values);
46   GList *node;
47   GstTimedValue *tv;
48
49   /*
50      if((prop->last_value) &&
51      (timestamp>((GstTimedValue *)(prop->last_value->data))->timestamp)) {
52      node=prop->last_value;
53      }
54      else {
55      node=prop->values;
56      }
57    */
58
59   /* iterate over timed value list */
60   for (node = prop->values; node; node = g_list_next (node)) {
61     tv = node->data;
62     /* this timestamp is newer that the one we look for */
63     if (timestamp < tv->timestamp) {
64       /* get previous one again */
65       prev_node = g_list_previous (node);
66       break;
67     }
68   }
69   /*
70      if(node) {
71      prop->last_value=prev_node;
72      }
73    */
74   return (prev_node);
75 }
76
77 // steps-like (no-)interpolation, default
78 // just returns the value for the most recent key-frame
79
80 static GValue *
81 interpolate_none_get (GstControlledProperty * prop, GstClockTime timestamp)
82 {
83   GList *node;
84
85   if ((node = gst_controlled_property_find_timed_value_node (prop, timestamp))) {
86     GstTimedValue *tv = node->data;
87
88     return (&tv->value);
89   }
90   return (&prop->default_value);
91 }
92
93 #define DEFINE_NONE_GET(type) \
94 static gboolean \
95 interpolate_none_get_##type##_value_array (GstControlledProperty * prop, \
96     GstClockTime timestamp, GstValueArray * value_array) \
97 { \
98   gint i; \
99   GstClockTime ts=timestamp; \
100   g##type *values=(g##type *)value_array->values; \
101   \
102   for(i=0;i<value_array->nbsamples;i++) { \
103     *values=g_value_get_##type (interpolate_none_get (prop,ts)); \
104     ts+=value_array->sample_interval; \
105     values++; \
106   } \
107   return (TRUE); \
108 }
109
110 DEFINE_NONE_GET (int)
111     DEFINE_NONE_GET (long)
112 DEFINE_NONE_GET (float)
113 DEFINE_NONE_GET (double)
114 DEFINE_NONE_GET (boolean)
115
116      static GstInterpolateMethod interpolate_none = {
117        interpolate_none_get,
118        interpolate_none_get_int_value_array,
119        interpolate_none_get,
120        interpolate_none_get_long_value_array,
121        interpolate_none_get,
122        interpolate_none_get_float_value_array,
123        interpolate_none_get,
124        interpolate_none_get_double_value_array,
125        interpolate_none_get,
126        interpolate_none_get_boolean_value_array
127      };
128
129 // returns the default value of the property, except for times with specific values
130 // needed for one-shot events, such as notes and triggers
131
132 static GValue *
133 interpolate_trigger_get (GstControlledProperty * prop, GstClockTime timestamp)
134 {
135   GList *node;
136   GstTimedValue *tv;
137
138   /* check if there is a value at the registered timestamp */
139   for (node = prop->values; node; node = g_list_next (node)) {
140     tv = node->data;
141     if (timestamp == tv->timestamp) {
142       return (&tv->value);
143     }
144   }
145
146   return (&prop->default_value);
147 }
148
149 static gboolean
150 interpolate_trigger_get_value_array (GstControlledProperty * prop,
151     GstClockTime timestamp, GstValueArray * value_array)
152 {
153   return (FALSE);
154 }
155
156 static GstInterpolateMethod interpolate_trigger = {
157   interpolate_trigger_get,
158   interpolate_trigger_get_value_array,
159   interpolate_trigger_get,
160   NULL,
161   interpolate_trigger_get,
162   NULL,
163   interpolate_trigger_get,
164   NULL,
165   interpolate_trigger_get,
166   NULL
167 };
168
169 // linear interpolation
170 // smoothes inbetween values
171
172 #define DEFINE_LINEAR_GET(type) \
173 static g##type \
174 _interpolate_linear_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
175 { \
176   GList *node; \
177   \
178   if ((node = gst_controlled_property_find_timed_value_node (prop, timestamp))) { \
179     GstTimedValue *tv1, *tv2; \
180     \
181     tv1 = node->data; \
182     if ((node = g_list_next (node))) { \
183       gdouble timediff,valuediff; \
184       g##type value1,value2; \
185       \
186       tv2 = node->data; \
187       \
188       timediff = (gdouble)(tv2->timestamp - tv1->timestamp); \
189       value1 = g_value_get_##type (&tv1->value); \
190       value2 = g_value_get_##type (&tv2->value); \
191       valuediff = (gdouble)(value2-value1); \
192       \
193       return((g##type)(value1+valuediff*((timestamp-tv1->timestamp)/timediff))); \
194     } \
195     else { \
196       return (g_value_get_##type (&tv1->value)); \
197     } \
198   } \
199   return (g_value_get_##type (&prop->default_value)); \
200 } \
201 \
202 static GValue * \
203 interpolate_linear_get_##type (GstControlledProperty * prop, GstClockTime timestamp) \
204 { \
205   g_value_set_##type (&prop->result_value,_interpolate_linear_get_##type (prop,timestamp)); \
206   return (&prop->result_value); \
207 } \
208 \
209 static gboolean \
210 interpolate_linear_get_##type##_value_array (GstControlledProperty * prop, \
211     GstClockTime timestamp, GstValueArray * value_array) \
212 { \
213   gint i; \
214   GstClockTime ts=timestamp; \
215   gint *values=(gint *)value_array->values; \
216   \
217   for(i=0;i<value_array->nbsamples;i++) { \
218     *values=_interpolate_linear_get_##type (prop,ts); \
219     ts+=value_array->sample_interval; \
220     values++; \
221   } \
222   return (TRUE); \
223 }
224
225 DEFINE_LINEAR_GET (int)
226 DEFINE_LINEAR_GET (long)
227 DEFINE_LINEAR_GET (float)
228 DEFINE_LINEAR_GET (double)
229
230      static GstInterpolateMethod interpolate_linear = {
231        interpolate_linear_get_int,
232        interpolate_linear_get_int_value_array,
233        interpolate_linear_get_long,
234        interpolate_linear_get_long_value_array,
235        interpolate_linear_get_float,
236        interpolate_linear_get_float_value_array,
237        interpolate_linear_get_double,
238        interpolate_linear_get_double_value_array,
239        NULL,
240        NULL
241      };
242
243 // square interpolation
244
245 // cubic interpolation
246
247 // register all interpolation methods
248 GstInterpolateMethod *interpolation_methods[] = {
249   &interpolate_none,
250   &interpolate_trigger,
251   &interpolate_linear,
252   NULL,
253   NULL
254 };