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/Decoder/Audio",
32 "Module decoder based on libmikmod",
33 "Jeremy SIMON <jsimon13@yahoo.fr>",
37 /* Filter signals and args */
61 static GstPadTemplate*
62 mikmod_src_factory (void)
64 static GstPadTemplate *template = NULL;
67 template = gst_pad_template_new (
74 GST_AUDIO_INT_PAD_TEMPLATE_PROPS
81 static GstPadTemplate*
82 mikmod_sink_factory (void)
84 static GstPadTemplate *template = NULL;
87 template = gst_pad_template_new (
100 static void gst_mikmod_base_init (gpointer g_class);
101 static void gst_mikmod_class_init (GstMikModClass *klass);
102 static void gst_mikmod_init (GstMikMod *filter);
103 static void gst_mikmod_set_property (GObject *object, guint id, const GValue *value, GParamSpec *pspec );
104 static void gst_mikmod_get_property (GObject *object, guint id, GValue *value, GParamSpec *pspec );
105 static GstPadLinkReturn gst_mikmod_srclink (GstPad *pad, GstCaps *caps);
106 static void gst_mikmod_loop (GstElement *element);
107 static gboolean gst_mikmod_setup (GstMikMod *mikmod);
108 static GstElementStateReturn gst_mikmod_change_state (GstElement *element);
112 static GstElementClass *parent_class = NULL;
115 gst_mikmod_get_type(void) {
116 static GType mikmod_type = 0;
119 static const GTypeInfo mikmod_info = {
120 sizeof(GstMikModClass),
121 gst_mikmod_base_init,
123 (GClassInitFunc)gst_mikmod_class_init,
128 (GInstanceInitFunc)gst_mikmod_init,
130 mikmod_type = g_type_register_static(GST_TYPE_ELEMENT, "GstMikmod", &mikmod_info, 0);
136 gst_mikmod_base_init (gpointer g_class)
138 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
140 gst_element_class_add_pad_template (element_class, mikmod_src_factory ());
141 gst_element_class_add_pad_template (element_class, mikmod_sink_factory ());
142 gst_element_class_set_details (element_class, &mikmod_details);
146 gst_mikmod_class_init (GstMikModClass *klass)
148 GObjectClass *gobject_class;
149 GstElementClass *gstelement_class;
151 gobject_class = (GObjectClass*)klass;
152 gstelement_class = (GstElementClass*)klass;
154 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
156 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SONGNAME,
157 g_param_spec_string("songname","songname","songname",
158 NULL, G_PARAM_READABLE));
159 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MODTYPE,
160 g_param_spec_string("modtype", "modtype", "modtype",
161 NULL, G_PARAM_READABLE ));
162 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MUSICVOLUME,
163 g_param_spec_int("musicvolume", "musivolume", "musicvolume",
164 0, 128, 128, G_PARAM_READWRITE ));
165 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PANSEP,
166 g_param_spec_int("pansep", "pansep", "pansep",
167 0, 128, 128, G_PARAM_READWRITE ));
168 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_REVERB,
169 g_param_spec_int("reverb", "reverb", "reverb",
170 0, 15, 0, G_PARAM_READWRITE ));
171 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SNDFXVOLUME,
172 g_param_spec_int("sndfxvolume", "sndfxvolume", "sndfxvolume",
173 0, 128, 128, G_PARAM_READWRITE ));
174 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VOLUME,
175 g_param_spec_int("volume", "volume", "volume",
176 0, 128, 96, G_PARAM_READWRITE ));
178 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_INTERP,
179 g_param_spec_boolean("interp", "interp", "interp",
180 FALSE, G_PARAM_READWRITE ));
181 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_REVERSE,
182 g_param_spec_boolean("reverse", "reverse", "reverse",
183 FALSE, G_PARAM_READWRITE ));
184 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SURROUND,
185 g_param_spec_boolean("surround", "surround", "surround",
186 TRUE, G_PARAM_READWRITE ));
187 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HQMIXER,
188 g_param_spec_boolean("hqmixer", "hqmixer", "hqmixer",
189 FALSE, G_PARAM_READWRITE ));
190 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SOFT_MUSIC,
191 g_param_spec_boolean("soft_music", "soft_music", "soft_music",
192 TRUE, G_PARAM_READWRITE ));
193 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SOFT_SNDFX,
194 g_param_spec_boolean("soft_sndfx", "soft_sndfx", "soft_sndfx",
195 TRUE, G_PARAM_READWRITE ));
198 gobject_class->set_property = gst_mikmod_set_property;
199 gobject_class->get_property = gst_mikmod_get_property;
201 gstelement_class->change_state = gst_mikmod_change_state;
206 gst_mikmod_init (GstMikMod *filter)
208 filter->sinkpad = gst_pad_new_from_template(mikmod_sink_factory (),"sink");
209 filter->srcpad = gst_pad_new_from_template(mikmod_src_factory (),"src");
211 gst_element_add_pad(GST_ELEMENT(filter),filter->sinkpad);
212 gst_element_add_pad(GST_ELEMENT(filter),filter->srcpad);
213 gst_pad_set_link_function (filter->srcpad, gst_mikmod_srclink);
215 gst_element_set_loop_function (GST_ELEMENT (filter), gst_mikmod_loop);
217 filter->Buffer = NULL;
219 filter->stereo = TRUE;
220 filter->surround = TRUE;
221 filter->_16bit = TRUE;
222 filter->soft_music = TRUE;
223 filter->soft_sndfx = TRUE;
224 filter->mixfreq = 44100;
226 filter->pansep = 128;
227 filter->musicvolume = 128;
229 filter->sndfxvolume = 128;
230 filter->songname = NULL;
231 filter->modtype = NULL;
235 static GstPadLinkReturn
236 gst_mikmod_negotiate (GstMikMod *mikmod)
240 if ( mikmod->_16bit ) {
248 return gst_pad_try_set_caps (mikmod->srcpad,
252 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
253 "signed", GST_PROPS_BOOLEAN (sign),
254 "width", GST_PROPS_INT (width),
255 "depth", GST_PROPS_INT (width),
256 "rate", GST_PROPS_INT (mikmod->mixfreq),
257 "channels", GST_PROPS_INT (mikmod->stereo ? 2 : 1)));
261 static GstPadLinkReturn
262 gst_mikmod_srclink (GstPad *pad, GstCaps *caps)
266 filter = GST_MIKMOD (gst_pad_get_parent (pad));
268 if (gst_caps_has_property_typed (caps, "depth", GST_PROPS_INT_TYPE)) {
270 gst_caps_get_int (caps, "depth", &depth);
271 filter->_16bit = (depth == 16);
273 if (gst_caps_has_property_typed (caps, "channels", GST_PROPS_INT_TYPE)) {
275 gst_caps_get_int (caps, "channels", &channels);
276 filter->stereo = (channels == 2);
278 if (gst_caps_has_property_typed (caps, "rate", GST_PROPS_INT_TYPE)) {
279 gst_caps_get_int (caps, "rate", &filter->mixfreq);
282 return gst_mikmod_negotiate(filter);
287 gst_mikmod_loop (GstElement *element)
290 GstBuffer *buffer_in;
292 g_return_if_fail (element != NULL);
293 g_return_if_fail (GST_IS_MIKMOD (element));
295 mikmod = GST_MIKMOD (element);
296 srcpad = mikmod->srcpad;
297 mikmod->Buffer = NULL;
299 while ((buffer_in = GST_BUFFER (gst_pad_pull( mikmod->sinkpad )))) {
300 if ( GST_IS_EVENT (buffer_in) ) {
301 GstEvent *event = GST_EVENT (buffer_in);
303 if (GST_EVENT_TYPE (event) == GST_EVENT_EOS)
308 if ( mikmod->Buffer ) {
309 mikmod->Buffer = gst_buffer_merge( mikmod->Buffer, buffer_in );
310 gst_buffer_unref( buffer_in );
313 mikmod->Buffer = buffer_in;
317 if (!GST_PAD_CAPS (mikmod->srcpad)) {
318 if (gst_mikmod_negotiate (mikmod) <= 0) {
319 gst_element_error (GST_ELEMENT (mikmod),
320 "Failed to negotiate with next element in mikmod");
324 gst_mikmod_setup( mikmod );
326 MikMod_RegisterDriver(&drv_gst);
327 MikMod_RegisterAllLoaders();
330 reader = GST_READER_new( mikmod );
331 module = Player_LoadGeneric ( reader, 64, 0 );
333 gst_buffer_unref (mikmod->Buffer);
335 if ( ! Player_Active() )
336 Player_Start(module);
339 if ( Player_Active() ) {
341 timestamp = ( module->sngtime / 1024.0 ) * GST_SECOND;
343 gst_element_yield (element);
346 gst_element_set_eos (GST_ELEMENT (mikmod));
347 gst_pad_push (mikmod->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
356 gst_mikmod_setup (GstMikMod *mikmod)
358 md_musicvolume = mikmod->musicvolume;
359 md_pansep = mikmod->pansep;
360 md_reverb = mikmod->reverb;
361 md_sndfxvolume = mikmod->sndfxvolume;
362 md_volume = mikmod->volume;
363 md_mixfreq = mikmod->mixfreq;
367 if ( mikmod->interp )
368 md_mode = md_mode | DMODE_INTERP;
370 if ( mikmod->reverse )
371 md_mode = md_mode | DMODE_REVERSE;
373 if ( mikmod->surround )
374 md_mode = md_mode | DMODE_SURROUND;
376 if ( mikmod->_16bit )
377 md_mode = md_mode | DMODE_16BITS;
379 if ( mikmod->hqmixer )
380 md_mode = md_mode | DMODE_HQMIXER;
382 if ( mikmod->soft_music )
383 md_mode = md_mode | DMODE_SOFT_MUSIC;
385 if ( mikmod->soft_sndfx )
386 md_mode = md_mode | DMODE_SOFT_SNDFX;
388 if ( mikmod->stereo )
389 md_mode = md_mode | DMODE_STEREO;
395 static GstElementStateReturn
396 gst_mikmod_change_state (GstElement *element)
400 g_return_val_if_fail (GST_IS_MIKMOD (element), GST_STATE_FAILURE);
402 mikmod = GST_MIKMOD (element);
404 GST_DEBUG ("state pending %d", GST_STATE_PENDING (element));
406 if (GST_STATE_PENDING (element) == GST_STATE_READY)
408 gst_mikmod_setup(mikmod);
410 if ( Player_Active() )
412 Player_TogglePause();
413 Player_SetPosition( 0 );
418 if (GST_STATE_PENDING (element) == GST_STATE_PLAYING)
420 if ( Player_Active() && Player_Paused() )
421 Player_TogglePause();
423 if ( ! Player_Active() )
424 Player_Start(module);
428 if (GST_STATE_PENDING (element) == GST_STATE_PAUSED)
429 if ( Player_Active() && ! Player_Paused() )
430 Player_TogglePause();
432 if (GST_STATE_PENDING (element) == GST_STATE_NULL)
436 if (GST_ELEMENT_CLASS (parent_class)->change_state)
437 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
439 return GST_STATE_SUCCESS;
445 gst_mikmod_set_property (GObject *object, guint id, const GValue *value, GParamSpec *pspec )
449 /* it's not null if we got it, but it might not be ours */
450 g_return_if_fail(GST_IS_MIKMOD(object));
451 filter = GST_MIKMOD(object);
455 g_free (filter->songname);
456 filter->songname = g_strdup (g_value_get_string (value));
459 g_free (filter->modtype);
460 filter->modtype = g_strdup (g_value_get_string (value));
462 case ARG_MUSICVOLUME:
463 filter->musicvolume = g_value_get_int (value);
466 filter->pansep = g_value_get_int (value);
469 filter->reverb = g_value_get_int (value);
471 case ARG_SNDFXVOLUME:
472 filter->sndfxvolume = g_value_get_int (value);
475 filter->volume = g_value_get_int (value);
478 filter->interp = g_value_get_boolean (value);
481 filter->reverse = g_value_get_boolean (value);
484 filter->surround = g_value_get_boolean (value);
487 filter->hqmixer = g_value_get_boolean (value);
490 filter->soft_music = g_value_get_boolean (value);
493 filter->soft_sndfx = g_value_get_boolean (value);
501 gst_mikmod_get_property (GObject *object, guint id, GValue *value, GParamSpec *pspec )
505 /* it's not null if we got it, but it might not be ours */
506 g_return_if_fail(GST_IS_MIKMOD(object));
507 filter = GST_MIKMOD(object);
510 case ARG_MUSICVOLUME:
511 g_value_set_int (value, filter->musicvolume);
514 g_value_set_int (value, filter->pansep);
517 g_value_set_int (value, filter->reverb);
519 case ARG_SNDFXVOLUME:
520 g_value_set_int (value, filter->sndfxvolume);
523 g_value_set_int (value, filter->volume);
526 g_value_set_boolean (value, filter->interp);
529 g_value_set_boolean (value, filter->reverse);
532 g_value_set_boolean (value, filter->surround);
535 g_value_set_boolean (value, filter->hqmixer);
538 g_value_set_boolean (value, filter->soft_music);
541 g_value_set_boolean (value, filter->soft_sndfx);
549 plugin_init (GstPlugin *plugin)
551 if (!gst_element_register (plugin, "mikmod", GST_RANK_NONE, GST_TYPE_MIKMOD))
561 "Mikmod plugin library",