57fa9bb2935ee8e8a6ce1a4fafaa20963d568eec
[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 <gst/audio/audio.h>
26 #include <stdlib.h>
27
28 /* elementfactory information */
29 GstElementDetails mikmod_details = {
30   "MikMod",
31   "Codec/Decoder/Audio",
32   "Module decoder based on libmikmod",
33   "Jeremy SIMON <jsimon13@yahoo.fr>",
34 };
35
36
37 /* Filter signals and args */
38 enum {
39   /* FILL ME */
40   LAST_SIGNAL
41 };
42
43 enum {
44   ARG_0,
45   ARG_SONGNAME,
46   ARG_MODTYPE,
47   ARG_MUSICVOLUME,
48   ARG_PANSEP,
49   ARG_REVERB,
50   ARG_SNDFXVOLUME,
51   ARG_VOLUME,
52   ARG_INTERP,
53   ARG_REVERSE,
54   ARG_SURROUND,
55   ARG_HQMIXER,
56   ARG_SOFT_MUSIC,
57   ARG_SOFT_SNDFX
58 };
59
60
61 static GstPadTemplate*
62 mikmod_src_factory (void)
63 {
64   static GstPadTemplate *template = NULL;
65
66   if (!template) {
67     template = gst_pad_template_new (
68       "src",
69       GST_PAD_SRC,
70       GST_PAD_ALWAYS,
71       gst_caps_new (
72         "mikmod_src",
73         "audio/x-raw-int",
74           GST_AUDIO_INT_PAD_TEMPLATE_PROPS
75       ), NULL);
76   }
77   return template;
78 }
79
80
81 static GstPadTemplate*
82 mikmod_sink_factory (void)
83 {
84   static GstPadTemplate *template = NULL;
85
86   if (!template) {
87     template = gst_pad_template_new (
88       "sink",
89       GST_PAD_SINK,
90       GST_PAD_ALWAYS,
91       gst_caps_new (
92         "mikmod_sink",
93         "audio/x-mod",
94         NULL),NULL        
95       );
96   }
97   return template;
98 }
99
100 static void             gst_mikmod_base_init            (gpointer g_class);
101 static void             gst_mikmod_class_init           (GstMikModClass *klass);
102 static void             gst_mikmod_init                 (GstMikMod *filter);
103 static void             gst_mikmod_set_property         (GObject *object, guint id, const GValue *value, GParamSpec *pspec );
104 static void             gst_mikmod_get_property         (GObject *object, guint id, GValue *value, GParamSpec *pspec );
105 static GstPadLinkReturn gst_mikmod_srclink              (GstPad *pad, GstCaps *caps);
106 static void             gst_mikmod_loop                 (GstElement *element);
107 static gboolean         gst_mikmod_setup                (GstMikMod *mikmod);
108 static GstElementStateReturn  gst_mikmod_change_state   (GstElement *element);
109
110
111
112 static GstElementClass *parent_class = NULL;
113
114 GType
115 gst_mikmod_get_type(void) {
116   static GType mikmod_type = 0;
117
118   if (!mikmod_type) {
119     static const GTypeInfo mikmod_info = {
120       sizeof(GstMikModClass),
121       gst_mikmod_base_init,
122       NULL,
123       (GClassInitFunc)gst_mikmod_class_init,
124       NULL,
125       NULL,
126       sizeof(GstMikMod),
127       0,
128       (GInstanceInitFunc)gst_mikmod_init,
129     };
130     mikmod_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMikmod", &mikmod_info, 0);
131   }
132   return mikmod_type;
133 }
134
135 static void
136 gst_mikmod_base_init (gpointer g_class)
137 {
138   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
139
140   gst_element_class_add_pad_template (element_class, mikmod_src_factory ());
141   gst_element_class_add_pad_template (element_class, 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_ref(GST_TYPE_ELEMENT);
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 = gst_pad_new_from_template(mikmod_sink_factory (),"sink");
209   filter->srcpad = gst_pad_new_from_template(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   
215   gst_element_set_loop_function (GST_ELEMENT (filter), gst_mikmod_loop);
216   
217   filter->Buffer = NULL;
218
219   filter->stereo      = TRUE;
220   filter->surround    = TRUE;
221   filter->_16bit      = TRUE;
222   filter->soft_music  = TRUE;
223   filter->soft_sndfx  = TRUE;
224   filter->mixfreq     = 44100;
225   filter->reverb      = 0;
226   filter->pansep      = 128;
227   filter->musicvolume = 128;
228   filter->volume      = 96;
229   filter->sndfxvolume = 128;
230   filter->songname    = NULL;
231   filter->modtype     = NULL;
232 }
233
234
235 static GstPadLinkReturn
236 gst_mikmod_negotiate (GstMikMod *mikmod)
237 {
238   gint width, sign;
239
240   if ( mikmod->_16bit ) {
241     width = 16;
242     sign = TRUE;
243   } else {
244     width = 8;
245     sign = FALSE;
246   }
247
248   return gst_pad_try_set_caps (mikmod->srcpad, 
249                           GST_CAPS_NEW (
250                             "mikmod_src",
251                             "audio/x-raw-int",
252                               "endianness",  GST_PROPS_INT (G_BYTE_ORDER),
253                               "signed",      GST_PROPS_BOOLEAN (sign),
254                               "width",       GST_PROPS_INT (width),
255                               "depth",       GST_PROPS_INT (width),
256                               "rate",        GST_PROPS_INT (mikmod->mixfreq),
257                               "channels",    GST_PROPS_INT (mikmod->stereo ? 2 : 1)));
258 }
259
260
261 static GstPadLinkReturn
262 gst_mikmod_srclink (GstPad *pad, GstCaps *caps)
263 {
264   GstMikMod *filter; 
265
266   filter = GST_MIKMOD (gst_pad_get_parent (pad));
267
268   if (gst_caps_has_property_typed (caps, "depth", GST_PROPS_INT_TYPE)) {
269     gint depth;
270     gst_caps_get_int (caps, "depth", &depth);
271     filter->_16bit = (depth == 16);
272   }
273   if (gst_caps_has_property_typed (caps, "channels", GST_PROPS_INT_TYPE)) {
274     gint channels;
275     gst_caps_get_int (caps, "channels", &channels);
276     filter->stereo = (channels == 2);
277   }
278   if (gst_caps_has_property_typed (caps, "rate", GST_PROPS_INT_TYPE)) {
279     gst_caps_get_int (caps, "rate", &filter->mixfreq);
280   }
281
282   return gst_mikmod_negotiate(filter);
283 }
284
285
286 static void
287 gst_mikmod_loop (GstElement *element)
288 {
289   GstMikMod *mikmod;
290   GstBuffer *buffer_in;
291
292   g_return_if_fail (element != NULL);
293   g_return_if_fail (GST_IS_MIKMOD (element));
294         
295   mikmod = GST_MIKMOD (element);
296   srcpad = mikmod->srcpad;
297   mikmod->Buffer = NULL;
298         
299   while ((buffer_in = GST_BUFFER (gst_pad_pull( mikmod->sinkpad )))) {
300     if ( GST_IS_EVENT (buffer_in) ) {
301       GstEvent *event = GST_EVENT (buffer_in);
302                 
303       if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) 
304          break;
305     }
306     else                
307     {
308       if ( mikmod->Buffer ) {    
309         mikmod->Buffer = gst_buffer_merge( mikmod->Buffer, buffer_in );
310         gst_buffer_unref( buffer_in );            
311       }
312       else
313         mikmod->Buffer = buffer_in;
314     }
315   }  
316   
317   if (!GST_PAD_CAPS (mikmod->srcpad)) {
318     if (gst_mikmod_negotiate (mikmod) <= 0) {
319       gst_element_error (GST_ELEMENT (mikmod),
320                          "Failed to negotiate with next element in mikmod");
321       return;
322     }
323   }
324   gst_mikmod_setup( mikmod );
325   
326   MikMod_RegisterDriver(&drv_gst);
327   MikMod_RegisterAllLoaders();
328
329   MikMod_Init("");
330   reader = GST_READER_new( mikmod );
331   module = Player_LoadGeneric ( reader, 64, 0 );
332   
333   gst_buffer_unref (mikmod->Buffer);
334   
335   if ( ! Player_Active() )
336     Player_Start(module);
337
338   do {
339     if ( Player_Active() ) {
340
341       timestamp = ( module->sngtime / 1024.0 ) * GST_SECOND;
342       drv_gst.Update();
343       gst_element_yield (element);
344     }
345     else {
346       gst_element_set_eos (GST_ELEMENT (mikmod));
347       gst_pad_push (mikmod->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
348     }
349
350   } 
351   while ( 1 );
352 }
353
354
355 static gboolean
356 gst_mikmod_setup (GstMikMod *mikmod)
357 {
358   md_musicvolume = mikmod->musicvolume;
359   md_pansep = mikmod->pansep;
360   md_reverb = mikmod->reverb;
361   md_sndfxvolume = mikmod->sndfxvolume;
362   md_volume = mikmod->volume;
363   md_mixfreq = mikmod->mixfreq;
364
365   md_mode = 0;
366
367   if ( mikmod->interp )
368     md_mode = md_mode | DMODE_INTERP;
369
370   if ( mikmod->reverse )
371     md_mode = md_mode | DMODE_REVERSE;
372
373   if ( mikmod->surround )
374     md_mode = md_mode | DMODE_SURROUND;
375
376   if ( mikmod->_16bit )
377     md_mode = md_mode | DMODE_16BITS;
378
379   if ( mikmod->hqmixer )
380     md_mode = md_mode | DMODE_HQMIXER;
381
382   if ( mikmod->soft_music )
383     md_mode = md_mode | DMODE_SOFT_MUSIC;
384
385   if ( mikmod->soft_sndfx )
386     md_mode = md_mode | DMODE_SOFT_SNDFX;
387
388   if ( mikmod->stereo )
389     md_mode = md_mode | DMODE_STEREO;
390
391   return TRUE;
392 }
393
394
395 static GstElementStateReturn
396 gst_mikmod_change_state (GstElement *element)
397 {
398 GstMikMod *mikmod;
399
400   g_return_val_if_fail (GST_IS_MIKMOD (element), GST_STATE_FAILURE);
401
402   mikmod = GST_MIKMOD (element);
403
404   GST_DEBUG ("state pending %d", GST_STATE_PENDING (element));
405
406   if (GST_STATE_PENDING (element) == GST_STATE_READY) 
407   {
408      gst_mikmod_setup(mikmod);
409           
410          if ( Player_Active() )
411          {
412                 Player_TogglePause();
413                 Player_SetPosition( 0 );
414          }
415         
416   }
417   
418   if (GST_STATE_PENDING (element) == GST_STATE_PLAYING) 
419   {      
420          if ( Player_Active() && Player_Paused() )       
421                 Player_TogglePause();
422          else
423            if ( ! Player_Active() )
424              Player_Start(module);
425          
426   }
427         
428   if (GST_STATE_PENDING (element) == GST_STATE_PAUSED) 
429     if ( Player_Active() && ! Player_Paused() )
430        Player_TogglePause();
431
432   if (GST_STATE_PENDING (element) == GST_STATE_NULL) 
433           MikMod_Exit();    
434   
435
436   if (GST_ELEMENT_CLASS (parent_class)->change_state)
437     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
438
439   return GST_STATE_SUCCESS;
440 }
441
442
443
444 static void
445 gst_mikmod_set_property (GObject *object, guint id, const GValue *value, GParamSpec *pspec )
446 {
447   GstMikMod *filter;
448
449   /* it's not null if we got it, but it might not be ours */
450   g_return_if_fail(GST_IS_MIKMOD(object));
451   filter = GST_MIKMOD(object);
452
453   switch (id) {
454     case ARG_SONGNAME:
455       g_free (filter->songname);
456       filter->songname = g_strdup (g_value_get_string (value));
457       break;
458     case ARG_MODTYPE:
459       g_free (filter->modtype);
460       filter->modtype = g_strdup (g_value_get_string (value));
461       break;
462     case ARG_MUSICVOLUME:
463       filter->musicvolume = g_value_get_int (value);
464       break;
465     case ARG_PANSEP:
466       filter->pansep = g_value_get_int (value);
467       break;
468     case ARG_REVERB:
469       filter->reverb = g_value_get_int (value);
470       break;
471     case ARG_SNDFXVOLUME:
472       filter->sndfxvolume = g_value_get_int (value);
473       break;
474     case ARG_VOLUME:
475       filter->volume = g_value_get_int (value);
476       break;
477     case ARG_INTERP:
478       filter->interp = g_value_get_boolean (value);
479       break;
480     case ARG_REVERSE:
481       filter->reverse = g_value_get_boolean (value);
482       break;
483     case ARG_SURROUND:
484       filter->surround = g_value_get_boolean (value);
485       break;
486     case ARG_HQMIXER:
487       filter->hqmixer = g_value_get_boolean (value);
488       break;
489     case ARG_SOFT_MUSIC:
490       filter->soft_music = g_value_get_boolean (value);
491       break;
492     case ARG_SOFT_SNDFX:
493       filter->soft_sndfx = g_value_get_boolean (value);
494       break;
495     default:
496       break;
497   }
498 }
499
500 static void
501 gst_mikmod_get_property (GObject *object, guint id, GValue *value, GParamSpec *pspec )
502 {
503   GstMikMod *filter;
504
505   /* it's not null if we got it, but it might not be ours */
506   g_return_if_fail(GST_IS_MIKMOD(object));
507   filter = GST_MIKMOD(object);
508
509   switch (id) {
510     case ARG_MUSICVOLUME:
511       g_value_set_int (value, filter->musicvolume);
512       break;
513     case ARG_PANSEP:
514       g_value_set_int (value, filter->pansep);
515       break;
516     case ARG_REVERB:
517       g_value_set_int (value, filter->reverb);
518       break;
519     case ARG_SNDFXVOLUME:
520       g_value_set_int (value, filter->sndfxvolume);
521       break;
522     case ARG_VOLUME:
523       g_value_set_int (value, filter->volume);
524       break;
525     case ARG_INTERP:
526       g_value_set_boolean (value, filter->interp);
527       break;
528     case ARG_REVERSE:
529       g_value_set_boolean (value, filter->reverse);
530       break;
531     case ARG_SURROUND:
532       g_value_set_boolean (value, filter->surround);
533       break;
534     case ARG_HQMIXER:
535       g_value_set_boolean (value, filter->hqmixer);
536       break;
537     case ARG_SOFT_MUSIC:
538       g_value_set_boolean (value, filter->soft_music);
539       break;
540     case ARG_SOFT_SNDFX:
541       g_value_set_boolean (value, filter->soft_sndfx);
542       break;
543     default:
544       break;
545   }
546 }
547
548 static gboolean
549 plugin_init (GstPlugin *plugin)
550 {
551   if (!gst_element_register (plugin, "mikmod", GST_RANK_NONE, GST_TYPE_MIKMOD))
552     return FALSE;
553
554   return TRUE;
555 }
556
557 GST_PLUGIN_DEFINE (
558   GST_VERSION_MAJOR,
559   GST_VERSION_MINOR,
560   "mikmod",
561   "Mikmod plugin library",
562   plugin_init,
563   VERSION,
564   "GPL",
565   GST_COPYRIGHT,
566   GST_PACKAGE,
567   GST_ORIGIN)