gstmodplug.cc 26.5 KB
Newer Older
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1
/* GStreamer
Jeremy Simon's avatar
Jeremy Simon committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
19

20 21 22 23 24 25 26
/* 
   Code based on modplugxmms
   XMMS plugin:
     Kenton Varda <temporal@gauge3d.org>
   Sound Engine:
     Olivier Lapicque <olivierl@jps.net>  
*/
Jeremy Simon's avatar
Jeremy Simon committed
27

28
/**
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
29 30 31 32
 * SECTION:element-modplug
 * 
 * Modplug uses the <ulink url="http://modplug-xmms.sourceforge.net/">modplug</ulink>
 * library to decode tracked music in the MOD/S3M/XM/IT and related formats.
33 34
 * 
 * <refsect2>
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
35
 * <title>Example pipeline</title>
36
 * |[
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
37
 * gst-launch -v filesrc location=1990s-nostalgia.xm ! modplug ! audioconvert ! alsasink
38
 * ]| Play a FastTracker xm file.
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
39 40 41
 * </refsect2>
 */

42 43 44 45
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

46 47 48 49
/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
 * with newer GLib versions (>= 2.31.0) */
#define GLIB_DISABLE_DEPRECATION_WARNINGS

50 51 52 53 54 55 56
/* Required to not get an undefined warning
 * https://bugzilla.gnome.org/show_bug.cgi?id=613795
 */
#ifndef WORDS_BIGENDIAN
#define WORDS_BIGENDIAN 0
#endif

57
#include <stdafx.h>
LRN's avatar
LRN committed
58
#include <libmodplug/sndfile.h>
Jeremy Simon's avatar
Jeremy Simon committed
59 60 61

#include "gstmodplug.h"

Jeremy Simon's avatar
Jeremy Simon committed
62
#include <gst/gst.h>
Jeremy Simon's avatar
Jeremy Simon committed
63
#include <stdlib.h>
64
#include <gst/audio/audio.h>
Jeremy Simon's avatar
Jeremy Simon committed
65

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
66 67 68
GST_DEBUG_CATEGORY_STATIC (modplug_debug);
#define GST_CAT_DEFAULT modplug_debug

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
69 70
enum
{
Jeremy Simon's avatar
Jeremy Simon committed
71 72 73 74 75 76 77 78 79 80 81 82
  ARG_0,
  ARG_SONGNAME,
  ARG_REVERB,
  ARG_REVERB_DEPTH,
  ARG_REVERB_DELAY,
  ARG_MEGABASS,
  ARG_MEGABASS_AMOUNT,
  ARG_MEGABASS_RANGE,
  ARG_NOISE_REDUCTION,
  ARG_SURROUND,
  ARG_SURROUND_DEPTH,
  ARG_SURROUND_DELAY,
David Schleef's avatar
David Schleef committed
83
  ARG_OVERSAMP
Jeremy Simon's avatar
Jeremy Simon committed
84 85
};

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
86 87 88 89 90 91 92 93 94 95 96 97
#define DEFAULT_REVERB           FALSE
#define DEFAULT_REVERB_DEPTH     30
#define DEFAULT_REVERB_DELAY     100
#define DEFAULT_MEGABASS         FALSE
#define DEFAULT_MEGABASS_AMOUNT  40
#define DEFAULT_MEGABASS_RANGE   30
#define DEFAULT_SURROUND         TRUE
#define DEFAULT_SURROUND_DEPTH   20
#define DEFAULT_SURROUND_DELAY   20
#define DEFAULT_OVERSAMP         TRUE
#define DEFAULT_NOISE_REDUCTION  TRUE

Wim Taymans's avatar
Wim Taymans committed
98 99
#define FORMATS "{ "GST_AUDIO_NE (S32)", "GST_AUDIO_NE (S16)", U8 }"

David Schleef's avatar
David Schleef committed
100
static GstStaticPadTemplate modplug_src_template_factory =
101
GST_STATIC_PAD_TEMPLATE ("src",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
102 103
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
Wim Taymans's avatar
Wim Taymans committed
104 105 106
    GST_STATIC_CAPS ("audio/x-raw,"
        " format = (string) " FORMATS ", "
        " layout = (string) interleaved, "
107 108
        " rate = (int) { 8000, 11025, 22050, 44100 },"
        " channels = (int) [ 1, 2 ]"));
Jeremy Simon's avatar
Jeremy Simon committed
109

David Schleef's avatar
David Schleef committed
110
static GstStaticPadTemplate modplug_sink_template_factory =
111
    GST_STATIC_PAD_TEMPLATE ("sink",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
112 113
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
114 115
    GST_STATIC_CAPS ("audio/x-mod; audio/x-xm; audio/x-it; audio/x-s3m; "
        "audio/x-stm"));
Jeremy Simon's avatar
Jeremy Simon committed
116

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
117
static void gst_modplug_dispose (GObject * object);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
118 119 120 121
static void gst_modplug_set_property (GObject * object,
    guint id, const GValue * value, GParamSpec * pspec);
static void gst_modplug_get_property (GObject * object,
    guint id, GValue * value, GParamSpec * pspec);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
122

Wim Taymans's avatar
Wim Taymans committed
123 124 125 126
static gboolean gst_modplug_src_event (GstPad * pad, GstObject * parent,
    GstEvent * event);
static gboolean gst_modplug_src_query (GstPad * pad, GstObject * parent,
    GstQuery * query);
127 128
static GstStateChangeReturn gst_modplug_change_state (GstElement * element,
    GstStateChange transition);
