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