2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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.
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.
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.
21 Code based on modplugxmms
23 Kenton Varda <temporal@gauge3d.org>
25 Olivier Lapicque <olivierl@jps.net>
32 #include "libmodplug/stdafx.h"
33 #include "libmodplug/sndfile.h"
35 #include "gstmodplug.h"
39 #include <gst/audio/audio.h>
41 /* elementfactory information */
42 GstElementDetails modplug_details = {
44 "Codec/Decoder/Audio",
45 "Module decoder based on modplug engine",
46 "Jeremy SIMON <jsimon13@yahoo.fr>"
50 /* Filter signals and args */
72 static GstStaticPadTemplate modplug_src_template_factory =
73 GST_STATIC_PAD_TEMPLATE (
79 "endianness = (int) BYTE_ORDER, "
80 "signed = (boolean) TRUE, "
83 "rate = (int) { 8000, 11025, 22050, 44100 }, " /* FIXME? */
84 "channels = (int) [ 1, 2 ]; "
86 "signed = (boolean) FALSE, "
89 "rate = (int) { 8000, 11025, 22050, 44100 }, " /* FIXME? */
90 "channels = (int) [ 1, 2 ]"
94 static GstStaticPadTemplate modplug_sink_template_factory =
95 GST_STATIC_PAD_TEMPLATE (
99 GST_STATIC_CAPS ("audio/x-mod")
103 MODPLUG_STATE_NEED_TUNE = 1,
104 MODPLUG_STATE_LOAD_TUNE = 2,
105 MODPLUG_STATE_PLAY_TUNE = 3,
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,
115 static void gst_modplug_get_property (GObject *object,
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,
133 static GstElementStateReturn
134 gst_modplug_change_state (GstElement *element);
136 static GstElementClass *parent_class = NULL;
139 gst_modplug_get_type(void) {
140 static GType modplug_type = 0;
143 static const GTypeInfo modplug_info = {
144 sizeof(GstModPlugClass),
145 (GBaseInitFunc)gst_modplug_base_init,
147 (GClassInitFunc)gst_modplug_class_init,
152 (GInstanceInitFunc)gst_modplug_init,
155 modplug_type = g_type_register_static(GST_TYPE_ELEMENT, "GstModPlug", &modplug_info, (GTypeFlags)0);
161 gst_modplug_base_init (GstModPlugClass *klass)
163 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
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);
173 gst_modplug_class_init (GstModPlugClass *klass)
175 GObjectClass *gobject_class;
176 GstElementClass *gstelement_class;
178 gobject_class = (GObjectClass*)klass;
179 gstelement_class = (GstElementClass*)klass;
181 parent_class = GST_ELEMENT_CLASS( g_type_class_ref(GST_TYPE_ELEMENT));
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));
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 ));
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 ));
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 ));
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 ));
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 ));
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 ));
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 ));
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 ));
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 ));
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 ));
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 ));
231 gobject_class->set_property = gst_modplug_set_property;
232 gobject_class->get_property = gst_modplug_get_property;
234 gstelement_class->change_state = gst_modplug_change_state;
238 gst_modplug_init (GstModPlug *modplug)
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);
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);
252 gst_element_set_loop_function (GST_ELEMENT (modplug), gst_modplug_loop);
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;
266 modplug->_16bit = TRUE;
267 modplug->channel = 2;
268 modplug->frequency = 44100;
269 modplug->audiobuffer = NULL;
270 modplug->buffer_in = NULL;
272 modplug->state = MODPLUG_STATE_NEED_TUNE;
276 gst_modplug_setup (GstModPlug *modplug)
279 modplug->mSoundFile->SetWaveConfig (modplug->frequency, 16, modplug->channel);
281 modplug->mSoundFile->SetWaveConfig (modplug->frequency, 8, modplug->channel);
283 modplug->mSoundFile->SetWaveConfigEx (modplug->surround, !modplug->oversamp, modplug->reverb, true, modplug->megabass, modplug->noise_reduction, true);
284 modplug->mSoundFile->SetResamplingMode (SRCMODE_POLYPHASE);
286 if (modplug->surround)
287 modplug->mSoundFile->SetSurroundParameters (modplug->surround_depth, modplug->surround_delay);
289 if (modplug->megabass)
290 modplug->mSoundFile->SetXBassParameters (modplug->megabass_amount, modplug->megabass_range);
293 modplug->mSoundFile->SetReverbParameters (modplug->reverb_depth, modplug->reverb_delay);
297 static const GstFormat*
298 gst_modplug_get_formats (GstPad *pad)
300 static const GstFormat src_formats[] = {
302 GST_FORMAT_DEFAULT,*/
306 static const GstFormat sink_formats[] = {
307 /*GST_FORMAT_BYTES,*/
312 return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
315 static const GstQueryType*
316 gst_modplug_get_query_types (GstPad *pad)
318 static const GstQueryType gst_modplug_src_query_types[] = {
324 return gst_modplug_src_query_types;
329 gst_modplug_src_query (GstPad *pad, GstQueryType type,
330 GstFormat *format, gint64 *value)
336 modplug = GST_MODPLUG (gst_pad_get_parent (pad));
339 case GST_QUERY_TOTAL:
341 case GST_FORMAT_TIME:
342 *value=(gint64)modplug->mSoundFile->GetSongTime() * GST_SECOND;
349 case GST_QUERY_POSITION:
352 tmp = ((float)( modplug->mSoundFile->GetSongTime() * modplug->mSoundFile->GetCurrentPos() ) / (float)modplug->mSoundFile->GetMaxPosition() );
353 *value=(gint64)(tmp * GST_SECOND);
365 gst_modplug_src_event (GstPad *pad, GstEvent *event)
370 modplug = GST_MODPLUG (gst_pad_get_parent (pad));
372 switch (GST_EVENT_TYPE (event)) {
373 /* the all-formats seek logic */
379 format = GST_FORMAT_TIME;
381 /* shave off the flush flag, we'll need it later */
382 flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
384 modplug->seek_at = GST_EVENT_SEEK_OFFSET (event);
392 gst_event_unref (event);
399 gst_modplug_get_streaminfo (GstModPlug *modplug)
403 props = gst_props_empty_new ();
405 entry = gst_props_entry_new ("Patterns", G_TYPE_INT ((gint)modplug->mSoundFile->GetNumPatterns()));
406 gst_props_add_entry (props, (GstPropsEntry *) entry);
408 caps = gst_caps_new_simple ("application/x-gst-streaminfo", NULL);
414 gst_modplug_update_info (GstModPlug *modplug)
416 if (modplug->streaminfo) {
417 gst_caps_unref (modplug->streaminfo);
420 modplug->streaminfo = gst_modplug_get_streaminfo (modplug);
421 g_object_notify (G_OBJECT (modplug), "streaminfo");
425 gst_modplug_update_metadata (GstModPlug *modplug)
428 GstPropsEntry *entry;
431 props = gst_props_empty_new ();
433 title = modplug->mSoundFile->GetTitle();
434 entry = gst_props_entry_new ("Title", G_TYPE_STRING (title));
435 gst_props_add_entry (props, entry);
437 modplug->metadata = gst_caps_new_simple ("application/x-gst-metadata",
440 g_object_notify (G_OBJECT (modplug), "metadata");
444 static GstPadLinkReturn
445 gst_modplug_srclink (GstPad *pad, const GstCaps *caps)
448 GstStructure *structure;
451 modplug = GST_MODPLUG (gst_pad_get_parent (pad));
453 structure = gst_caps_get_structure (caps, 0);
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);
460 modplug->length = 1152 * modplug->channel * depth / 8;
461 gst_modplug_setup (modplug);
463 return GST_PAD_LINK_OK;
467 gst_modplug_fixate (GstPad *pad, const GstCaps *caps)
469 if (gst_caps_is_simple (caps)) {
471 GstStructure *structure;
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))
477 if (gst_caps_structure_fixate_field_nearest_int (structure, "channels", 2))
479 gst_caps_free (copy);
485 gst_modplug_handle_event (GstModPlug *modplug)
490 gst_bytestream_get_status (modplug->bs, &remaining, &event);
493 g_warning ("modplug: no bytestream event");
497 switch (GST_EVENT_TYPE (event)) {
498 case GST_EVENT_DISCONTINUOUS:
499 gst_bytestream_flush_fast (modplug->bs, remaining);
501 gst_pad_event_default (modplug->sinkpad, event);
507 gst_modplug_loop (GstElement *element)
512 g_return_if_fail (element != NULL);
513 g_return_if_fail (GST_IS_MODPLUG (element));
515 modplug = GST_MODPLUG (element);
517 if (modplug->state == MODPLUG_STATE_NEED_TUNE)
521 modplug->seek_at = -1;
522 modplug->need_discont = FALSE;
523 modplug->eos = FALSE;
525 buf = gst_pad_pull (modplug->sinkpad);
526 g_assert (buf != NULL);
528 if (GST_IS_EVENT (buf)) {
529 GstEvent *event = GST_EVENT (buf);
531 switch (GST_EVENT_TYPE (buf)) {
533 modplug->state = MODPLUG_STATE_LOAD_TUNE;
535 case GST_EVENT_DISCONTINUOUS:
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);
544 gst_event_unref (event);
547 memcpy (modplug->buffer_in + modplug->song_size, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
548 modplug->song_size += GST_BUFFER_SIZE (buf);
550 gst_buffer_unref (buf);
558 modplug->song_size = gst_bytestream_length (modplug->bs);
560 got = gst_bytestream_peek_bytes (modplug->bs, &modplug->buffer_in, modplug->song_size);
562 if ( got < modplug->song_size )
564 gst_modplug_handle_event (modplug);
567 modplug->state = MODPLUG_STATE_LOAD_TUNE;
571 if (modplug->state == MODPLUG_STATE_LOAD_TUNE)
573 modplug->mSoundFile = new CSoundFile;
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));
581 modplug->mSoundFile->Create (modplug->buffer_in, modplug->song_size);
582 modplug->opened = TRUE;
584 gst_bytestream_flush (modplug->bs, modplug->song_size);
585 modplug->buffer_in = NULL;
587 modplug->audiobuffer = (guchar *) g_malloc (modplug->length);
589 //gst_modplug_update_metadata (modplug);
590 //gst_modplug_update_info (modplug);
592 modplug->state = MODPLUG_STATE_PLAY_TUNE;
595 if (modplug->state == MODPLUG_STATE_PLAY_TUNE && !modplug->eos)
597 if (modplug->seek_at != -1)
603 total = modplug->mSoundFile->GetSongTime () * GST_SECOND;
605 temp = (gfloat) total / modplug->seek_at;
606 seek_to_pos = (int) (modplug->mSoundFile->GetMaxPosition () / temp);
608 modplug->mSoundFile->SetCurrentPos (seek_to_pos);
609 modplug->need_discont = TRUE;
610 modplug->seek_at = -1;
613 if (modplug->mSoundFile->Read (modplug->audiobuffer, modplug->length) != 0)
615 GstBuffer *buffer_out;
619 format = GST_FORMAT_TIME;
620 gst_modplug_src_query (modplug->srcpad, GST_QUERY_POSITION, &format, &value);
622 if (modplug->need_discont && GST_PAD_IS_USABLE (modplug->srcpad))
626 discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, value, NULL);
627 gst_pad_push (modplug->srcpad, GST_DATA (discont));
629 modplug->need_discont= FALSE;
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;
637 if (GST_PAD_IS_USABLE (modplug->srcpad))
638 gst_pad_push (modplug->srcpad, GST_DATA (buffer_out));
641 if (GST_PAD_IS_LINKED (modplug->srcpad))
643 /* FIXME, hack, pull final EOS from peer */
644 gst_bytestream_flush (modplug->bs, 1);
646 event = gst_event_new (GST_EVENT_EOS);
647 gst_pad_push (modplug->srcpad, GST_DATA (event));
648 gst_element_set_eos (element);
655 static GstElementStateReturn
656 gst_modplug_change_state (GstElement *element)
660 modplug = GST_MODPLUG (element);
662 switch (GST_STATE_TRANSITION (element)) {
663 case GST_STATE_NULL_TO_READY:
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;
670 case GST_STATE_PAUSED_TO_PLAYING:
672 case GST_STATE_PLAYING_TO_PAUSED:
674 case GST_STATE_PAUSED_TO_READY:
675 gst_bytestream_destroy (modplug->bs);
679 modplug->mSoundFile->Destroy ();
680 modplug->opened = FALSE;
682 if (modplug->audiobuffer) g_free (modplug->audiobuffer);
683 modplug->buffer_in = NULL;
684 modplug->audiobuffer = NULL;
685 modplug->state = MODPLUG_STATE_NEED_TUNE;
687 case GST_STATE_READY_TO_NULL:
693 if (GST_ELEMENT_CLASS (parent_class)->change_state)
694 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
696 return GST_STATE_SUCCESS;
701 gst_modplug_set_property (GObject *object, guint id, const GValue *value, GParamSpec *pspec )
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);
711 modplug->reverb = g_value_get_boolean (value);
713 case ARG_REVERB_DEPTH:
714 modplug->reverb_depth = g_value_get_int (value);
716 case ARG_REVERB_DELAY:
717 modplug->reverb_delay = g_value_get_int (value);
720 modplug->megabass = g_value_get_boolean (value);
722 case ARG_MEGABASS_AMOUNT:
723 modplug->megabass_amount = g_value_get_int (value);
725 case ARG_MEGABASS_RANGE:
726 modplug->megabass_range = g_value_get_int (value);
728 case ARG_NOISE_REDUCTION:
729 modplug->noise_reduction = g_value_get_boolean (value);
732 modplug->surround = g_value_get_boolean (value);
734 case ARG_SURROUND_DEPTH:
735 modplug->surround_depth = g_value_get_int (value);
737 case ARG_SURROUND_DELAY:
738 modplug->surround_delay = g_value_get_int (value);
746 gst_modplug_get_property (GObject *object, guint id, GValue *value, GParamSpec *pspec )
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);
756 g_value_set_boolean (value, modplug->reverb);
758 case ARG_REVERB_DEPTH:
759 g_value_set_int (value, modplug->reverb_depth);
761 case ARG_REVERB_DELAY:
762 g_value_set_int (value, modplug->reverb_delay);
765 g_value_set_boolean (value, modplug->megabass);
767 case ARG_MEGABASS_AMOUNT:
768 g_value_set_int (value, modplug->megabass_amount);
770 case ARG_MEGABASS_RANGE:
771 g_value_set_int (value, modplug->megabass_range);
774 g_value_set_boolean (value, modplug->surround);
776 case ARG_SURROUND_DEPTH:
777 g_value_set_int (value, modplug->surround_depth);
779 case ARG_SURROUND_DELAY:
780 g_value_set_int (value, modplug->surround_delay);
782 case ARG_NOISE_REDUCTION:
783 g_value_set_boolean (value, modplug->noise_reduction);
791 plugin_init (GstPlugin *plugin)
793 /* this filter needs the bytestream package */
794 if (!gst_library_load ("gstbytestream"))
797 return gst_element_register (plugin, "modplug",
798 GST_RANK_PRIMARY, GST_TYPE_MODPLUG);
805 ".MOD audio decoding",