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