Fix #337365 (g_type_class_ref <-> g_type_class_peek_parent)
[platform/upstream/gstreamer.git] / ext / mikmod / gstmikmod.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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include "gstmikmod.h"
24
25 #include <stdlib.h>
26
27 /* elementfactory information */
28 GstElementDetails mikmod_details = GST_ELEMENT_DETAILS ("MikMod audio decoder",
29     "Codec/Decoder/Audio",
30     "Module decoder based on libmikmod",
31     "Jeremy SIMON <jsimon13@yahoo.fr>");
32
33
34 /* Filter signals and args */
35 enum
36 {
37   /* FILL ME */
38   LAST_SIGNAL
39 };
40
41 enum
42 {
43   ARG_0,
44   ARG_SONGNAME,
45   ARG_MODTYPE,
46   ARG_MUSICVOLUME,
47   ARG_PANSEP,
48   ARG_REVERB,
49   ARG_SNDFXVOLUME,
50   ARG_VOLUME,
51   ARG_INTERP,
52   ARG_REVERSE,
53   ARG_SURROUND,
54   ARG_HQMIXER,
55   ARG_SOFT_MUSIC,
56   ARG_SOFT_SNDFX
57 };
58
59 MODULE *module;
60 MREADER *reader;
61 GstPad *srcpad;
62 GstClockTime timestamp;
63 int need_sync;
64
65 static GstStaticPadTemplate mikmod_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
66     GST_PAD_SRC,
67     GST_PAD_ALWAYS,
68     GST_STATIC_CAPS ("audio/x-raw-int, "
69         "endianness = (int) BYTE_ORDER, "
70         "signed = (boolean) TRUE, "
71         "width = (int) 16, "
72         "depth = (int) 16, "
73         "rate = (int) { 8000, 11025, 22050, 44100 }, "
74         "channels = (int) [ 1, 2 ]; "
75         "audio/x-raw-int, "
76         "endianness = (int) BYTE_ORDER, "
77         "signed = (boolean) FALSE, "
78         "width = (int) 8, "
79         "depth = (int) 8, "
80         "rate = (int) { 8000, 11025, 22050, 44100 }, "
81         "channels = (int) [ 1, 2 ]")
82     );
83
84 static GstStaticPadTemplate mikmod_sink_factory =
85 GST_STATIC_PAD_TEMPLATE ("sink",
86     GST_PAD_SINK,
87     GST_PAD_ALWAYS,
88     GST_STATIC_CAPS ("audio/x-mod")
89     );
90
91 static void gst_mikmod_base_init (gpointer g_class);
92 static void gst_mikmod_class_init (GstMikModClass * klass);
93 static void gst_mikmod_init (GstMikMod * filter);
94 static void gst_mikmod_set_property (GObject * object, guint id,
95     const GValue * value, GParamSpec * pspec);
96 static void gst_mikmod_get_property (GObject * object, guint id, GValue * value,
97     GParamSpec * pspec);
98 static GstPadLinkReturn gst_mikmod_srclink (GstPad * pad, const GstCaps * caps);
99 static GstCaps *gst_mikmod_srcfixate (GstPad * pad, const GstCaps * caps);
100 static void gst_mikmod_loop (GstElement * element);
101 static gboolean gst_mikmod_setup (GstMikMod * mikmod);
102 static GstStateChangeReturn gst_mikmod_change_state (GstElement * element,
103     GstStateChange transition);
104
105
106
107 static GstElementClass *parent_class = NULL;
108
109 GType
110 gst_mikmod_get_type (void)
111 {
112   static GType mikmod_type = 0;
113
114   if (!mikmod_type) {
115     static const GTypeInfo mikmod_info = {
116       sizeof (GstMikModClass),
117       gst_mikmod_base_init,
118       NULL,
119       (GClassInitFunc) gst_mikmod_class_init,
120       NULL,
121       NULL,
122       sizeof (GstMikMod),
123       0,
124       (GInstanceInitFunc) gst_mikmod_init,
125     };
126
127     mikmod_type =
128         g_type_register_static (GST_TYPE_ELEMENT, "GstMikmod", &mikmod_info, 0);
129   }
130   return mikmod_type;
131 }
132
133 static void
134 gst_mikmod_base_init (gpointer g_class)
135 {
136   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
137
138   gst_element_class_add_pad_template (element_class,
139       gst_static_pad_template_get (&mikmod_src_factory));
140   gst_element_class_add_pad_template (element_class,
141       gst_static_pad_template_get (&mikmod_sink_factory));
142   gst_element_class_set_details (element_class, &mikmod_details);
143 }
144
145 static void
146 gst_mikmod_class_init (GstMikModClass * klass)
147 {
148   GObjectClass *gobject_class;
149   GstElementClass *gstelement_class;
150
151   gobject_class = (GObjectClass *) klass;
152   gstelement_class = (GstElementClass *) klass;
153
154   parent_class = g_type_class_peek_parent (klass);
155
156   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SONGNAME,
157       g_param_spec_string ("songname", "songname", "songname",
158           NULL, G_PARAM_READABLE));
159   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MODTYPE,
160       g_param_spec_string ("modtype", "modtype", "modtype",
161           NULL, G_PARAM_READABLE));
162   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MUSICVOLUME,
163       g_param_spec_int ("musicvolume", "musivolume", "musicvolume",
164           0, 128, 128, G_PARAM_READWRITE));
165   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PANSEP,
166       g_param_spec_int ("pansep", "pansep", "pansep",
167           0, 128, 128, G_PARAM_READWRITE));
168   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_REVERB,
169       g_param_spec_int ("reverb", "reverb", "reverb",
170           0, 15, 0, G_PARAM_READWRITE));
171   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SNDFXVOLUME,
172       g_param_spec_int ("sndfxvolume", "sndfxvolume", "sndfxvolume",
173           0, 128, 128, G_PARAM_READWRITE));
174   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VOLUME,
175       g_param_spec_int ("volume", "volume", "volume",
176           0, 128, 96, G_PARAM_READWRITE));
177
178   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_INTERP,
179       g_param_spec_boolean ("interp", "interp", "interp",
180           FALSE, G_PARAM_READWRITE));
181   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_REVERSE,
182       g_param_spec_boolean ("reverse", "reverse", "reverse",
183           FALSE, G_PARAM_READWRITE));
184   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SURROUND,
185       g_param_spec_boolean ("surround", "surround", "surround",
186           TRUE, G_PARAM_READWRITE));
187   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HQMIXER,
188       g_param_spec_boolean ("hqmixer", "hqmixer", "hqmixer",
189           FALSE, G_PARAM_READWRITE));
190   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SOFT_MUSIC,
191       g_param_spec_boolean ("soft_music", "soft_music", "soft_music",
192           TRUE, G_PARAM_READWRITE));
193   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SOFT_SNDFX,
194       g_param_spec_boolean ("soft_sndfx", "soft_sndfx", "soft_sndfx",
195           TRUE, G_PARAM_READWRITE));
196
197
198   gobject_class->set_property = gst_mikmod_set_property;
199   gobject_class->get_property = gst_mikmod_get_property;
200
201   gstelement_class->change_state = gst_mikmod_change_state;
202 }
203
204
205 static void
206 gst_mikmod_init (GstMikMod * filter)
207 {
208   filter->sinkpad =
209       gst_pad_new_from_static_template (&mikmod_sink_factory, "sink");
210   filter->srcpad =
211       gst_pad_new_from_static_template (&mikmod_src_factory, "src");
212
213   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
214   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
215   gst_pad_set_link_function (filter->srcpad, gst_mikmod_srclink);
216   gst_pad_set_fixate_function (filter->srcpad, gst_mikmod_srcfixate);
217
218   gst_element_set_loop_function (GST_ELEMENT (filter), gst_mikmod_loop);
219
220   filter->Buffer = NULL;
221
222   filter->stereo = TRUE;
223   filter->surround = TRUE;
224   filter->_16bit = TRUE;
225   filter->soft_music = TRUE;
226   filter->soft_sndfx = TRUE;
227   filter->mixfreq = 44100;
228   filter->reverb = 0;
229   filter->pansep = 128;
230   filter->musicvolume = 128;
231   filter->volume = 96;
232   filter->sndfxvolume = 128;
233   filter->songname = NULL;
234   filter->modtype = NULL;
235
236   filter->initialized = FALSE;
237 }
238
239 static GstCaps *
240 gst_mikmod_srcfixate (GstPad * pad, const GstCaps * caps)
241 {
242   GstCaps *ret;
243   GstStructure *structure;
244
245   /* FIXME: select est caps here */
246   if (gst_caps_get_size (caps) > 1)
247     return NULL;
248
249   ret = gst_caps_copy (caps);
250   structure = gst_caps_get_structure (ret, 0);
251
252   if (gst_structure_fixate_field_nearest_int (structure, "channels", 2))
253     return ret;
254   if (gst_structure_fixate_field_nearest_int (structure, "rate", 44100))
255     return ret;
256
257   gst_caps_free (ret);
258   return NULL;
259 }
260
261 static GstPadLinkReturn
262 gst_mikmod_srclink (GstPad * pad, const GstCaps * caps)
263 {
264   GstMikMod *filter;
265   GstStructure *structure;
266   gint depth;
267   gint channels;
268   gboolean result;
269
270   filter = GST_MIKMOD (gst_pad_get_parent (pad));
271
272   structure = gst_caps_get_structure (caps, 0);
273
274   gst_structure_get_int (structure, "depth", &depth);
275   filter->_16bit = (depth == 16);
276   gst_structure_get_int (structure, "channels", &channels);
277   filter->stereo = (channels == 2);
278   gst_structure_get_int (structure, "rate", &filter->mixfreq);
279
280   result = gst_mikmod_setup (filter);
281   gst_object_unref (filter);
282
283   if (result) {
284     return GST_PAD_LINK_OK;
285   } else {
286     return GST_PAD_LINK_REFUSED;
287   }
288 }
289
290 static void
291 gst_mikmod_loop (GstElement * element)
292 {
293   GstMikMod *mikmod;
294   GstBuffer *buffer_in;
295
296   g_return_if_fail (element != NULL);
297   g_return_if_fail (GST_IS_MIKMOD (element));
298
299   mikmod = GST_MIKMOD (element);
300   srcpad = mikmod->srcpad;
301   mikmod->Buffer = NULL;
302
303   if (!mikmod->initialized) {
304     while ((buffer_in = GST_BUFFER (gst_pad_pull (mikmod->sinkpad)))) {
305       if (GST_IS_EVENT (buffer_in)) {
306         GstEvent *event = GST_EVENT (buffer_in);
307
308         if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)
309           break;
310       } else {
311         if (mikmod->Buffer) {
312           GstBuffer *merge;
313
314           merge = gst_buffer_merge (mikmod->Buffer, buffer_in);
315           gst_buffer_unref (buffer_in);
316           gst_buffer_unref (mikmod->Buffer);
317           mikmod->Buffer = merge;
318         } else {
319           mikmod->Buffer = buffer_in;
320         }
321       }
322     }
323
324     if (!GST_PAD_CAPS (mikmod->srcpad)) {
325       if (GST_PAD_LINK_SUCCESSFUL (gst_pad_renegotiate (mikmod->srcpad))) {
326         GST_ELEMENT_ERROR (mikmod, CORE, NEGOTIATION, (NULL), (NULL));
327         return;
328       }
329     }
330
331     MikMod_RegisterDriver (&drv_gst);
332     MikMod_RegisterAllLoaders ();
333
334     MikMod_Init ("");
335     reader = GST_READER_new (mikmod);
336     module = Player_LoadGeneric (reader, 64, 0);
337
338     gst_buffer_unref (mikmod->Buffer);
339
340     if (!Player_Active ())
341       Player_Start (module);
342
343     mikmod->initialized = TRUE;
344   }
345
346   if (Player_Active ()) {
347     timestamp = (module->sngtime / 1024.0) * GST_SECOND;
348     drv_gst.Update ();
349   } else {
350     gst_element_set_eos (GST_ELEMENT (mikmod));
351     gst_pad_push (mikmod->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
352   }
353 }
354
355
356 static gboolean
357 gst_mikmod_setup (GstMikMod * mikmod)
358 {
359   md_musicvolume = mikmod->musicvolume;
360   md_pansep = mikmod->pansep;
361   md_reverb = mikmod->reverb;
362   md_sndfxvolume = mikmod->sndfxvolume;
363   md_volume = mikmod->volume;
364   md_mixfreq = mikmod->mixfreq;
365
366   md_mode = 0;
367
368   if (mikmod->interp)
369     md_mode = md_mode | DMODE_INTERP;
370
371   if (mikmod->reverse)
372     md_mode = md_mode | DMODE_REVERSE;
373
374   if (mikmod->surround)
375     md_mode = md_mode | DMODE_SURROUND;
376
377   if (mikmod->_16bit)
378     md_mode = md_mode | DMODE_16BITS;
379
380   if (mikmod->hqmixer)
381     md_mode = md_mode | DMODE_HQMIXER;
382
383   if (mikmod->soft_music)
384     md_mode = md_mode | DMODE_SOFT_MUSIC;
385
386   if (mikmod->soft_sndfx)
387     md_mode = md_mode | DMODE_SOFT_SNDFX;
388
389   if (mikmod->stereo)
390     md_mode = md_mode | DMODE_STEREO;
391
392   return TRUE;
393 }
394
395
396 static GstStateChangeReturn
397 gst_mikmod_change_state (GstElement * element, GstStateChange transition)
398 {
399   GstMikMod *mikmod;
400
401   g_return_val_if_fail (GST_IS_MIKMOD (element), GST_STATE_CHANGE_FAILURE);
402
403   mikmod = GST_MIKMOD (element);
404
405   GST_DEBUG ("state pending %d", GST_STATE_PENDING (element));
406
407   if (GST_STATE_PENDING (element) == GST_STATE_READY) {
408     gst_mikmod_setup (mikmod);
409
410     if (Player_Active ()) {
411       Player_TogglePause ();
412       Player_SetPosition (0);
413     }
414     mikmod->initialized = FALSE;
415   }
416
417   if (GST_STATE_PENDING (element) == GST_STATE_PLAYING) {
418     if (Player_Active () && Player_Paused ())
419       Player_TogglePause ();
420     else if (!Player_Active ())
421       Player_Start (module);
422
423   }
424
425   if (GST_STATE_PENDING (element) == GST_STATE_PAUSED)
426     if (Player_Active () && !Player_Paused ())
427       Player_TogglePause ();
428
429   if (GST_STATE_PENDING (element) == GST_STATE_NULL)
430     MikMod_Exit ();
431
432
433   if (GST_ELEMENT_CLASS (parent_class)->change_state)
434     return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
435
436   return GST_STATE_CHANGE_SUCCESS;
437 }
438
439
440
441 static void
442 gst_mikmod_set_property (GObject * object, guint id, const GValue * value,
443     GParamSpec * pspec)
444 {
445   GstMikMod *filter;
446
447   g_return_if_fail (GST_IS_MIKMOD (object));
448   filter = GST_MIKMOD (object);
449
450   switch (id) {
451     case ARG_SONGNAME:
452       g_free (filter->songname);
453       filter->songname = g_strdup (g_value_get_string (value));
454       break;
455     case ARG_MODTYPE:
456       g_free (filter->modtype);
457       filter->modtype = g_strdup (g_value_get_string (value));
458       break;
459     case ARG_MUSICVOLUME:
460       filter->musicvolume = g_value_get_int (value);
461       break;
462     case ARG_PANSEP:
463       filter->pansep = g_value_get_int (value);
464       break;
465     case ARG_REVERB:
466       filter->reverb = g_value_get_int (value);
467       break;
468     case ARG_SNDFXVOLUME:
469       filter->sndfxvolume = g_value_get_int (value);
470       break;
471     case ARG_VOLUME:
472       filter->volume = g_value_get_int (value);
473       break;
474     case ARG_INTERP:
475       filter->interp = g_value_get_boolean (value);
476       break;
477     case ARG_REVERSE:
478       filter->reverse = g_value_get_boolean (value);
479       break;
480     case ARG_SURROUND:
481       filter->surround = g_value_get_boolean (value);
482       break;
483     case ARG_HQMIXER:
484       filter->hqmixer = g_value_get_boolean (value);
485       break;
486     case ARG_SOFT_MUSIC:
487       filter->soft_music = g_value_get_boolean (value);
488       break;
489     case ARG_SOFT_SNDFX:
490       filter->soft_sndfx = g_value_get_boolean (value);
491       break;
492     default:
493       break;
494   }
495 }
496
497 static void
498 gst_mikmod_get_property (GObject * object, guint id, GValue * value,
499     GParamSpec * pspec)
500 {
501   GstMikMod *filter;
502
503   g_return_if_fail (GST_IS_MIKMOD (object));
504   filter = GST_MIKMOD (object);
505
506   switch (id) {
507     case ARG_MUSICVOLUME:
508       g_value_set_int (value, filter->musicvolume);
509       break;
510     case ARG_PANSEP:
511       g_value_set_int (value, filter->pansep);
512       break;
513     case ARG_REVERB:
514       g_value_set_int (value, filter->reverb);
515       break;
516     case ARG_SNDFXVOLUME:
517       g_value_set_int (value, filter->sndfxvolume);
518       break;
519     case ARG_VOLUME:
520       g_value_set_int (value, filter->volume);
521       break;
522     case ARG_INTERP:
523       g_value_set_boolean (value, filter->interp);
524       break;
525     case ARG_REVERSE:
526       g_value_set_boolean (value, filter->reverse);
527       break;
528     case ARG_SURROUND:
529       g_value_set_boolean (value, filter->surround);
530       break;
531     case ARG_HQMIXER:
532       g_value_set_boolean (value, filter->hqmixer);
533       break;
534     case ARG_SOFT_MUSIC:
535       g_value_set_boolean (value, filter->soft_music);
536       break;
537     case ARG_SOFT_SNDFX:
538       g_value_set_boolean (value, filter->soft_sndfx);
539       break;
540     default:
541       break;
542   }
543 }
544
545 static gboolean
546 plugin_init (GstPlugin * plugin)
547 {
548   if (!gst_element_register (plugin, "mikmod", GST_RANK_SECONDARY,
549           GST_TYPE_MIKMOD))
550     return FALSE;
551
552   return TRUE;
553 }
554
555 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
556     GST_VERSION_MINOR,
557     "mikmod",
558     "Mikmod plugin library",
559     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)