9ebd85631b982f5f87ecfd57961cae216d52cdf3
[platform/upstream/gstreamer.git] / gst / modplug / gstmodplug.cc
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    Code based on modplugxmms
22    XMMS plugin:
23      Kenton Varda <temporal@gauge3d.org>
24    Sound Engine:
25      Olivier Lapicque <olivierl@jps.net>  
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "libmodplug/stdafx.h"
33 #include "libmodplug/sndfile.h"
34
35 #include "gstmodplug.h"
36
37 #include <gst/gst.h>
38 #include <stdlib.h>
39 #include <gst/audio/audio.h>
40
41 /* elementfactory information */
42 GstElementDetails modplug_details = {
43   "ModPlug",
44   "Codec/Decoder/Audio",
45   "Module decoder based on modplug engine",
46   "Jeremy SIMON <jsimon13@yahoo.fr>"
47 };
48
49
50 /* Filter signals and args */
51 enum {
52   /* FILL ME */
53   LAST_SIGNAL
54 };
55
56 enum {
57   ARG_0,
58   ARG_SONGNAME,
59   ARG_REVERB,
60   ARG_REVERB_DEPTH,
61   ARG_REVERB_DELAY,
62   ARG_MEGABASS,
63   ARG_MEGABASS_AMOUNT,
64   ARG_MEGABASS_RANGE,
65   ARG_NOISE_REDUCTION,
66   ARG_SURROUND,
67   ARG_SURROUND_DEPTH,
68   ARG_SURROUND_DELAY,
69   ARG_OVERSAMP
70 };
71
72 static GstStaticPadTemplate modplug_src_template_factory =
73 GST_STATIC_PAD_TEMPLATE (
74   "src",
75   GST_PAD_SRC,
76   GST_PAD_ALWAYS,
77   GST_STATIC_CAPS (
78     "audio/x-raw-int, "
79       "endianness = (int) BYTE_ORDER, "
80       "signed = (boolean) TRUE, "
81       "width = (int) 16, "
82       "depth = (int) 16, "
83       "rate = (int) { 8000, 11025, 22050, 44100 }, " /* FIXME? */
84       "channels = (int) [ 1, 2 ]; "
85     "audio/x-raw-int, "
86       "signed = (boolean) FALSE, "
87       "width = (int) 8, "
88       "depth = (int) 8, "
89       "rate = (int) { 8000, 11025, 22050, 44100 }, " /* FIXME? */
90       "channels = (int) [ 1, 2 ]"
91   )
92 );
93
94 static GstStaticPadTemplate modplug_sink_template_factory =
95 GST_STATIC_PAD_TEMPLATE (
96   "sink",
97   GST_PAD_SINK,
98   GST_PAD_ALWAYS,
99   GST_STATIC_CAPS ("audio/x-mod")
100 );
101
102 enum {
103   MODPLUG_STATE_NEED_TUNE = 1,
104   MODPLUG_STATE_LOAD_TUNE = 2,
105   MODPLUG_STATE_PLAY_TUNE = 3,
106 };
107
108 static void     gst_modplug_base_init           (GstModPlugClass *klass);
109 static void     gst_modplug_class_init          (GstModPlugClass *klass);
110 static void     gst_modplug_init                (GstModPlug *filter);
111 static void     gst_modplug_set_property        (GObject *object,
112                                                  guint id,
113                                                  const GValue *value,
114                                                  GParamSpec *pspec );
115 static void     gst_modplug_get_property        (GObject *object,
116                                                  guint id,
117                                                  GValue *value,
118                                                  GParamSpec *pspec );
119 static GstPadLinkReturn
120                 gst_modplug_srclink             (GstPad *pad, const GstCaps *caps);
121 static void     gst_modplug_loop                (GstElement *element);
122 static void     gst_modplug_setup               (GstModPlug *modplug);
123 static const GstFormat *
124               gst_modplug_get_formats           (GstPad *pad);
125 static const GstQueryType *
126               gst_modplug_get_query_types       (GstPad *pad);
127 static gboolean gst_modplug_src_event           (GstPad *pad, GstEvent *event);
128 static gboolean gst_modplug_src_query           (GstPad *pad,
129                                                  GstQueryType type,
130                                                  GstFormat *format,
131                                                  gint64 *value);
132 static GstElementStateReturn  
133                 gst_modplug_change_state        (GstElement *element);
134
135 static GstElementClass *parent_class = NULL;
136
137 GType
138 gst_modplug_get_type(void) {
139   static GType modplug_type = 0;
140
141   if (!modplug_type) {
142     static const GTypeInfo modplug_info = {
143       sizeof(GstModPlugClass),
144       (GBaseInitFunc)gst_modplug_base_init,
145       NULL,
146       (GClassInitFunc)gst_modplug_class_init,
147       NULL,
148       NULL,
149       sizeof(GstModPlug),
150       0,
151       (GInstanceInitFunc)gst_modplug_init,
152       NULL
153     };
154     modplug_type = g_type_register_static(GST_TYPE_ELEMENT, "GstModPlug", &modplug_info, (GTypeFlags)0);
155   }
156   return modplug_type;
157 }
158
159 static void
160 gst_modplug_base_init (GstModPlugClass *klass)
161 {
162   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
163
164   gst_element_class_add_pad_template (element_class,
165         gst_static_pad_template_get (&modplug_sink_template_factory));
166   gst_element_class_add_pad_template (element_class,
167         gst_static_pad_template_get (&modplug_src_template_factory));
168   gst_element_class_set_details (element_class, &modplug_details);
169 }
170
171 static void
172 gst_modplug_class_init (GstModPlugClass *klass)
173 {
174   GObjectClass *gobject_class;
175   GstElementClass *gstelement_class;
176
177   gobject_class = (GObjectClass*)klass;
178   gstelement_class = (GstElementClass*)klass;
179
180   parent_class = GST_ELEMENT_CLASS( g_type_class_ref(GST_TYPE_ELEMENT));
181
182   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SONGNAME,
183     g_param_spec_string("songname","Songname","The song name",
184                         "", G_PARAM_READABLE));
185
186   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_REVERB,
187     g_param_spec_boolean("reverb", "reverb", "reverb",
188                          FALSE, (GParamFlags)G_PARAM_READWRITE ));
189
190   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_REVERB_DEPTH,
191     g_param_spec_int("reverb_depth", "reverb_depth", "reverb_depth",
192                      0, 100, 30, (GParamFlags)G_PARAM_READWRITE ));
193
194   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_REVERB_DELAY,
195     g_param_spec_int("reverb_delay", "reverb_delay", "reverb_delay",
196                      0, 200, 100, (GParamFlags)G_PARAM_READWRITE ));
197
198   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MEGABASS,
199     g_param_spec_boolean("megabass", "megabass", "megabass",
200                          FALSE, (GParamFlags)G_PARAM_READWRITE ));
201
202   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MEGABASS_AMOUNT,
203     g_param_spec_int("megabass_amount", "megabass_amount", "megabass_amount",
204                      0, 100, 40, (GParamFlags)G_PARAM_READWRITE ));
205                                         
206   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MEGABASS_RANGE,
207     g_param_spec_int("megabass_range", "megabass_range", "megabass_range",
208                      0, 100, 30, (GParamFlags)G_PARAM_READWRITE ));
209
210   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SURROUND,
211     g_param_spec_boolean("surround", "surround", "surround",
212                          TRUE, (GParamFlags)G_PARAM_READWRITE ));
213
214   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SURROUND_DEPTH,
215     g_param_spec_int("surround_depth", "surround_depth", "surround_depth",
216                      0, 100, 20, (GParamFlags)G_PARAM_READWRITE ));
217
218   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SURROUND_DELAY,
219     g_param_spec_int("surround_delay", "surround_delay", "surround_delay",
220                      0, 40, 20, (GParamFlags)G_PARAM_READWRITE ));
221
222   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_OVERSAMP,
223     g_param_spec_boolean("oversamp", "oversamp", "oversamp",
224                          TRUE, (GParamFlags)G_PARAM_READWRITE ));
225
226   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NOISE_REDUCTION,
227     g_param_spec_boolean("noise_reduction", "noise_reduction", "noise_reduction",
228                          TRUE, (GParamFlags)G_PARAM_READWRITE ));
229
230   gobject_class->set_property = gst_modplug_set_property;
231   gobject_class->get_property = gst_modplug_get_property;
232
233   gstelement_class->change_state = gst_modplug_change_state;
234 }
235
236 static void
237 gst_modplug_init (GstModPlug *modplug)
238 {  
239   modplug->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get (&modplug_sink_template_factory), "sink");
240   gst_element_add_pad (GST_ELEMENT(modplug), modplug->sinkpad);
241
242   modplug->srcpad = gst_pad_new_from_template (gst_static_pad_template_get (&modplug_src_template_factory), "src");
243   gst_element_add_pad (GST_ELEMENT(modplug), modplug->srcpad);
244   gst_pad_set_link_function (modplug->srcpad, gst_modplug_srclink);
245   
246   gst_pad_set_event_function (modplug->srcpad, (GstPadEventFunction)GST_DEBUG_FUNCPTR(gst_modplug_src_event));
247   gst_pad_set_query_function (modplug->srcpad, gst_modplug_src_query);
248   gst_pad_set_query_type_function (modplug->srcpad,  (GstPadQueryTypeFunction) GST_DEBUG_FUNCPTR (gst_modplug_get_query_types));
249   gst_pad_set_formats_function (modplug->srcpad, (GstPadFormatsFunction)GST_DEBUG_FUNCPTR (gst_modplug_get_formats));
250   
251   gst_element_set_loop_function (GST_ELEMENT (modplug), gst_modplug_loop);      
252   
253   modplug->reverb          = FALSE;
254   modplug->reverb_depth    = 30;
255   modplug->reverb_delay    = 100;
256   modplug->megabass        = FALSE;
257   modplug->megabass_amount = 40;
258   modplug->megabass_range  = 30;          
259   modplug->surround        = TRUE;
260   modplug->surround_depth  = 20;
261   modplug->surround_delay  = 20;
262   modplug->oversamp        = TRUE;
263   modplug->noise_reduction = TRUE;
264
265   modplug->_16bit          = TRUE;
266   modplug->channel         = 2;
267   modplug->frequency       = 44100;
268   modplug->audiobuffer = NULL;
269   modplug->buffer_in = NULL;
270   
271   modplug->state = MODPLUG_STATE_NEED_TUNE;
272 }
273
274 static void
275 gst_modplug_setup (GstModPlug *modplug)
276 {
277   if (modplug->_16bit) 
278     modplug->mSoundFile->SetWaveConfig (modplug->frequency, 16, modplug->channel);
279   else
280     modplug->mSoundFile->SetWaveConfig (modplug->frequency, 8,  modplug->channel);
281   
282   modplug->mSoundFile->SetWaveConfigEx (modplug->surround, !modplug->oversamp, modplug->reverb, true, modplug->megabass, modplug->noise_reduction, true);
283   modplug->mSoundFile->SetResamplingMode (SRCMODE_POLYPHASE);
284
285   if (modplug->surround)
286     modplug->mSoundFile->SetSurroundParameters (modplug->surround_depth, modplug->surround_delay);
287
288   if (modplug->megabass)
289     modplug->mSoundFile->SetXBassParameters (modplug->megabass_amount, modplug->megabass_range);
290
291   if (modplug->reverb)
292     modplug->mSoundFile->SetReverbParameters (modplug->reverb_depth, modplug->reverb_delay);
293
294 }
295
296 static const GstFormat*
297 gst_modplug_get_formats (GstPad *pad)
298 {
299   static const GstFormat src_formats[] = {
300 /*    GST_FORMAT_BYTES,
301     GST_FORMAT_DEFAULT,*/
302     GST_FORMAT_TIME,
303     (GstFormat)0
304   };
305   static const GstFormat sink_formats[] = {
306     /*GST_FORMAT_BYTES,*/
307     GST_FORMAT_TIME,
308     (GstFormat)0
309   };
310   
311   return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
312 }
313
314 static const GstQueryType*
315 gst_modplug_get_query_types (GstPad *pad)
316 {
317   static const GstQueryType gst_modplug_src_query_types[] = {
318     GST_QUERY_TOTAL,
319     GST_QUERY_POSITION,
320     (GstQueryType)0
321   };
322   
323   return gst_modplug_src_query_types;
324 }
325
326
327 static gboolean
328 gst_modplug_src_query (GstPad *pad, GstQueryType type,
329                                    GstFormat *format, gint64 *value)
330 {
331   gboolean res = TRUE;
332   GstModPlug *modplug;
333   gfloat tmp;
334
335   modplug = GST_MODPLUG (gst_pad_get_parent (pad));
336
337   switch (type) {
338     case GST_QUERY_TOTAL:
339       switch (*format) {
340         case GST_FORMAT_TIME:
341             *value=(gint64)modplug->mSoundFile->GetSongTime() * GST_SECOND;
342             break;
343         default:
344             res = FALSE;
345             break;
346       }
347       break;
348     case GST_QUERY_POSITION:
349       switch (*format) {
350          default:
351            tmp = ((float)( modplug->mSoundFile->GetSongTime() * modplug->mSoundFile->GetCurrentPos() ) / (float)modplug->mSoundFile->GetMaxPosition() );
352            *value=(gint64)(tmp * GST_SECOND);
353            break;
354       }
355     default:
356       break;
357   }
358
359   return res;
360 }    
361                 
362
363 static gboolean
364 gst_modplug_src_event (GstPad *pad, GstEvent *event)
365 {
366   gboolean res = TRUE;
367   GstModPlug *modplug; 
368
369   modplug = GST_MODPLUG (gst_pad_get_parent (pad));
370
371   switch (GST_EVENT_TYPE (event)) {
372     /* the all-formats seek logic */
373     case GST_EVENT_SEEK:
374     {
375       gboolean flush;
376       GstFormat format;
377
378       format = GST_FORMAT_TIME;
379
380       /* shave off the flush flag, we'll need it later */
381       flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
382
383       modplug->seek_at = GST_EVENT_SEEK_OFFSET (event);
384       break;
385     }
386     default:
387       res = FALSE;
388       break;
389   }
390   
391   gst_event_unref (event);
392
393   return res;
394 }
395
396 #if 0
397 static GstCaps*
398 gst_modplug_get_streaminfo (GstModPlug *modplug)
399 {
400   GstCaps *caps;
401  
402   props = gst_props_empty_new ();
403
404   entry = gst_props_entry_new ("Patterns", G_TYPE_INT ((gint)modplug->mSoundFile->GetNumPatterns()));
405   gst_props_add_entry (props, (GstPropsEntry *) entry);
406   
407   caps = gst_caps_new_simple ("application/x-gst-streaminfo", NULL);
408   return caps;
409 }
410
411
412 static void
413 gst_modplug_update_info (GstModPlug *modplug)
414 {  
415     if (modplug->streaminfo) {
416       gst_caps_unref (modplug->streaminfo);
417     }
418
419     modplug->streaminfo = gst_modplug_get_streaminfo (modplug);
420     g_object_notify (G_OBJECT (modplug), "streaminfo"); 
421 }
422
423 static void 
424 gst_modplug_update_metadata (GstModPlug *modplug)
425 {  
426   GstProps *props;
427   GstPropsEntry *entry;
428   const gchar *title;
429
430   props = gst_props_empty_new ();
431
432   title = modplug->mSoundFile->GetTitle();
433   entry = gst_props_entry_new ("Title", G_TYPE_STRING (title));
434   gst_props_add_entry (props, entry);
435
436   modplug->metadata = gst_caps_new_simple ("application/x-gst-metadata",
437                   NULL);
438
439   g_object_notify (G_OBJECT (modplug), "metadata");
440 }
441 #endif
442
443 static GstPadLinkReturn
444 gst_modplug_srclink (GstPad *pad, const GstCaps *caps)
445 {
446   GstModPlug *modplug; 
447   GstStructure *structure;
448   gint depth;
449
450   modplug = GST_MODPLUG (gst_pad_get_parent (pad));
451
452   structure = gst_caps_get_structure (caps, 0);
453
454   gst_structure_get_int (structure, "depth", &depth);
455   modplug->_16bit = (depth == 16);
456   gst_structure_get_int (structure, "channels", &modplug->channel);
457   gst_structure_get_int (structure, "rate", &modplug->frequency);
458
459   modplug->length = 1152 * modplug->channel * depth / 8;
460   gst_modplug_setup (modplug);
461
462   return GST_PAD_LINK_OK;
463 }
464
465 static void
466 gst_modplug_handle_event (GstModPlug *modplug)
467 {
468   guint32 remaining;
469   GstEvent *event;
470
471   gst_bytestream_get_status (modplug->bs, &remaining, &event);
472
473   if (!event) {
474     g_warning ("modplug: no bytestream event");
475     return;
476   }
477
478   switch (GST_EVENT_TYPE (event)) {
479     case GST_EVENT_DISCONTINUOUS:
480       gst_bytestream_flush_fast (modplug->bs, remaining);
481     default:
482       gst_pad_event_default (modplug->sinkpad, event);
483       break;
484   }
485 }
486
487 static void
488 gst_modplug_loop (GstElement *element)
489 {
490   GstModPlug *modplug;  
491   GstEvent *event;    
492
493   g_return_if_fail (element != NULL);
494   g_return_if_fail (GST_IS_MODPLUG (element));
495         
496   modplug = GST_MODPLUG (element);
497
498   if (modplug->state == MODPLUG_STATE_NEED_TUNE) 
499   {            
500 /*    GstBuffer *buf;*/
501        
502     modplug->seek_at = -1;
503     modplug->need_discont = FALSE;
504     modplug->eos = FALSE;
505 /*            
506     buf = gst_pad_pull (modplug->sinkpad);
507     g_assert (buf != NULL);
508       
509     if (GST_IS_EVENT (buf)) {
510       GstEvent *event = GST_EVENT (buf);
511
512       switch (GST_EVENT_TYPE (buf)) {
513         case GST_EVENT_EOS:             
514           modplug->state = MODPLUG_STATE_LOAD_TUNE;
515           break;
516         case GST_EVENT_DISCONTINUOUS:
517           break;
518         default:
519            bail out, we're not going to do anything 
520           gst_event_unref (event);
521           gst_pad_send_event (modplug->srcpad, gst_event_new (GST_EVENT_EOS));
522           gst_element_set_eos (element);
523           return;
524       }
525       gst_event_unref (event);
526     }
527     else {      
528       memcpy (modplug->buffer_in + modplug->song_size, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
529       modplug->song_size += GST_BUFFER_SIZE (buf);
530
531       gst_buffer_unref (buf);
532     }
533 */
534
535     if (modplug->bs)
536     {
537       guint64 got;
538       
539       modplug->song_size = gst_bytestream_length (modplug->bs);
540
541       got = gst_bytestream_peek_bytes (modplug->bs, &modplug->buffer_in,  modplug->song_size);
542
543       if ( got < modplug->song_size )
544       {
545         gst_modplug_handle_event (modplug);
546         return;
547       }
548       modplug->state = MODPLUG_STATE_LOAD_TUNE; 
549     }  
550   }  
551   
552   if (modplug->state == MODPLUG_STATE_LOAD_TUNE) 
553   {            
554     modplug->mSoundFile = new CSoundFile;
555     
556     if (!GST_PAD_CAPS (modplug->srcpad) &&
557         GST_PAD_LINK_FAILED (gst_pad_renegotiate (modplug->srcpad))) {
558       GST_ELEMENT_ERROR (modplug, CORE, NEGOTIATION, (NULL), (NULL));
559       return;
560     }
561         
562     modplug->mSoundFile->Create (modplug->buffer_in, modplug->song_size);    
563     modplug->opened = TRUE;
564       
565     gst_bytestream_flush (modplug->bs, modplug->song_size);
566     modplug->buffer_in = NULL;
567
568     modplug->audiobuffer = (guchar *) g_malloc (modplug->length);
569     
570     //gst_modplug_update_metadata (modplug);
571     //gst_modplug_update_info (modplug);
572
573     modplug->state = MODPLUG_STATE_PLAY_TUNE;
574   }
575       
576   if (modplug->state == MODPLUG_STATE_PLAY_TUNE && !modplug->eos) 
577   {
578     if (modplug->seek_at != -1)
579     {
580       gint seek_to_pos;
581       gint64 total;
582       gfloat temp;
583        
584       total = modplug->mSoundFile->GetSongTime () * GST_SECOND;
585
586       temp = (gfloat) total / modplug->seek_at;     
587       seek_to_pos = (int) (modplug->mSoundFile->GetMaxPosition () / temp);
588
589       modplug->mSoundFile->SetCurrentPos (seek_to_pos);    
590       modplug->need_discont = TRUE;
591       modplug->seek_at = -1;
592     }
593         
594     if (modplug->mSoundFile->Read (modplug->audiobuffer, modplug->length) != 0)
595     {         
596       GstBuffer *buffer_out;
597       GstFormat format;
598       gint64 value;
599  
600       format = GST_FORMAT_TIME;
601       gst_modplug_src_query (modplug->srcpad, GST_QUERY_POSITION, &format, &value);
602       
603       if (modplug->need_discont && GST_PAD_IS_USABLE (modplug->srcpad))
604       {
605         GstEvent *discont;
606     
607         discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, value, NULL);
608         gst_pad_push (modplug->srcpad, GST_DATA (discont));        
609       
610         modplug->need_discont= FALSE;
611       }
612           
613       buffer_out = gst_buffer_new ();
614       GST_BUFFER_DATA (buffer_out) = (guchar *) g_memdup (modplug->audiobuffer, modplug->length);
615       GST_BUFFER_SIZE (buffer_out) = modplug->length;
616       GST_BUFFER_TIMESTAMP (buffer_out) = value;
617       
618       if (GST_PAD_IS_USABLE (modplug->srcpad))
619         gst_pad_push (modplug->srcpad, GST_DATA (buffer_out));   
620     }
621     else
622       if (GST_PAD_IS_LINKED (modplug->srcpad))
623       {        
624         /* FIXME, hack, pull final EOS from peer */
625         gst_bytestream_flush (modplug->bs, 1);
626         
627         event = gst_event_new (GST_EVENT_EOS);
628         gst_pad_push (modplug->srcpad, GST_DATA (event));
629         gst_element_set_eos (element);
630         modplug->eos = TRUE;
631       }
632   }
633 }
634
635
636 static GstElementStateReturn
637 gst_modplug_change_state (GstElement *element)
638 {
639   GstModPlug *modplug;
640
641   modplug = GST_MODPLUG (element);
642
643   switch (GST_STATE_TRANSITION (element)) {
644     case GST_STATE_NULL_TO_READY:
645       break;
646     case GST_STATE_READY_TO_PAUSED:  
647       modplug->bs = gst_bytestream_new (modplug->sinkpad);
648       modplug->song_size = 0;
649       modplug->state = MODPLUG_STATE_NEED_TUNE;
650       break;
651     case GST_STATE_PAUSED_TO_PLAYING:
652       break;
653     case GST_STATE_PLAYING_TO_PAUSED:
654       break;
655     case GST_STATE_PAUSED_TO_READY:     
656       gst_bytestream_destroy (modplug->bs);          
657       modplug->bs = NULL;
658       if (modplug->opened)
659       {
660         modplug->mSoundFile->Destroy ();      
661         modplug->opened = FALSE;
662       }
663       if (modplug->audiobuffer) g_free (modplug->audiobuffer);      
664       modplug->buffer_in = NULL;
665       modplug->audiobuffer = NULL;
666       modplug->state = MODPLUG_STATE_NEED_TUNE;
667       break;
668     case GST_STATE_READY_TO_NULL:         
669       break;
670     default:
671       break;
672   }
673
674   if (GST_ELEMENT_CLASS (parent_class)->change_state)
675     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
676     
677   return GST_STATE_SUCCESS;
678 }
679
680
681 static void
682 gst_modplug_set_property (GObject *object, guint id, const GValue *value, GParamSpec *pspec )
683 {
684   GstModPlug *modplug;
685
686   /* it's not null if we got it, but it might not be ours */
687   g_return_if_fail (GST_IS_MODPLUG(object));
688   modplug = GST_MODPLUG (object);
689
690   switch (id) {
691     case ARG_REVERB:
692       modplug->reverb = g_value_get_boolean (value);
693       break;
694     case ARG_REVERB_DEPTH:
695       modplug->reverb_depth = g_value_get_int (value);
696       break;
697     case ARG_REVERB_DELAY:
698       modplug->reverb_delay = g_value_get_int (value);
699       break;
700     case ARG_MEGABASS:
701       modplug->megabass = g_value_get_boolean (value);
702       break;
703     case ARG_MEGABASS_AMOUNT:
704       modplug->megabass_amount = g_value_get_int (value);
705       break;
706     case ARG_MEGABASS_RANGE:
707       modplug->megabass_range = g_value_get_int (value);
708       break;
709     case ARG_NOISE_REDUCTION:
710       modplug->noise_reduction = g_value_get_boolean (value);
711       break;
712     case ARG_SURROUND:
713       modplug->surround = g_value_get_boolean (value);
714       break;
715     case ARG_SURROUND_DEPTH:
716       modplug->surround_depth = g_value_get_int (value);
717       break;
718     case ARG_SURROUND_DELAY:
719       modplug->surround_delay = g_value_get_int (value);
720       break;
721     default:
722       break;
723   }
724 }
725
726 static void
727 gst_modplug_get_property (GObject *object, guint id, GValue *value, GParamSpec *pspec )
728 {
729   GstModPlug *modplug;
730
731   /* it's not null if we got it, but it might not be ours */
732   g_return_if_fail (GST_IS_MODPLUG(object));
733   modplug = GST_MODPLUG (object);
734   
735   switch (id) {
736     case ARG_REVERB:
737       g_value_set_boolean (value, modplug->reverb);
738       break;
739     case ARG_REVERB_DEPTH:
740       g_value_set_int (value, modplug->reverb_depth);
741       break;
742     case ARG_REVERB_DELAY:
743       g_value_set_int (value, modplug->reverb_delay);
744       break;
745     case ARG_MEGABASS:
746       g_value_set_boolean (value, modplug->megabass);
747       break;
748     case ARG_MEGABASS_AMOUNT:
749       g_value_set_int (value, modplug->megabass_amount);
750       break;
751     case ARG_MEGABASS_RANGE:
752       g_value_set_int (value, modplug->megabass_range);
753       break;
754     case ARG_SURROUND:
755       g_value_set_boolean (value, modplug->surround);
756       break;
757     case ARG_SURROUND_DEPTH:
758       g_value_set_int (value, modplug->surround_depth);
759       break;
760     case ARG_SURROUND_DELAY:
761       g_value_set_int (value, modplug->surround_delay);
762       break;
763     case ARG_NOISE_REDUCTION:
764       g_value_set_boolean (value, modplug->noise_reduction);
765       break;
766     default:
767       break;
768   }
769 }
770
771 static gboolean
772 plugin_init (GstPlugin *plugin)
773 {
774   /* this filter needs the bytestream package */
775   if (!gst_library_load ("gstbytestream"))
776     return FALSE;
777   
778   return gst_element_register (plugin, "modplug",
779                                GST_RANK_PRIMARY, GST_TYPE_MODPLUG);
780 }
781
782 GST_PLUGIN_DEFINE (
783   GST_VERSION_MAJOR,
784   GST_VERSION_MINOR,
785   "modplug",
786   ".MOD audio decoding",
787   plugin_init,
788   VERSION,
789   "LGPL",
790   GST_PACKAGE,
791   GST_ORIGIN
792 )