Jeremy Simon's avatar
Jeremy Simon committed
129

Wim Taymans's avatar
Wim Taymans committed
130 131 132
static gboolean gst_modplug_sinkpad_activate (GstPad * pad, GstObject * parent);
static gboolean gst_modplug_sinkpad_activate_mode (GstPad * pad,
    GstObject * parent, GstPadMode mode, gboolean active);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
133
static void gst_modplug_loop (GstModPlug * element);
Jeremy Simon's avatar
Jeremy Simon committed
134

Wim Taymans's avatar
Wim Taymans committed
135 136
#define parent_class gst_modplug_parent_class
G_DEFINE_TYPE (GstModPlug, gst_modplug, GST_TYPE_ELEMENT);
Jeremy Simon's avatar
Jeremy Simon committed
137 138

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
139
gst_modplug_class_init (GstModPlugClass * klass)
Jeremy Simon's avatar
Jeremy Simon committed
140 141 142 143
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
144 145 146
  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
147 148 149
  gobject_class->set_property = gst_modplug_set_property;
  gobject_class->get_property = gst_modplug_get_property;
  gobject_class->dispose = gst_modplug_dispose;
Jeremy Simon's avatar
Jeremy Simon committed
150

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
151 152
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SONGNAME,
      g_param_spec_string ("songname", "Songname", "The song name",
153
          NULL, (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
154

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
155
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_REVERB,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
156
      g_param_spec_boolean ("reverb", "reverb", "Reverb",
157 158
          DEFAULT_REVERB,
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
159

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
160
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_REVERB_DEPTH,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
161
      g_param_spec_int ("reverb-depth", "reverb depth", "Reverb depth",
162 163
          0, 100, DEFAULT_REVERB_DEPTH,
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
164

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
165
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_REVERB_DELAY,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
166
      g_param_spec_int ("reverb-delay", "reverb delay", "Reverb delay",
167 168
          0, 200, DEFAULT_REVERB_DELAY,
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
169

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
170
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MEGABASS,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
171
      g_param_spec_boolean ("megabass", "megabass", "Megabass",
172 173
          DEFAULT_MEGABASS,
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
174

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
175
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MEGABASS_AMOUNT,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
176
      g_param_spec_int ("megabass-amount", "megabass amount", "Megabass amount",
177 178
          0, 100, DEFAULT_MEGABASS_AMOUNT,
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
179

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
180
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MEGABASS_RANGE,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
181
      g_param_spec_int ("megabass-range", "megabass range", "Megabass range",
182 183
          0, 100, DEFAULT_MEGABASS_RANGE,
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
184

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
185
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SURROUND,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
186
      g_param_spec_boolean ("surround", "surround", "Surround",
187 188
          DEFAULT_SURROUND,
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
189

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
190
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SURROUND_DEPTH,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
191
      g_param_spec_int ("surround-depth", "surround depth", "Surround depth",
192 193
          0, 100, DEFAULT_SURROUND_DEPTH,
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
194

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
195
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SURROUND_DELAY,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
196
      g_param_spec_int ("surround-delay", "surround delay", "Surround delay",
197 198
          0, 40, DEFAULT_SURROUND_DELAY,
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
199

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
200 201
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_OVERSAMP,
      g_param_spec_boolean ("oversamp", "oversamp", "oversamp",
202 203
          DEFAULT_OVERSAMP,
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
204

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
205
  g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NOISE_REDUCTION,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
206 207
      g_param_spec_boolean ("noise-reduction", "noise reduction",
          "noise reduction", DEFAULT_NOISE_REDUCTION,
208
          (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
Jeremy Simon's avatar
Jeremy Simon committed
209

210
  gstelement_class->change_state = gst_modplug_change_state;
Wim Taymans's avatar
Wim Taymans committed
211 212 213 214 215 216

  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&modplug_sink_template_factory));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&modplug_src_template_factory));

217
  gst_element_class_set_metadata (gstelement_class, "ModPlug",
Wim Taymans's avatar
Wim Taymans committed
218 219 220 221
      "Codec/Decoder/Audio", "Module decoder based on modplug engine",
      "Jeremy SIMON <jsimon13@yahoo.fr>");

  GST_DEBUG_CATEGORY_INIT (modplug_debug, "modplug", 0, "ModPlug element");
Jeremy Simon's avatar
Jeremy Simon committed
222 223 224
}

static void
Wim Taymans's avatar
Wim Taymans committed
225
gst_modplug_init (GstModPlug * modplug)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
226
{
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
227
  /* create the sink and src pads */
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
228
  modplug->sinkpad =
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
229 230 231
      gst_pad_new_from_static_template (&modplug_sink_template_factory, "sink");
  gst_pad_set_activate_function (modplug->sinkpad,
      GST_DEBUG_FUNCPTR (gst_modplug_sinkpad_activate));
Wim Taymans's avatar
Wim Taymans committed
232 233
  gst_pad_set_activatemode_function (modplug->sinkpad,
      GST_DEBUG_FUNCPTR (gst_modplug_sinkpad_activate_mode));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
234 235 236
  gst_element_add_pad (GST_ELEMENT (modplug), modplug->sinkpad);

  modplug->srcpad =
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
237
      gst_pad_new_from_static_template (&modplug_src_template_factory, "src");
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
238
  gst_pad_set_event_function (modplug->srcpad,
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
239 240 241
      GST_DEBUG_FUNCPTR (gst_modplug_src_event));
  gst_pad_set_query_function (modplug->srcpad,
      GST_DEBUG_FUNCPTR (gst_modplug_src_query));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
242 243
  gst_element_add_pad (GST_ELEMENT (modplug), modplug->srcpad);

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
244 245 246 247 248 249 250 251 252 253 254
  modplug->reverb = DEFAULT_REVERB;
  modplug->reverb_depth = DEFAULT_REVERB_DEPTH;
  modplug->reverb_delay = DEFAULT_REVERB_DELAY;
  modplug->megabass = DEFAULT_MEGABASS;
  modplug->megabass_amount = DEFAULT_MEGABASS_AMOUNT;
  modplug->megabass_range = DEFAULT_MEGABASS_RANGE;
  modplug->surround = DEFAULT_SURROUND;
  modplug->surround_depth = DEFAULT_SURROUND_DEPTH;
  modplug->surround_delay = DEFAULT_SURROUND_DELAY;
  modplug->oversamp = DEFAULT_OVERSAMP;
  modplug->noise_reduction = DEFAULT_NOISE_REDUCTION;
Jeremy Simon's avatar
Jeremy Simon committed
255

256
  modplug->bits = 16;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
257 258
  modplug->channel = 2;
  modplug->frequency = 44100;
Jeremy Simon's avatar
Jeremy Simon committed
259 260
}

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
261

Jeremy Simon's avatar
Jeremy Simon committed
262
static void
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
263
gst_modplug_dispose (GObject * object)
Jeremy Simon's avatar
Jeremy Simon committed
264
{
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
265
  GstModPlug *modplug = GST_MODPLUG (object);
Jeremy Simon's avatar
Jeremy Simon committed
266

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
267
  G_OBJECT_CLASS (parent_class)->dispose (object);
Jeremy Simon's avatar
Jeremy Simon committed
268

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
269 270 271 272
  if (modplug->buffer) {
    gst_buffer_unref (modplug->buffer);
    modplug->buffer = NULL;
  }
Jeremy Simon's avatar
Jeremy Simon committed
273
}
Jeremy Simon's avatar
Jeremy Simon committed
274 275

static gboolean
Wim Taymans's avatar
Wim Taymans committed
276
gst_modplug_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
Jeremy Simon's avatar
Jeremy Simon committed
277 278
{
  GstModPlug *modplug;
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
279
  gboolean res = FALSE;
Jeremy Simon's avatar
Jeremy Simon committed
280

Wim Taymans's avatar
Wim Taymans committed
281
  modplug = GST_MODPLUG (parent);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
282 283 284 285 286 287

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_DURATION:
    {
      GstFormat format;

Wim Taymans's avatar
Wim Taymans committed
288 289 290
      if (!modplug->mSoundFile)
        goto done;

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
291 292 293 294
      gst_query_parse_duration (query, &format, NULL);
      if (format == GST_FORMAT_TIME) {
        gst_query_set_duration (query, format, modplug->song_length);
        res = TRUE;
Jeremy Simon's avatar
Jeremy Simon committed
295
      }
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
296
    }
Jeremy Simon's avatar
Jeremy Simon committed
297
      break;
Wim Taymans's avatar
Wim Taymans committed
298
    case GST_QUERY_POSITION:
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
299 300 301
    {
      GstFormat format;

Wim Taymans's avatar
Wim Taymans committed
302 303 304
      if (!modplug->mSoundFile)
        goto done;

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
305 306 307 308
      gst_query_parse_position (query, &format, NULL);
      if (format == GST_FORMAT_TIME) {
        gint64 pos;

309 310
        pos = (modplug->song_length * modplug->mSoundFile->GetCurrentPos ());
        pos /= modplug->mSoundFile->GetMaxPosition ();
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
311 312
        gst_query_set_position (query, format, pos);
        res = TRUE;
Jeremy Simon's avatar
Jeremy Simon committed
313
      }
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
314
    }
315
      break;
Jeremy Simon's avatar
Jeremy Simon committed
316
    default:
Wim Taymans's avatar
Wim Taymans committed
317
      res = gst_pad_query_default (pad, parent, query);
Jeremy Simon's avatar
Jeremy Simon committed
318 319 320
      break;
  }

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
321
done:
Jeremy Simon's avatar
Jeremy Simon committed
322
  return res;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
323 324
}

Jeremy Simon's avatar
Jeremy Simon committed
325
static gboolean
Wim Taymans's avatar
Wim Taymans committed
326
gst_modplug_do_seek (GstModPlug * modplug, GstEvent * event)
Jeremy Simon's avatar
Jeremy Simon committed
327
{
Wim Taymans's avatar
Wim Taymans committed
328 329 330 331 332 333 334
  gdouble rate;
  GstFormat format;
  GstSeekFlags flags;
  GstSeekType cur_type, stop_type;
  gboolean flush;
  gint64 cur, stop;
  GstSegment seg;
335 336
/* FIXME timestamp is set but not used */
#if 0
Wim Taymans's avatar
Wim Taymans committed
337
  guint64 timestamp;
338
#endif
Jeremy Simon's avatar
Jeremy Simon committed
339

Wim Taymans's avatar
Wim Taymans committed
340 341
  if (modplug->frequency == 0)
    goto no_song;
Jeremy Simon's avatar
Jeremy Simon committed
342

343
#if 0
Wim Taymans's avatar
Wim Taymans committed
344 345
  timestamp = gst_util_uint64_scale_int (modplug->offset, GST_SECOND,
      modplug->frequency);
346
#endif
Jeremy Simon's avatar
Jeremy Simon committed
347

Wim Taymans's avatar
Wim Taymans committed
348 349
  gst_event_parse_seek (event, &rate, &format, &flags,
      &cur_type, &cur, &stop_type, &stop);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
350

Wim Taymans's avatar
Wim Taymans committed
351 352
  if (format != GST_FORMAT_TIME)
    goto no_time;
Jeremy Simon's avatar
Jeremy Simon committed
353

Wim Taymans's avatar
Wim Taymans committed
354 355 356
  /* FIXME: we should be using GstSegment for all this */
  if (cur_type != GST_SEEK_TYPE_SET || stop_type != GST_SEEK_TYPE_NONE)
    goto not_supported;
Jeremy Simon's avatar
Jeremy Simon committed
357

Wim Taymans's avatar
Wim Taymans committed
358 359
  if (stop_type == GST_SEEK_TYPE_NONE)
    stop = GST_CLOCK_TIME_NONE;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
360

Wim Taymans's avatar
Wim Taymans committed
361
  cur = CLAMP (cur, 0, modplug->song_length);
Jeremy Simon's avatar
Jeremy Simon committed
362

Wim Taymans's avatar
Wim Taymans committed
363 364
  GST_DEBUG_OBJECT (modplug, "seek to %" GST_TIME_FORMAT,
      GST_TIME_ARGS ((guint64) cur));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
365

Wim Taymans's avatar
Wim Taymans committed
366
  modplug->seek_at = cur;
Jeremy Simon's avatar
Jeremy Simon committed
367

Wim Taymans's avatar
Wim Taymans committed
368
  flush = ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
Jeremy Simon's avatar
Jeremy Simon committed
369

Wim Taymans's avatar
Wim Taymans committed
370 371 372 373 374
  if (flush) {
    gst_pad_push_event (modplug->srcpad, gst_event_new_flush_start ());
  } else {
    gst_pad_stop_task (modplug->sinkpad);
  }
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
375

Wim Taymans's avatar
Wim Taymans committed
376
  GST_PAD_STREAM_LOCK (modplug->sinkpad);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
377

Wim Taymans's avatar
Wim Taymans committed
378 379 380 381 382 383
  if (flags & GST_SEEK_FLAG_SEGMENT) {
    gst_element_post_message (GST_ELEMENT (modplug),
        gst_message_new_segment_start (GST_OBJECT (modplug), format, cur));
  }
  if (stop == -1 && modplug->song_length > 0)
    stop = modplug->song_length;
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
384

Wim Taymans's avatar
Wim Taymans committed
385 386 387
  if (flush) {
    gst_pad_push_event (modplug->srcpad, gst_event_new_flush_stop (TRUE));
  }
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
388

Wim Taymans's avatar
Wim Taymans committed
389 390 391 392
  GST_LOG_OBJECT (modplug, "sending newsegment from %" GST_TIME_FORMAT "-%"
      GST_TIME_FORMAT ", pos=%" GST_TIME_FORMAT,
      GST_TIME_ARGS ((guint64) cur), GST_TIME_ARGS ((guint64) stop),
      GST_TIME_ARGS ((guint64) cur));
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
393

Wim Taymans's avatar
Wim Taymans committed
394 395 396 397 398 399
  gst_segment_init (&seg, GST_FORMAT_TIME);
  seg.rate = rate;
  seg.start = cur;
  seg.stop = stop;
  seg.time = cur;
  gst_pad_push_event (modplug->srcpad, gst_event_new_segment (&seg));
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
400

Wim Taymans's avatar
Wim Taymans committed
401 402
  modplug->offset =
      gst_util_uint64_scale_int (cur, modplug->frequency, GST_SECOND);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
403

Wim Taymans's avatar
Wim Taymans committed
404
  gst_pad_start_task (modplug->sinkpad,
Wim Taymans's avatar
Wim Taymans committed
405
      (GstTaskFunction) gst_modplug_loop, modplug, NULL);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
406

Wim Taymans's avatar
Wim Taymans committed
407
  GST_PAD_STREAM_UNLOCK (modplug->sinkpad);
408

Wim Taymans's avatar
Wim Taymans committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
  return TRUE;

  /* ERROR */
no_song:
  {
    GST_DEBUG_OBJECT (modplug, "no song loaded yet");
    return FALSE;
  }
no_time:
  {
    GST_DEBUG_OBJECT (modplug, "seeking is only supported in TIME format");
    return FALSE;
  }
not_supported:
  {
    GST_DEBUG_OBJECT (modplug, "unsupported seek type");
    return FALSE;
  }
Jeremy Simon's avatar
Jeremy Simon committed
427 428
}

Wim Taymans's avatar
Wim Taymans committed
429 430
static gboolean
gst_modplug_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
431
{
Wim Taymans's avatar
Wim Taymans committed
432 433
  GstModPlug *modplug;
  gboolean res = FALSE;
Jeremy Simon's avatar
Jeremy Simon committed
434

Wim Taymans's avatar
Wim Taymans committed
435 436 437 438 439 440 441 442 443 444 445
  modplug = GST_MODPLUG (parent);

  switch (GST_EVENT_TYPE (event)) {
    case GST_EVENT_SEEK:
      res = gst_modplug_do_seek (modplug, event);
      break;
    default:
      res = gst_pad_event_default (pad, parent, event);
      break;
  }
  return res;
Jeremy Simon's avatar
Jeremy Simon committed
446 447
}

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
448 449
static gboolean
gst_modplug_load_song (GstModPlug * modplug)
450
{
Wim Taymans's avatar
Wim Taymans committed
451
  GstCaps *newcaps;
David Schleef's avatar
David Schleef committed
452
  GstStructure *structure;
Wim Taymans's avatar
Wim Taymans committed
453
  GstMapInfo map;
454
  const gchar *format;
455

456
  GST_DEBUG_OBJECT (modplug, "Setting caps");
David Schleef's avatar
David Schleef committed
457

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
458
  /* negotiate srcpad caps */
Wim Taymans's avatar
Wim Taymans committed
459 460
  if ((newcaps = gst_pad_get_allowed_caps (modplug->srcpad)) == NULL) {
    newcaps = gst_pad_get_pad_template_caps (modplug->srcpad);
461
  }
Wim Taymans's avatar
Wim Taymans committed
462 463
  newcaps = gst_caps_make_writable (newcaps);

464
  GST_DEBUG_OBJECT (modplug, "allowed caps %" GST_PTR_FORMAT, newcaps);
Wim Taymans's avatar
Wim Taymans committed
465 466 467

  structure = gst_caps_get_structure (newcaps, 0);

468 469
  if (!gst_structure_fixate_field_string (structure, "format",
          GST_AUDIO_NE (S16)))
Wim Taymans's avatar
Wim Taymans committed
470 471 472 473
    GST_WARNING_OBJECT (modplug, "Failed to fixate format to S16NE");
  if (!gst_structure_fixate_field_nearest_int (structure, "rate", 44100))
    GST_WARNING_OBJECT (modplug, "Failed to fixate rate to 44100");
  if (!gst_structure_fixate_field_nearest_int (structure, "channels", 2))
474 475
    GST_WARNING_OBJECT (modplug,
        "Failed to fixate number of channels to stereo");
Wim Taymans's avatar
Wim Taymans committed
476

477
  GST_DEBUG_OBJECT (modplug, "normalized caps %" GST_PTR_FORMAT, newcaps);
Wim Taymans's avatar
Wim Taymans committed
478

Wim Taymans's avatar
Wim Taymans committed
479
  newcaps = gst_caps_fixate (newcaps);
Wim Taymans's avatar
Wim Taymans committed
480

481
  GST_DEBUG_OBJECT (modplug, "fixated caps %" GST_PTR_FORMAT, newcaps);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
482 483 484

  /* set up modplug to output the negotiated format */
  structure = gst_caps_get_structure (newcaps, 0);
Wim Taymans's avatar
Wim Taymans committed
485 486 487 488 489 490 491 492 493
  format = gst_structure_get_string (structure, "format");

  if (g_str_equal (format, GST_AUDIO_NE (S32)))
    modplug->bits = 32;
  else if (g_str_equal (format, GST_AUDIO_NE (S16)))
    modplug->bits = 16;
  else
    modplug->bits = 8;

David Schleef's avatar
David Schleef committed
494 495
  gst_structure_get_int (structure, "channels", &modplug->channel);
  gst_structure_get_int (structure, "rate", &modplug->frequency);
496 497

  GST_DEBUG_OBJECT (modplug,
498 499
      "Audio settings: %d bits, %d channel(s), %d Hz sampling rate",
      modplug->bits, modplug->channel, modplug->frequency);
500

Vincent Penquerc'h's avatar
Vincent Penquerc'h committed
501 502 503
  gst_pad_set_caps (modplug->srcpad, newcaps);
  gst_caps_unref (newcaps);

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
504
  modplug->read_samples = 1152;
Sebastian Dröge's avatar
Sebastian Dröge committed
505 506
  modplug->read_bytes =
      modplug->read_samples * modplug->channel * modplug->bits / 8;
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
507

508 509 510 511
  GST_DEBUG_OBJECT (modplug, "Loading song");

  modplug->mSoundFile = new CSoundFile;

512
  modplug->mSoundFile->SetWaveConfig (modplug->frequency, modplug->bits,
Sebastian Dröge's avatar
Sebastian Dröge committed
513
      modplug->channel);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
514 515 516 517

  modplug->mSoundFile->SetWaveConfigEx (modplug->surround, !modplug->oversamp,
      modplug->reverb, true, modplug->megabass, modplug->noise_reduction, true);
  modplug->mSoundFile->SetResamplingMode (SRCMODE_POLYPHASE);
518

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
519 520 521 522 523 524 525 526 527 528 529 530
  if (modplug->surround)
    modplug->mSoundFile->SetSurroundParameters (modplug->surround_depth,
        modplug->surround_delay);

  if (modplug->megabass)
    modplug->mSoundFile->SetXBassParameters (modplug->megabass_amount,
        modplug->megabass_range);

  if (modplug->reverb)
    modplug->mSoundFile->SetReverbParameters (modplug->reverb_depth,
        modplug->reverb_delay);

Wim Taymans's avatar
Wim Taymans committed
531 532 533 534 535

  gst_buffer_map (modplug->buffer, &map, GST_MAP_READ);
  if (!modplug->mSoundFile->Create (map.data, modplug->song_size))
    goto load_error;
  gst_buffer_unmap (modplug->buffer, &map);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
536 537 538 539 540

  modplug->song_length = modplug->mSoundFile->GetSongTime () * GST_SECOND;
  modplug->seek_at = -1;

  GST_INFO_OBJECT (modplug, "Song length: %" GST_TIME_FORMAT,
541
      GST_TIME_ARGS ((guint64) modplug->song_length));
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
542 543

  return TRUE;
Wim Taymans's avatar
Wim Taymans committed
544 545 546 547 548 549 550 551 552

  /* ERRORS */
load_error:
  {
    gst_buffer_unmap (modplug->buffer, &map);
    GST_ELEMENT_ERROR (modplug, STREAM, DECODE, (NULL),
        ("Unable to load song"));
    return FALSE;
  }
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
553 554 555
}

static gboolean
Wim Taymans's avatar
Wim Taymans committed
556
gst_modplug_sinkpad_activate (GstPad * sinkpad, GstObject * parent)
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
557
{
Wim Taymans's avatar
Wim Taymans committed
558 559 560 561 562 563 564 565 566 567
  GstQuery *query;
  gboolean pull_mode;

  query = gst_query_new_scheduling ();

  if (!gst_pad_peer_query (sinkpad, query)) {
    gst_query_unref (query);
    goto activate_push;
  }

568 569
  pull_mode = gst_query_has_scheduling_mode_with_flags (query,
      GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
Wim Taymans's avatar
Wim Taymans committed
570 571 572 573 574 575 576
  gst_query_unref (query);

  if (!pull_mode)
    goto activate_push;

  GST_DEBUG_OBJECT (sinkpad, "activating pull");
  return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
577

Wim Taymans's avatar
Wim Taymans committed
578 579 580 581 582
activate_push:
  {
    GST_DEBUG_OBJECT (sinkpad, "activating push");
    return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
  }
583 584
}

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
585
static gboolean
Wim Taymans's avatar
Wim Taymans committed
586 587
gst_modplug_sinkpad_activate_mode (GstPad * pad, GstObject * parent,
    GstPadMode mode, gboolean active)
588
{
Wim Taymans's avatar
Wim Taymans committed
589 590
  GstModPlug *modplug = GST_MODPLUG (parent);
  gboolean res;
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
591

Wim Taymans's avatar
Wim Taymans committed
592 593 594 595 596 597 598
  switch (mode) {
    case GST_PAD_MODE_PUSH:
      res = TRUE;
      break;
    case GST_PAD_MODE_PULL:
      if (active) {
        res = gst_pad_start_task (pad, (GstTaskFunction) gst_modplug_loop,
Wim Taymans's avatar
Wim Taymans committed
599
            modplug, NULL);
Wim Taymans's avatar
Wim Taymans committed
600 601 602 603 604 605 606
      } else {
        res = gst_pad_stop_task (pad);
      }
      break;
    default:
      res = FALSE;
      break;
607
  }
Wim Taymans's avatar
Wim Taymans committed
608
  return res;
609 610
}

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
611 612
static gboolean
gst_modplug_get_upstream_size (GstModPlug * modplug, gint64 * length)
Jeremy Simon's avatar
Jeremy Simon committed
613
{
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
614 615
  gboolean res = FALSE;
  GstPad *peer;
Jeremy Simon's avatar
Jeremy Simon committed
616

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
617 618 619
  peer = gst_pad_get_peer (modplug->sinkpad);
  if (peer == NULL)
    return FALSE;
Jeremy Simon's avatar
Jeremy Simon committed
620

Wim Taymans's avatar
Wim Taymans committed
621
  if (gst_pad_query_duration (peer, GST_FORMAT_BYTES, length) && *length >= 0) {
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
622
    res = TRUE;
Jeremy Simon's avatar
Jeremy Simon committed
623 624
  }

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
625 626
  gst_object_unref (peer);
  return res;
Jeremy Simon's avatar
Jeremy Simon committed
627 628
}

Jeremy Simon's avatar
Jeremy Simon committed
629
static void
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
630
gst_modplug_loop (GstModPlug * modplug)
Jeremy Simon's avatar
Jeremy Simon committed
631
{
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
632 633
  GstFlowReturn flow;
  GstBuffer *out = NULL;
Wim Taymans's avatar
Wim Taymans committed
634
  GstMapInfo map;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
635

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
636
  g_assert (GST_IS_MODPLUG (modplug));
637

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
638 639 640 641 642 643 644
  /* first, get the size of the song */
  if (!modplug->song_size) {
    if (!gst_modplug_get_upstream_size (modplug, &modplug->song_size)) {
      GST_ELEMENT_ERROR (modplug, STREAM, DECODE, (NULL),
          ("Unable to load song"));
      goto pause;
    }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
645

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
646 647
    if (modplug->buffer) {
      gst_buffer_unref (modplug->buffer);
Jeremy Simon's avatar
Jeremy Simon committed
648
    }
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
649 650 651
    modplug->buffer = gst_buffer_new_and_alloc (modplug->song_size);
    modplug->offset = 0;
  }
652

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
  /* read in the song data */
  if (!modplug->mSoundFile) {
    GstBuffer *buffer = NULL;
    guint64 read_size = modplug->song_size - modplug->offset;

    if (read_size > 4096)
      read_size = 4096;

    flow =
        gst_pad_pull_range (modplug->sinkpad, modplug->offset, read_size,
        &buffer);
    if (flow != GST_FLOW_OK) {
      GST_ELEMENT_ERROR (modplug, STREAM, DECODE, (NULL),
          ("Unable to load song"));
      goto pause;
Jeremy Simon's avatar
Jeremy Simon committed
668
    }
669

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
670
    /* GST_LOG_OBJECT (modplug, "Read %u bytes", GST_BUFFER_SIZE (buffer)); */
Wim Taymans's avatar
Wim Taymans committed
671 672 673
    gst_buffer_map (buffer, &map, GST_MAP_READ);
    gst_buffer_fill (modplug->buffer, modplug->offset, map.data, map.size);
    gst_buffer_unmap (buffer, &map);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
674
    gst_buffer_unref (buffer);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
675

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
676
    modplug->offset += read_size;
Jeremy Simon's avatar
Jeremy Simon committed
677

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
678 679
    /* actually load it */
    if (modplug->offset == modplug->song_size) {
680
      GstTagList *tags;
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
681
      gboolean ok;
682
#define COMMENT_SIZE 16384
683
      gchar comment[COMMENT_SIZE];
Wim Taymans's avatar
Wim Taymans committed
684
      GstSegment seg;
Jeremy Simon's avatar
Jeremy Simon committed
685

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
686 687 688 689
      ok = gst_modplug_load_song (modplug);
      gst_buffer_unref (modplug->buffer);
      modplug->buffer = NULL;
      modplug->offset = 0;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
690

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
691 692 693
      if (!ok) {
        goto pause;
      }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
694

Wim Taymans's avatar
Wim Taymans committed
695 696 697
      gst_segment_init (&seg, GST_FORMAT_TIME);
      seg.stop = modplug->song_length;
      gst_pad_push_event (modplug->srcpad, gst_event_new_segment (&seg));
698 699

      /* get and send metadata */
Wim Taymans's avatar
Wim Taymans committed
700
      tags = gst_tag_list_new_empty ();
701 702 703 704 705
      gst_tag_list_add (tags, GST_TAG_MERGE_APPEND,
          GST_TAG_TITLE, modplug->mSoundFile->GetTitle (),
          GST_TAG_BEATS_PER_MINUTE,
          (gdouble) modplug->mSoundFile->GetMusicTempo (), NULL);

706
      if (modplug->mSoundFile->GetSongComments ((gchar *) & comment,
707
              COMMENT_SIZE, 32)) {
708
        comment[COMMENT_SIZE - 1] = '\0';
709 710 711
        gst_tag_list_add (tags, GST_TAG_MERGE_APPEND,
            GST_TAG_COMMENT, comment, NULL);
      }
712
      gst_pad_push_event (modplug->srcpad, gst_event_new_tag (tags));
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
713 714
    } else {
      /* not fully loaded yet */
Jeremy Simon's avatar
Jeremy Simon committed
715 716
      return;
    }
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
717
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
718

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
719 720 721 722 723
  /* could move this to gst_modplug_src_event 
   * if libmodplug was definitely thread safe.. */
  if (modplug->seek_at != -1) {
    gint seek_to_pos;
    gfloat temp;
Wim Taymans's avatar
Wim Taymans committed
724

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
725
    temp = (gfloat) modplug->song_length / modplug->seek_at;
726
    seek_to_pos = (gint) (modplug->mSoundFile->GetMaxPosition () / temp);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
727

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
728
    GST_DEBUG_OBJECT (modplug, "Seeking to row %d", seek_to_pos);
Jeremy Simon's avatar
Jeremy Simon committed
729

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
730 731
    modplug->mSoundFile->SetCurrentPos (seek_to_pos);
    modplug->seek_at = -1;
Jeremy Simon's avatar
Jeremy Simon committed
732
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
733

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
734
  /* read and output a buffer */
735
  GST_LOG_OBJECT (modplug, "Read %d bytes", (gint) modplug->read_bytes);
736
  /* libmodplug 0.8.7 trashes memory */
737
  out = gst_buffer_new_allocate (NULL, modplug->read_bytes * 2, NULL);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
738

Wim Taymans's avatar
Wim Taymans committed
739 740 741
  gst_buffer_map (out, &map, GST_MAP_WRITE);
  if (!modplug->mSoundFile->Read (map.data, modplug->read_bytes)) {
    gst_buffer_unmap (out, &map);
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
742
    goto eos;
Wim Taymans's avatar
Wim Taymans committed
743 744
  }
  gst_buffer_unmap (out, &map);
745
  gst_buffer_resize (out, 0, modplug->read_bytes);
746

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
747 748 749 750 751 752 753
  GST_BUFFER_DURATION (out) =
      gst_util_uint64_scale_int (modplug->read_samples, GST_SECOND,
      modplug->frequency);
  GST_BUFFER_OFFSET (out) = modplug->offset;
  GST_BUFFER_TIMESTAMP (out) =
      gst_util_uint64_scale_int (modplug->offset, GST_SECOND,
      modplug->frequency);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
754

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
755
  modplug->offset += modplug->read_samples;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
756

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
757
  flow = gst_pad_push (modplug->srcpad, out);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
758

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
759 760 761 762
  if (flow != GST_FLOW_OK) {
    GST_LOG_OBJECT (modplug, "pad push flow: %s", gst_flow_get_name (flow));
    goto pause;
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
763

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
764
  return;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
765

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
766 767 768 769 770 771 772
eos:
  {
    gst_buffer_unref (out);
    GST_INFO_OBJECT (modplug, "EOS");
    gst_pad_push_event (modplug->srcpad, gst_event_new_eos ());
    goto pause;
  }
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
773

Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
774 775 776 777
pause:
  {
    GST_INFO_OBJECT (modplug, "Pausing");
    gst_pad_pause_task (modplug->sinkpad);
778
  }
Jeremy Simon's avatar
Jeremy Simon committed
779 780 781
}


782 783
static GstStateChangeReturn
gst_modplug_change_state (GstElement * element, GstStateChange transition)
Jeremy Simon's avatar
Jeremy Simon committed
784
{
Jeremy Simon's avatar
Jeremy Simon committed
785
  GstModPlug *modplug;
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
786
  GstStateChangeReturn ret;
Jeremy Simon's avatar
Jeremy Simon committed
787

Jeremy Simon's avatar
Jeremy Simon committed
788
  modplug = GST_MODPLUG (element);
Jeremy Simon's avatar
Jeremy Simon committed
789

790 791
  switch (transition) {
    case GST_STATE_CHANGE_READY_TO_PAUSED:
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
792 793
      modplug->buffer = NULL;
      modplug->offset = 0;
Jeremy Simon's avatar
Jeremy Simon committed
794
      modplug->song_size = 0;
Jeremy Simon's avatar
Jeremy Simon committed
795
      break;
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
796
    default:
Jeremy Simon's avatar
Jeremy Simon committed
797
      break;
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
798 799 800 801 802 803 804
  }

  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  if (ret == GST_STATE_CHANGE_FAILURE)
    return ret;

  switch (transition) {
805
    case GST_STATE_CHANGE_PAUSED_TO_READY:
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
806 807 808 809 810
      if (modplug->buffer) {
        gst_buffer_unref (modplug->buffer);
        modplug->buffer = NULL;
      }
      if (modplug->mSoundFile) {
811
        modplug->mSoundFile->Destroy ();
812
        delete modplug->mSoundFile;
Tim-Philipp Müller's avatar
 
Tim-Philipp Müller committed
813
        modplug->mSoundFile = NULL;
814
      }
815 816
      break;
    default:
Jeremy Simon's avatar
Jeremy Simon committed
817
      break;
Jeremy Simon's avatar
Jeremy Simon committed
818 819
  }

820
  return GST_STATE_CHANGE_SUCCESS;
Jeremy Simon's avatar
Jeremy Simon committed
821 822
}

823

Jeremy Simon's avatar
Jeremy Simon committed
824
static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
825 826
gst_modplug_set_property (GObject * object, guint id, const GValue * value,
    GParamSpec * pspec)
Jeremy Simon's avatar
Jeremy Simon committed
827 828 829
{
  GstModPlug *modplug;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
830
  g_return_if_fail (GST_IS_MODPLUG (object));
Jeremy Simon's avatar
Jeremy Simon committed
831
  modplug = GST_MODPLUG (object);
Jeremy Simon's avatar
Jeremy Simon committed
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869

  switch (id) {
    case ARG_REVERB:
      modplug->reverb = g_value_get_boolean (value);
      break;
    case ARG_REVERB_DEPTH:
      modplug->reverb_depth = g_value_get_int (value);
      break;
    case ARG_REVERB_DELAY:
      modplug->reverb_delay = g_value_get_int (value);
      break;
    case ARG_MEGABASS:
      modplug->megabass = g_value_get_boolean (value);
      break;
    case ARG_MEGABASS_AMOUNT:
      modplug->megabass_amount = g_value_get_int (value);
      break;
    case ARG_MEGABASS_RANGE:
      modplug->megabass_range = g_value_get_int (value);
      break;
    case ARG_NOISE_REDUCTION:
      modplug->noise_reduction = g_value_get_boolean (value);
      break;
    case ARG_SURROUND:
      modplug->surround = g_value_get_boolean (value);
      break;
    case ARG_SURROUND_DEPTH:
      modplug->surround_depth = g_value_get_int (value);
      break;
    case ARG_SURROUND_DELAY:
      modplug->surround_delay = g_value_get_int (value);
      break;
    default:
      break;
  }
}

static void
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
870 871
gst_modplug_get_property (GObject * object, guint id, GValue * value,
    GParamSpec * pspec)
Jeremy Simon's avatar
Jeremy Simon committed
872 873 874
{
  GstModPlug *modplug;

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
875
  g_return_if_fail (GST_IS_MODPLUG (object));
Jeremy Simon's avatar
Jeremy Simon committed
876
  modplug = GST_MODPLUG (object);
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
877

Jeremy Simon's avatar
Jeremy Simon committed
878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
  switch (id) {
    case ARG_REVERB:
      g_value_set_boolean (value, modplug->reverb);
      break;
    case ARG_REVERB_DEPTH:
      g_value_set_int (value, modplug->reverb_depth);
      break;
    case ARG_REVERB_DELAY:
      g_value_set_int (value, modplug->reverb_delay);
      break;
    case ARG_MEGABASS:
      g_value_set_boolean (value, modplug->megabass);
      break;
    case ARG_MEGABASS_AMOUNT:
      g_value_set_int (value, modplug->megabass_amount);
      break;
    case ARG_MEGABASS_RANGE:
      g_value_set_int (value, modplug->megabass_range);
      break;
    case ARG_SURROUND:
      g_value_set_boolean (value, modplug->surround);
      break;
    case ARG_SURROUND_DEPTH:
      g_value_set_int (value, modplug->surround_depth);
      break;
    case ARG_SURROUND_DELAY:
      g_value_set_int (value, modplug->surround_delay);
      break;
    case ARG_NOISE_REDUCTION:
      g_value_set_boolean (value, modplug->noise_reduction);
      break;
    default:
      break;
  }
}

static gboolean
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
915
plugin_init (GstPlugin * plugin)
Jeremy Simon's avatar
Jeremy Simon committed
916
{
Ronald S. Bultje's avatar
Ronald S. Bultje committed
917
  return gst_element_register (plugin, "modplug",
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
918
      GST_RANK_PRIMARY, GST_TYPE_MODPLUG);
Jeremy Simon's avatar
Jeremy Simon committed
919 920
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
921 922
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
923
    modplug,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
924
    ".MOD audio decoding",
925
    plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)