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