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.
23 #include "gstmikmod.h"
25 #include <gst/audio/audio.h>
28 /* elementfactory information */
29 GstElementDetails mikmod_details = {
31 "Codec/Audio/Decoder",
33 "Module decoder based on libmikmod",
35 "Jeremy SIMON <jsimon13@yahoo.fr>",
40 /* Filter signals and args */
64 static GstPadTemplate*
65 mikmod_src_factory (void)
67 static GstPadTemplate *template = NULL;
70 template = gst_pad_template_new (
77 GST_AUDIO_INT_PAD_TEMPLATE_PROPS
84 static GstPadTemplate*
85 mikmod_sink_factory (void)
87 static GstPadTemplate *template = NULL;
90 template = gst_pad_template_new (
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);
115 static GstElementClass *parent_class = NULL;
118 gst_mikmod_get_type(void) {
119 static GType mikmod_type = 0;
122 static const GTypeInfo mikmod_info = {
123 sizeof(GstMikModClass),
126 (GClassInitFunc)gst_mikmod_class_init,
131 (GInstanceInitFunc)gst_mikmod_init,
133 mikmod_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMikmod", &mikmod_info, 0);
140 gst_mikmod_class_init (GstMikModClass *klass)
142 GObjectClass *gobject_class;
143 GstElementClass *gstelement_class;
145 gobject_class = (GObjectClass*)klass;
146 gstelement_class = (GstElementClass*)klass;
148 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
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 ));
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 ));
192 gobject_class->set_property = gst_mikmod_set_property;
193 gobject_class->get_property = gst_mikmod_get_property;
195 gstelement_class->change_state = gst_mikmod_change_state;
200 gst_mikmod_init (GstMikMod *filter)
202 filter->sinkpad = gst_pad_new_from_template(mikmod_sink_factory (),"sink");
203 filter->srcpad = gst_pad_new_from_template(mikmod_src_factory (),"src");
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);
209 gst_element_set_loop_function (GST_ELEMENT (filter), gst_mikmod_loop);
211 filter->Buffer = NULL;
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;
220 filter->pansep = 128;
221 filter->musicvolume = 128;
223 filter->sndfxvolume = 128;
224 filter->songname = NULL;
225 filter->modtype = NULL;
229 static GstPadLinkReturn
230 gst_mikmod_negotiate (GstMikMod *mikmod)
234 if ( mikmod->_16bit ) {
242 return gst_pad_try_set_caps (mikmod->srcpad,
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)));
255 static GstPadLinkReturn
256 gst_mikmod_srclink (GstPad *pad, GstCaps *caps)
260 filter = GST_MIKMOD (gst_pad_get_parent (pad));
262 if (gst_caps_has_property_typed (caps, "depth", GST_PROPS_INT_TYPE)) {
264 gst_caps_get_int (caps, "depth", &depth);
265 filter->_16bit = (depth == 16);
267 if (gst_caps_has_property_typed (caps, "channels", GST_PROPS_INT_TYPE)) {
269 gst_caps_get_int (caps, "channels", &channels);
270 filter->stereo = (channels == 2);
272 if (gst_caps_has_property_typed (caps, "rate", GST_PROPS_INT_TYPE)) {
273 gst_caps_get_int (caps, "rate", &filter->mixfreq);
276 return gst_mikmod_negotiate(filter);
281 gst_mikmod_loop (GstElement *element)
284 GstBuffer *buffer_in;
286 g_return_if_fail (element != NULL);
287 g_return_if_fail (GST_IS_MIKMOD (element));
289 mikmod = GST_MIKMOD (element);
290 srcpad = mikmod->srcpad;
291 mikmod->Buffer = NULL;
293 while ((buffer_in = gst_pad_pull( mikmod->sinkpad ))) {
294 if ( GST_IS_EVENT (buffer_in) ) {
295 GstEvent *event = GST_EVENT (buffer_in);
297 if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)
302 if ( mikmod->Buffer ) {
303 mikmod->Buffer = gst_buffer_merge( mikmod->Buffer, buffer_in );
304 gst_buffer_unref( buffer_in );
307 mikmod->Buffer = buffer_in;
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");
318 gst_mikmod_setup( mikmod );
320 MikMod_RegisterDriver(&drv_gst);
321 MikMod_RegisterAllLoaders();
324 reader = GST_READER_new( mikmod );
325 module = Player_LoadGeneric ( reader, 64, 0 );
327 gst_buffer_unref (mikmod->Buffer);
329 if ( ! Player_Active() )
330 Player_Start(module);
333 if ( Player_Active() ) {
335 timestamp = ( module->sngtime / 1024.0 ) * GST_SECOND;
337 gst_element_yield (element);
340 gst_element_set_eos (GST_ELEMENT (mikmod));
341 gst_pad_push (mikmod->srcpad, GST_BUFFER (gst_event_new (GST_EVENT_EOS)));
350 gst_mikmod_setup (GstMikMod *mikmod)
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;
361 if ( mikmod->interp )
362 md_mode = md_mode | DMODE_INTERP;
364 if ( mikmod->reverse )
365 md_mode = md_mode | DMODE_REVERSE;
367 if ( mikmod->surround )
368 md_mode = md_mode | DMODE_SURROUND;
370 if ( mikmod->_16bit )
371 md_mode = md_mode | DMODE_16BITS;
373 if ( mikmod->hqmixer )
374 md_mode = md_mode | DMODE_HQMIXER;
376 if ( mikmod->soft_music )
377 md_mode = md_mode | DMODE_SOFT_MUSIC;
379 if ( mikmod->soft_sndfx )
380 md_mode = md_mode | DMODE_SOFT_SNDFX;
382 if ( mikmod->stereo )
383 md_mode = md_mode | DMODE_STEREO;
389 static GstElementStateReturn
390 gst_mikmod_change_state (GstElement *element)
394 g_return_val_if_fail (GST_IS_MIKMOD (element), GST_STATE_FAILURE);
396 mikmod = GST_MIKMOD (element);
398 GST_DEBUG ("state pending %d", GST_STATE_PENDING (element));
400 if (GST_STATE_PENDING (element) == GST_STATE_READY)
402 gst_mikmod_setup(mikmod);
404 if ( Player_Active() )
406 Player_TogglePause();
407 Player_SetPosition( 0 );
412 if (GST_STATE_PENDING (element) == GST_STATE_PLAYING)
414 if ( Player_Active() && Player_Paused() )
415 Player_TogglePause();
417 if ( ! Player_Active() )
418 Player_Start(module);
422 if (GST_STATE_PENDING (element) == GST_STATE_PAUSED)
423 if ( Player_Active() && ! Player_Paused() )
424 Player_TogglePause();
426 if (GST_STATE_PENDING (element) == GST_STATE_NULL)
430 if (GST_ELEMENT_CLASS (parent_class)->change_state)
431 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
433 return GST_STATE_SUCCESS;
439 gst_mikmod_set_property (GObject *object, guint id, const GValue *value, GParamSpec *pspec )
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);
449 g_free (filter->songname);
450 filter->songname = g_strdup (g_value_get_string (value));
453 g_free (filter->modtype);
454 filter->modtype = g_strdup (g_value_get_string (value));
456 case ARG_MUSICVOLUME:
457 filter->musicvolume = g_value_get_int (value);
460 filter->pansep = g_value_get_int (value);
463 filter->reverb = g_value_get_int (value);
465 case ARG_SNDFXVOLUME:
466 filter->sndfxvolume = g_value_get_int (value);
469 filter->volume = g_value_get_int (value);
472 filter->interp = g_value_get_boolean (value);
475 filter->reverse = g_value_get_boolean (value);
478 filter->surround = g_value_get_boolean (value);
481 filter->hqmixer = g_value_get_boolean (value);
484 filter->soft_music = g_value_get_boolean (value);
487 filter->soft_sndfx = g_value_get_boolean (value);
495 gst_mikmod_get_property (GObject *object, guint id, GValue *value, GParamSpec *pspec )
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);
504 case ARG_MUSICVOLUME:
505 g_value_set_int (value, filter->musicvolume);
508 g_value_set_int (value, filter->pansep);
511 g_value_set_int (value, filter->reverb);
513 case ARG_SNDFXVOLUME:
514 g_value_set_int (value, filter->sndfxvolume);
517 g_value_set_int (value, filter->volume);
520 g_value_set_boolean (value, filter->interp);
523 g_value_set_boolean (value, filter->reverse);
526 g_value_set_boolean (value, filter->surround);
529 g_value_set_boolean (value, filter->hqmixer);
532 g_value_set_boolean (value, filter->soft_music);
535 g_value_set_boolean (value, filter->soft_sndfx);
543 plugin_init (GModule *module, GstPlugin *plugin)
545 GstElementFactory *factory;
547 factory = gst_element_factory_new("mikmod",GST_TYPE_MIKMOD,
549 g_return_val_if_fail(factory != NULL, FALSE);
550 gst_element_factory_set_rank (factory, GST_ELEMENT_RANK_SECONDARY);
552 gst_element_factory_add_pad_template (factory, mikmod_src_factory ());
553 gst_element_factory_add_pad_template (factory, mikmod_sink_factory ());
555 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
560 GstPluginDesc plugin_desc = {