backmerge
[platform/upstream/gstreamer.git] / gst / audioscale / gstaudioscale.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include <string.h>
22 #include <math.h>
23
24 /*#define DEBUG_ENABLED */
25 #include <gstaudioscale.h>
26 #include <gst/audio/audio.h>
27 #include <gst/resample/resample.h>
28
29 /* elementfactory information */
30 static GstElementDetails audioscale_details = {
31   "Audio scaler",
32   "Filter/Audio",
33   "LGPL",
34   "Audio resampler",
35   VERSION,
36   "Wim Taymans <wim.taymans@chello.be>",
37   "(C) 2000",
38 };
39
40 /* Audioscale signals and args */
41 enum {
42   /* FILL ME */
43   LAST_SIGNAL
44 };
45
46 enum {
47   ARG_0,
48   ARG_FREQUENCY,
49   ARG_FILTERLEN,
50   ARG_METHOD,
51   /* FILL ME */
52 };
53
54 static GstPadTemplate *
55 sink_template (void)
56 {
57   static GstPadTemplate *template = NULL;
58
59   if (!template) {
60     template = gst_pad_template_new ("sink",
61                                     GST_PAD_SINK,
62                                     GST_PAD_ALWAYS,
63                                     gst_caps_new
64                                     ("audioscale_sink",
65                                      "audio/raw", GST_AUDIO_INT_PAD_TEMPLATE_PROPS), NULL);
66   }
67   return template;
68 }
69
70 static GstPadTemplate *
71 src_template (void)
72 {
73   static GstPadTemplate *template = NULL;
74
75   if (!template) {
76     template = gst_pad_template_new ("src",
77                                     GST_PAD_SRC,
78                                     GST_PAD_ALWAYS,
79                                     gst_caps_new
80                                     ("audioscale_src",
81                                      "audio/raw", GST_AUDIO_INT_PAD_TEMPLATE_PROPS), NULL);
82   }
83   return template;
84 }
85
86 #define GST_TYPE_AUDIOSCALE_METHOD (gst_audioscale_method_get_type())
87 static GType
88 gst_audioscale_method_get_type (void)
89 {
90   static GType audioscale_method_type = 0;
91   static GEnumValue audioscale_methods[] = {
92     { RESAMPLE_NEAREST,  "0", "Nearest" },
93     { RESAMPLE_BILINEAR, "1", "Bilinear" },
94     { RESAMPLE_SINC,     "2", "Sinc" },
95     { 0, NULL, NULL },
96   };
97   if(!audioscale_method_type){
98     audioscale_method_type = g_enum_register_static("GstAudioscaleMethod",
99                                                     audioscale_methods);
100   }
101   return audioscale_method_type;
102 }
103
104 static void     gst_audioscale_class_init       (AudioscaleClass *klass);
105 static void     gst_audioscale_init             (Audioscale *audioscale);
106
107 static void     gst_audioscale_chain            (GstPad *pad, GstBuffer *buf);
108
109 static void gst_audioscale_set_property (GObject * object, guint prop_id,
110                                          const GValue * value, GParamSpec * pspec);
111 static void gst_audioscale_get_property (GObject * object, guint prop_id,
112                                          GValue * value, GParamSpec * pspec);
113
114 static GstElementClass *parent_class = NULL;
115
116 /*static guint gst_audioscale_signals[LAST_SIGNAL] = { 0 }; */
117
118 GType
119 audioscale_get_type (void)
120 {
121   static GType audioscale_type = 0;
122
123   if (!audioscale_type) {
124     static const GTypeInfo audioscale_info = {
125       sizeof(AudioscaleClass),      NULL,
126       NULL,
127       (GClassInitFunc)gst_audioscale_class_init,
128       NULL,
129       NULL,
130       sizeof(Audioscale),
131       0,
132       (GInstanceInitFunc)gst_audioscale_init,
133     };
134     audioscale_type = g_type_register_static(GST_TYPE_ELEMENT, "Audioscale", &audioscale_info, 0);
135   }
136   return audioscale_type;
137 }
138
139 static void
140 gst_audioscale_class_init (AudioscaleClass *klass)
141 {
142   GObjectClass *gobject_class;
143   GstElementClass *gstelement_class;
144
145   gobject_class = (GObjectClass*)klass;
146   gstelement_class = (GstElementClass*)klass;
147
148   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FREQUENCY,
149         g_param_spec_int ("frequency","frequency","frequency",
150                           0,G_MAXINT,44100,G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
151   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FILTERLEN,
152         g_param_spec_int ("filter_length", "filter_length", "filter_length",
153                           0, G_MAXINT, 16, G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
154   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METHOD,
155         g_param_spec_enum ("method", "method", "method", GST_TYPE_AUDIOSCALE_METHOD,
156                            RESAMPLE_SINC, G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
157
158   parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
159
160   gobject_class->set_property = gst_audioscale_set_property;
161   gobject_class->get_property = gst_audioscale_get_property;
162
163 }
164
165 static GstPadConnectReturn
166 gst_audioscale_sinkconnect (GstPad * pad, GstCaps * caps)
167 {
168   Audioscale *audioscale;
169   resample_t *r;
170   GstCaps *newcaps;
171   gint rate;
172
173   audioscale = GST_AUDIOSCALE (gst_pad_get_parent (pad));
174   r = audioscale->resample;
175
176   gst_caps_get_int (caps, "rate",     &rate);
177   gst_caps_get_int (caps, "channels", &r->channels);
178
179   r->i_rate = rate;
180   
181   resample_reinit(r);
182   
183   newcaps = gst_caps_copy (caps);
184   gst_caps_set (newcaps, "rate", GST_PROPS_INT_TYPE, audioscale->targetfrequency, NULL);
185
186   if (GST_CAPS_IS_FIXED (caps))
187     return gst_pad_try_set_caps (audioscale->srcpad, newcaps);
188   else
189     return GST_PAD_CONNECT_DELAYED;
190 }
191
192 static void *
193 gst_audioscale_get_buffer (void *priv, unsigned int size)
194 {
195   Audioscale * audioscale = priv;
196
197   audioscale->outbuf = gst_buffer_new();
198   GST_BUFFER_SIZE(audioscale->outbuf) = size;
199   GST_BUFFER_DATA(audioscale->outbuf) = g_malloc(size);
200   GST_BUFFER_TIMESTAMP(audioscale->outbuf) = audioscale->offset * GST_SECOND / audioscale->targetfrequency;
201   audioscale->offset += size / sizeof(gint16) / audioscale->resample->channels;
202
203   return GST_BUFFER_DATA(audioscale->outbuf);
204 }
205
206 static void
207 gst_audioscale_init (Audioscale *audioscale)
208 {
209   resample_t *r;
210
211   audioscale->sinkpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (sink_template), "sink");
212   gst_element_add_pad(GST_ELEMENT(audioscale),audioscale->sinkpad);
213   gst_pad_set_chain_function(audioscale->sinkpad,gst_audioscale_chain);
214   gst_pad_set_connect_function (audioscale->sinkpad, gst_audioscale_sinkconnect);
215
216   audioscale->srcpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (src_template), "src");
217
218   gst_element_add_pad(GST_ELEMENT(audioscale),audioscale->srcpad);
219
220   r = g_new0(resample_t,1);
221   audioscale->resample = r;
222
223   r->priv = audioscale;
224   r->get_buffer = gst_audioscale_get_buffer;
225   r->method = RESAMPLE_SINC;
226   r->channels = 0;
227   r->filter_length = 16;
228   r->i_rate = -1;
229   r->o_rate = -1;
230   r->format = RESAMPLE_S16;
231   /*r->verbose = 1; */
232
233   resample_init(r);
234
235   /* we will be reinitialized when the G_PARAM_CONSTRUCTs hit */
236 }
237
238 static void
239 gst_audioscale_chain (GstPad *pad, GstBuffer *buf)
240 {
241   Audioscale *audioscale;
242   guchar *data;
243   gulong size;
244
245   g_return_if_fail(pad != NULL);
246   g_return_if_fail(GST_IS_PAD(pad));
247   g_return_if_fail(buf != NULL);
248
249   audioscale = GST_AUDIOSCALE (gst_pad_get_parent (pad));
250   data = GST_BUFFER_DATA(buf);
251   size = GST_BUFFER_SIZE(buf);
252
253   GST_DEBUG (0,
254              "gst_audioscale_chain: got buffer of %ld bytes in '%s'\n",
255              size, gst_element_get_name (GST_ELEMENT (audioscale)));
256
257
258   resample_scale (audioscale->resample, data, size);
259
260   gst_pad_push (audioscale->srcpad, audioscale->outbuf);
261
262   gst_buffer_unref (buf);
263 }
264
265 static void
266 gst_audioscale_set_property (GObject * object, guint prop_id,
267                              const GValue * value, GParamSpec * pspec)
268 {
269   Audioscale *src;
270   resample_t *r;
271
272   /* it's not null if we got it, but it might not be ours */
273   g_return_if_fail(GST_IS_AUDIOSCALE(object));
274   src = GST_AUDIOSCALE(object);
275   r = src->resample;
276
277   switch (prop_id) {
278     case ARG_FREQUENCY:
279       src->targetfrequency = g_value_get_int (value);
280       r->o_rate = src->targetfrequency;
281       break;
282     case ARG_FILTERLEN:
283       r->filter_length = g_value_get_int (value);
284       GST_DEBUG_ELEMENT (0, GST_ELEMENT(src), "new filter length %d\n", r->filter_length);
285       break;
286     case ARG_METHOD:
287       r->method = g_value_get_enum (value);
288       break;
289     default:
290       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
291       break;
292   }
293
294   resample_reinit (r);
295 }
296
297 static void
298 gst_audioscale_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
299 {
300   Audioscale *src;
301   resample_t *r;
302
303   src = GST_AUDIOSCALE (object);
304   r = src->resample;
305
306   switch (prop_id) {
307     case ARG_FREQUENCY:
308       g_value_set_int (value, src->targetfrequency);
309       break;
310     case ARG_FILTERLEN:
311       g_value_set_int (value, r->filter_length);
312       break;
313     case ARG_METHOD:
314       g_value_set_enum (value, r->method);
315       break;
316     default:
317       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
318       break;
319   }
320 }
321
322
323 static gboolean
324 plugin_init (GModule *module, GstPlugin *plugin)
325 {
326   GstElementFactory *factory;
327
328   /* create an elementfactory for the audioscale element */
329   factory = gst_element_factory_new ("audioscale", GST_TYPE_AUDIOSCALE, &audioscale_details);
330   g_return_val_if_fail(factory != NULL, FALSE);
331   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
332
333   /* load support library */
334   if (!gst_library_load ("gstresample"))
335     return FALSE;
336
337   return TRUE;
338 }
339
340 GstPluginDesc plugin_desc = {
341   GST_VERSION_MAJOR,
342   GST_VERSION_MINOR,
343   "audioscale",
344   plugin_init
345 };