Support for GStreamer 1.0
[projects/chimara/chimara.git] / libchimara / schannel.c
1 #include <config.h>
2 #include <glib.h>
3 #include <glib/gi18n-lib.h>
4 #include <libchimara/glk.h>
5 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
6 #include <gst/gst.h>
7 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
8 #include "magic.h"
9 #include "schannel.h"
10 #include "chimara-glk-private.h"
11 #include "gi_dispa.h"
12 #include "gi_blorb.h"
13 #include "resource.h"
14 #include "event.h"
15
16 #define VOLUME_TIMER_RESOLUTION 1.0 /* In milliseconds */
17
18 #ifdef GSTREAMER_0_10_SOUND
19 #define OGG_MIMETYPE "application/ogg"
20 #endif
21 #ifdef GSTREAMER_1_0_SOUND
22 #define OGG_MIMETYPE "audio/ogg"
23 #endif
24
25 extern GPrivate glk_data_key;
26
27 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
28 /* Stop any currently playing sound on this channel, and remove any
29  format-specific GStreamer elements from the channel. */
30 static void
31 clean_up_after_playing_sound(schanid_t chan)
32 {
33         if(!gst_element_set_state(chan->pipeline, GST_STATE_NULL))
34                 WARNING_S(_("Could not set GstElement state to"), "NULL");
35         if(chan->source)
36         {
37                 gst_bin_remove(GST_BIN(chan->pipeline), chan->source);
38                 chan->source = NULL;
39         }
40         if(chan->demux)
41         {
42                 gst_bin_remove(GST_BIN(chan->pipeline), chan->demux);
43                 chan->demux = NULL;
44         }
45         if(chan->decode)
46         {
47                 gst_bin_remove(GST_BIN(chan->pipeline), chan->decode);
48                 chan->decode = NULL;
49         }
50 }
51
52 /* This signal is thrown whenever the GStreamer pipeline generates a message.
53  Most messages are harmless. */
54 static void
55 on_pipeline_message(GstBus *bus, GstMessage *message, schanid_t s)
56 {
57         /* g_printerr("Got %s message\n", GST_MESSAGE_TYPE_NAME(message)); */
58
59         GError *err;
60         gchar *debug_message;
61         
62         switch(GST_MESSAGE_TYPE(message)) {
63         case GST_MESSAGE_ERROR: 
64         {
65                 gst_message_parse_error(message, &err, &debug_message);
66                 IO_WARNING(_("GStreamer error"), err->message, debug_message);
67                 g_error_free(err);
68                 g_free(debug_message);
69                 clean_up_after_playing_sound(s);
70         }
71                 break;
72         case GST_MESSAGE_WARNING:
73         {
74                 gst_message_parse_warning(message, &err, &debug_message);
75                 IO_WARNING(_("GStreamer warning"), err->message, debug_message);
76                 g_error_free(err);
77                 g_free(debug_message);
78         }
79                 break;
80         case GST_MESSAGE_INFO:
81         {
82                 gst_message_parse_info(message, &err, &debug_message);
83                 g_message("GStreamer info \"%s\": %s", err->message, debug_message);
84                 g_error_free(err);
85                 g_free(debug_message);
86         }
87                 break;
88         case GST_MESSAGE_EOS: /* End of stream */
89                 /* Decrease repeats if not set to forever */
90                 if(s->repeats != (glui32)-1)
91                         s->repeats--;
92                 if(s->repeats > 0) {
93                         if(!gst_element_seek_simple(s->pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT, 0)) {
94                                 WARNING(_("Could not execute GStreamer seek"));
95                                 clean_up_after_playing_sound(s);
96                         }
97                 } else {
98                         clean_up_after_playing_sound(s);
99                         /* Sound ended normally, send a notification if requested */
100                         if(s->notify)
101                                 event_throw(s->glk, evtype_SoundNotify, NULL, s->resource, s->notify);
102                 }
103                 break;
104         default:
105                 /* unhandled message */
106                 break;
107         }
108 }
109
110 /* This signal is thrown when the OGG demuxer element has decided what kind of
111  outputs it will output. We connect the decoder element dynamically. */
112 static void
113 on_ogg_demuxer_pad_added(GstElement *demux, GstPad *pad, schanid_t s)
114 {
115         GstPad *sinkpad;
116         
117         /* We can now link this pad with the vorbis-decoder sink pad */
118         sinkpad = gst_element_get_static_pad(s->decode, "sink");
119         if(gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK)
120                 WARNING(_("Could not link OGG demuxer with Vorbis decoder"));
121         gst_object_unref(sinkpad);
122 }
123
124 /* This signal is thrown when the typefinder element has found the type of its
125  input. Now that we know what kind of input stream we have, we can connect the
126  proper demuxer/decoder elements. */
127 static void
128 on_type_found(GstElement *typefind, guint probability, GstCaps *caps, schanid_t s)
129 {
130         gchar *type = gst_caps_to_string(caps);
131         if(strcmp(type, OGG_MIMETYPE) == 0) {
132                 s->demux = gst_element_factory_make("oggdemux", NULL);
133                 s->decode = gst_element_factory_make("vorbisdec", NULL);
134                 if(!s->demux || !s->decode) {
135                         WARNING(_("Could not create one or more GStreamer elements"));
136                         goto finally;
137                 }
138                 gst_bin_add_many(GST_BIN(s->pipeline), s->demux, s->decode, NULL);
139                 if(!gst_element_link(s->typefind, s->demux) || !gst_element_link(s->decode, s->convert)) {
140                         WARNING(_("Could not link GStreamer elements"));
141                         goto finally;
142                 }
143                 /* We link the demuxer and decoder together dynamically, since the
144                  demuxer doesn't know what source pads it will have until it starts
145                  demuxing the stream */
146                 g_signal_connect(s->demux, "pad-added", G_CALLBACK(on_ogg_demuxer_pad_added), s);
147         } else if(strcmp(type, "audio/x-aiff") == 0) {
148                 s->decode = gst_element_factory_make("aiffparse", NULL);
149                 if(!s->decode) {
150                         WARNING(_("Could not create 'aiffparse' GStreamer element"));
151                         goto finally;
152                 }
153                 gst_bin_add(GST_BIN(s->pipeline), s->decode);
154                 if(!gst_element_link_many(s->typefind, s->decode, s->convert, NULL)) {
155                         WARNING(_("Could not link GStreamer elements"));
156                         goto finally;
157                 }
158         } else if(strcmp(type, "audio/x-mod") == 0) {
159                 s->decode = gst_element_factory_make("modplug", NULL);
160                 if(!s->decode) {
161                         WARNING(_("Could not create 'modplug' GStreamer element"));
162                         goto finally;
163                 }
164                 gst_bin_add(GST_BIN(s->pipeline), s->decode);
165                 if(!gst_element_link_many(s->typefind, s->decode, s->convert, NULL)) {
166                         WARNING(_("Could not link GStreamer elements"));
167                         goto finally;
168                 }
169         } else {
170                 WARNING_S(_("Unexpected audio type in blorb"), type);
171         }
172
173 finally:
174         g_free(type);
175 }
176 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
177
178 /**
179  * glk_schannel_create:
180  * @rock: The rock value to give the new sound channel.
181  *
182  * This creates a sound channel, about as you'd expect.
183  *
184  * Remember that it is possible that the library will be unable to create a new
185  * channel, in which case glk_schannel_create() will return %NULL.
186  *
187  * When you create a channel using glk_schannel_create(), it has full volume,
188  * represented by the value 0x10000. Half volume would be 0x8000, three-quarters
189  * volume would be 0xC000, and so on. A volume of zero represents silence.
190  *
191  * You can overdrive the volume of a channel by setting a volume greater than 
192  * 0x10000. However, this is not recommended; the library may be unable to 
193  * increase the volume past full, or the sound may become distorted. You should 
194  * always create sound resources with the maximum volume you will need, and then
195  * reduce the volume when appropriate using the channel-volume calls.
196  *
197  * <note><para>
198  *   Mathematically, these volume changes should be taken as linear
199  *   multiplication of a waveform represented as linear samples. As I
200  *   understand it, linear PCM encodes the sound pressure, and therefore a
201  *   volume of 0x8000 should represent a 6 dB drop.
202  * </para></note>
203  *
204  * Returns: A new sound channel, or %NULL.
205  */
206 schanid_t 
207 glk_schannel_create(glui32 rock)
208 {
209         return glk_schannel_create_ext(rock, 0x10000);
210 }
211
212 /**
213  * glk_schannel_create_ext:
214  * @rock: The rock value to give the new sound channel.
215  * @volume: Integer representing the volume; 0x10000 is 100&percnt;.
216  *
217  * The glk_schannel_create_ext() call lets you create a channel with the volume
218  * already set at a given level.
219  *
220  * Not all libraries support glk_schannel_create_ext(). You should test the
221  * %gestalt_Sound2 selector before you rely on it; see <link
222  * linkend="chimara-Testing-for-Sound-Capabilities">Testing for Sound
223  * Capabilities</link>.
224  *
225  * Returns: A new sound channel, or %NULL.
226  */
227 schanid_t
228 glk_schannel_create_ext(glui32 rock, glui32 volume)
229 {
230 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
231         ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
232
233         schanid_t s = g_new0(struct glk_schannel_struct, 1);
234         s->magic = MAGIC_SCHANNEL;
235         s->rock = rock;
236         if(glk_data->register_obj)
237                 s->disprock = (*glk_data->register_obj)(s, gidisp_Class_Schannel);
238
239         /* Add it to the global sound channel list */
240         glk_data->schannel_list = g_list_prepend(glk_data->schannel_list, s);
241         s->schannel_list = glk_data->schannel_list;
242
243         /* Add a pointer to the ChimaraGlk widget, for convenience */
244         s->glk = glk_data->self;
245
246         /* Create a GStreamer pipeline for the sound channel */
247         gchar *pipeline_name = g_strdup_printf("pipeline-%p", s);
248         s->pipeline = gst_pipeline_new(pipeline_name);
249         g_free(pipeline_name);
250
251         /* Watch for messages from the pipeline */
252         GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(s->pipeline));
253         gst_bus_add_signal_watch(bus);
254         g_signal_connect(bus, "message", G_CALLBACK(on_pipeline_message), s);
255         gst_object_unref(bus);
256
257         /* Create GStreamer elements to put in the pipeline */
258         s->typefind = gst_element_factory_make("typefind", NULL);
259         s->convert = gst_element_factory_make("audioconvert", NULL);
260         s->filter = gst_element_factory_make("volume", NULL);
261         s->sink = gst_element_factory_make("autoaudiosink", NULL);
262         if(!s->typefind || !s->convert || !s->filter || !s->sink) {
263                 WARNING(_("Could not create one or more GStreamer elements"));
264                 goto fail;
265         }
266
267         /* Set the initial volume */
268         glk_schannel_set_volume(s, volume);
269
270         /* Put the elements in the pipeline and link as many together as we can
271          without knowing the type of the audio stream */
272         gst_bin_add_many(GST_BIN(s->pipeline), s->typefind, s->convert, s->filter, s->sink, NULL);
273
274         /* Link elements: ??? -> Converter -> Volume filter -> Sink */
275         if(!gst_element_link_many(s->convert, s->filter, s->sink, NULL)) {
276                 WARNING(_("Could not link GStreamer elements"));
277                 goto fail;
278         }
279         g_signal_connect(s->typefind, "have-type", G_CALLBACK(on_type_found), s);
280         
281         return s;
282
283 fail:
284         glk_schannel_destroy(s);
285         return NULL;
286 #else
287         return NULL;
288 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
289 }
290
291 /**
292  * glk_schannel_destroy:
293  * @chan: The sound channel to destroy.
294  *
295  * Destroys the channel. If the channel is playing a sound, the sound stops 
296  * immediately (with no notification event).
297  */
298 void 
299 glk_schannel_destroy(schanid_t chan)
300 {
301         VALID_SCHANNEL(chan, return);
302
303 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
304         ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
305
306         if(!gst_element_set_state(chan->pipeline, GST_STATE_NULL))
307                 WARNING_S(_("Could not set GstElement state to"), "NULL");
308         
309         glk_data->schannel_list = g_list_delete_link(glk_data->schannel_list, chan->schannel_list);
310
311         if(glk_data->unregister_obj)
312         {
313                 (*glk_data->unregister_obj)(chan, gidisp_Class_Schannel, chan->disprock);
314                 chan->disprock.ptr = NULL;
315         }
316
317         /* This also frees all the objects inside the pipeline */
318         if(chan->pipeline)
319                 gst_object_unref(chan->pipeline);
320         
321         chan->magic = MAGIC_FREE;
322         g_free(chan);
323 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
324 }
325
326 /**
327  * glk_schannel_iterate:
328  * @chan: A sound channel, or %NULL.
329  * @rockptr: Return location for the next sound channel's rock, or %NULL.
330  *
331  * This function can be used to iterate through the list of all open channels.
332  * See <link linkend="chimara-Iterating-Through-Opaque-Objects">Iterating 
333  * Through Opaque Objects</link>.
334  *
335  * As that section describes, the order in which channels are returned is 
336  * arbitrary.
337  *
338  * Returns: the next sound channel, or %NULL if there are no more.
339  */
340 schanid_t 
341 glk_schannel_iterate(schanid_t chan, glui32 *rockptr)
342 {
343         VALID_SCHANNEL_OR_NULL(chan, return NULL);
344
345 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
346         ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
347         GList *retnode;
348         
349         if(chan == NULL)
350                 retnode = glk_data->schannel_list;
351         else
352                 retnode = chan->schannel_list->next;
353         schanid_t retval = retnode? (schanid_t)retnode->data : NULL;
354                 
355         /* Store the sound channel's rock in rockptr */
356         if(retval && rockptr)
357                 *rockptr = glk_schannel_get_rock(retval);
358                 
359         return retval;
360 #else
361         return NULL;
362 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
363 }
364
365 /**
366  * glk_schannel_get_rock:
367  * @chan: A sound channel.
368  * 
369  * Retrieves the channel's rock value. See <link 
370  * linkend="chimara-Rocks">Rocks</link>.
371  *
372  * Returns: A rock value.
373  */
374 glui32 
375 glk_schannel_get_rock(schanid_t chan)
376 {
377         VALID_SCHANNEL(chan, return 0);
378         return chan->rock;
379 }
380
381 /**
382  * glk_schannel_play:
383  * @chan: Channel to play the sound in.
384  * @snd: Resource number of the sound to play.
385  *
386  * Begins playing the given sound on the channel. If the channel was already
387  * playing a sound (even the same one), the old sound is stopped (with no
388  * notification event.
389  *
390  * This returns 1 if the sound actually started playing, and 0 if there was any
391  * problem.
392  * <note><para>
393  *   The most obvious problem is if there is no sound resource with the given
394  *   identifier. But other problems can occur. For example, the MOD-playing 
395  *   facility in a library might be unable to handle two MODs at the same time,
396  *   in which case playing a MOD resource would fail if one was already playing.
397  * </para></note>
398  *
399  * Returns: 1 on success, 0 on failure.
400  */
401 glui32 
402 glk_schannel_play(schanid_t chan, glui32 snd)
403 {
404         return glk_schannel_play_ext(chan, snd, 1, 0);
405 }
406
407 /**
408  * glk_schannel_play_ext:
409  * @chan: Channel to play the sound in.
410  * @snd: Resource number of the sound to play.
411  * @repeats: Number of times to repeat the sound.
412  * @notify: If nonzero, requests a notification when the sound is finished.
413  *
414  * This works the same as glk_schannel_play(), but lets you specify additional 
415  * options. <code>glk_schannel_play(chan, snd)</code> is exactly equivalent to 
416  * <code>glk_schannel_play_ext(chan, snd, 1, 0)</code>.
417  * 
418  * The @repeats value is the number of times the sound should be repeated. A 
419  * repeat value of -1 (or rather 0xFFFFFFFF) means that the sound should repeat 
420  * forever. A repeat value of 0 means that the sound will not be played at all; 
421  * nothing happens. (Although a previous sound on the channel will be stopped, 
422  * and the function will return 1.)
423  * 
424  * The @notify value should be nonzero in order to request a sound notification
425  * event. If you do this, when the sound is completed, you will get an event 
426  * with type %evtype_SoundNotify. The @window will be %NULL, @val1 will be the 
427  * sound's resource id, and @val2 will be the nonzero value you passed as 
428  * @notify.
429  * 
430  * If you request sound notification, and the repeat value is greater than one, 
431  * you will get the event only after the last repetition. If the repeat value is
432  * 0 or -1, you will never get a notification event at all. Similarly, if the 
433  * sound is stopped or interrupted, or if the channel is destroyed while the 
434  * sound is playing, there will be no notification event.
435  *
436  * Not all libraries support sound notification. You should test the
437  * %gestalt_Sound2 selector before you rely on it; see <link
438  * linkend="chimara-Testing-for-Sound-Capabilities">Testing for Sound 
439  * Capabilities</link>.
440  *
441  * Note that you can play a sound on a channel whose volume is zero. This has
442  * no audible result, unless you later change the volume; but it produces
443  * notifications as usual. You can also play a sound on a paused channel; the
444  * sound is paused immediately, and does not progress.
445  * 
446  * Returns: 1 on success, 0 on failure.
447  */
448 glui32 
449 glk_schannel_play_ext(schanid_t chan, glui32 snd, glui32 repeats, glui32 notify)
450 {
451         VALID_SCHANNEL(chan, return 0);
452 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
453         ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
454         GInputStream *stream;
455
456         /* Stop the previous sound */
457         clean_up_after_playing_sound(chan);
458
459         /* Don't play if repeats = 0 */
460         if(repeats == 0) {
461                 chan->repeats = 0;
462                 return 1;
463         }
464
465         /* Load the sound into a GInputStream, by whatever method */
466         if(!glk_data->resource_map) {
467                 if(!glk_data->resource_load_callback) {
468                         WARNING(_("No resource map has been loaded yet."));
469                         return 0;
470                 }
471                 gchar *filename = glk_data->resource_load_callback(CHIMARA_RESOURCE_SOUND, snd, glk_data->resource_load_callback_data);
472                 if(!filename) {
473                         WARNING(_("Error loading resource from alternative location."));
474                         return 0;
475                 }
476
477                 GError *err = NULL;
478                 GFile *file = g_file_new_for_path(filename);
479                 stream = G_INPUT_STREAM(g_file_read(file, NULL, &err));
480                 if(!stream) {
481                         IO_WARNING(_("Error loading resource from file"), filename, err->message);
482                         g_free(filename);
483                         g_object_unref(file);
484                         return 0;
485                 }
486                 g_free(filename);
487                 g_object_unref(file);
488         } else {
489                 giblorb_result_t resource;
490                 giblorb_err_t result = giblorb_load_resource(glk_data->resource_map, giblorb_method_Memory, &resource, giblorb_ID_Snd, snd);
491                 if(result != giblorb_err_None) {
492                         WARNING_S( _("Error loading resource"), giblorb_get_error_message(result) );
493                         return 0;
494                 }
495                 stream = g_memory_input_stream_new_from_data(resource.data.ptr, resource.length, NULL);
496         }
497
498         chan->source = gst_element_factory_make("giostreamsrc", NULL);
499         g_object_set(chan->source, "stream", stream, NULL);
500         g_object_unref(stream); /* Now owned by GStreamer element */
501         gst_bin_add(GST_BIN(chan->pipeline), chan->source);
502         if(!gst_element_link(chan->source, chan->typefind)) {
503                 WARNING(_("Could not link GStreamer elements"));
504                 clean_up_after_playing_sound(chan);
505                 return 0;
506         }
507
508         chan->repeats = repeats;
509         chan->resource = snd;
510         chan->notify = notify;
511         
512         /* Play the sound; unless the channel is paused, then pause it instead */
513         if(!gst_element_set_state(chan->pipeline, chan->paused? GST_STATE_PAUSED : GST_STATE_PLAYING)) {
514                 WARNING_S(_("Could not set GstElement state to"), chan->paused? "PAUSED" : "PLAYING");
515                 clean_up_after_playing_sound(chan);
516                 return 0;
517         }
518         return 1;
519 #else
520         return 0;
521 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
522 }
523
524 /**
525  * glk_schannel_play_multi:
526  * @chanarray: Array of #schanid_t structures.
527  * @chancount: Length of @chanarray.
528  * @sndarray: Array of sound resource numbers.
529  * @soundcount: Length of @sndarray, must be equal to @chanarray.
530  * @notify: If nonzero, request a notification when each sound finishes.
531  *
532  * This works the same as glk_schannel_play_ext(), except that you can specify
533  * more than one sound. The channel references and sound resource numbers are
534  * given as two arrays, which must be the same length. The @notify argument
535  * applies to all the sounds; the repeats value for all the sounds is 1.
536  * 
537  * All the sounds will begin at exactly the same time.
538  * 
539  * This returns the number of sounds that began playing correctly. (This will be
540  * a number from 0 to @soundcount.)
541  *
542  * <note><para>
543  *   If the @notify argument is nonzero, you will get a separate sound
544  *   notification event as each sound finishes. They will all have the same
545  *   @val2 value.
546  * </para></note>
547  * <note><para>
548  *   Note that you have to supply @chancount and @soundcount as separate
549  *   arguments, even though they are required to be the same. This is an awkward
550  *   consequence of the way array arguments are dispatched in Glulx.
551  * </para></note>
552  * 
553  * Returns: The number of sounds that started playing correctly.
554  */
555 glui32
556 glk_schannel_play_multi(schanid_t *chanarray, glui32 chancount, glui32 *sndarray, glui32 soundcount, glui32 notify)
557 {
558         g_return_val_if_fail(chancount == soundcount, 0);
559         g_return_val_if_fail(chanarray != NULL || chancount == 0, 0);
560         g_return_val_if_fail(sndarray != NULL || soundcount == 0, 0);
561
562         int count;
563         for(count = 0; count < chancount; count++)
564                 VALID_SCHANNEL(chanarray[count], return 0);
565
566 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
567         ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
568         GInputStream *stream;
569
570         if(!glk_data->resource_map && !glk_data->resource_load_callback) {
571                 WARNING(_("No resource map has been loaded yet."));
572                 return 0;
573         }
574
575         /* We keep an array of sounds to skip if any of them have errors */
576         gboolean *skiparray = g_new0(gboolean, chancount);
577
578         /* Set up all the channels one by one */
579         for(count = 0; count < chancount; count++) {
580                 /* Stop the previous sound */
581                 clean_up_after_playing_sound(chanarray[count]);
582
583                 /* Load the sound into a GInputStream, by whatever method */
584                 if(!glk_data->resource_map) {
585                         gchar *filename = glk_data->resource_load_callback(CHIMARA_RESOURCE_SOUND, sndarray[count], glk_data->resource_load_callback_data);
586                         if(!filename) {
587                                 WARNING(_("Error loading resource from alternative location."));
588                                 skiparray[count] = TRUE;
589                                 continue;
590                         }
591
592                         GError *err = NULL;
593                         GFile *file = g_file_new_for_path(filename);
594                         stream = G_INPUT_STREAM(g_file_read(file, NULL, &err));
595                         if(!stream) {
596                                 IO_WARNING(_("Error loading resource from file"), filename, err->message);
597                                 g_free(filename);
598                                 g_object_unref(file);
599                                 skiparray[count] = TRUE;
600                                 continue;
601                         }
602                         g_free(filename);
603                         g_object_unref(file);
604                 } else {
605                         giblorb_result_t resource;
606                         giblorb_err_t result = giblorb_load_resource(glk_data->resource_map, giblorb_method_Memory, &resource, giblorb_ID_Snd, sndarray[count]);
607                         if(result != giblorb_err_None) {
608                                 WARNING_S( _("Error loading resource"), giblorb_get_error_message(result) );
609                                 skiparray[count] = TRUE;
610                                 continue;
611                         }
612                         stream = g_memory_input_stream_new_from_data(resource.data.ptr, resource.length, NULL);
613                 }
614
615                 chanarray[count]->source = gst_element_factory_make("giostreamsrc", NULL);
616                 g_object_set(chanarray[count]->source, "stream", stream, NULL);
617                 g_object_unref(stream); /* Now owned by GStreamer element */
618                 gst_bin_add(GST_BIN(chanarray[count]->pipeline), chanarray[count]->source);
619                 if(!gst_element_link(chanarray[count]->source, chanarray[count]->typefind)) {
620                         WARNING(_("Could not link GStreamer elements"));
621                         clean_up_after_playing_sound(chanarray[count]);
622                 }
623
624                 chanarray[count]->repeats = 1;
625                 chanarray[count]->resource = sndarray[count];
626                 chanarray[count]->notify = notify;
627         }
628
629         /* Start all the sounds as close to each other as possible. */
630         /* FIXME: Is there a way to start them exactly at the same time? */
631         glui32 successes = 0;
632         for(count = 0; count < chancount; count++) {
633                 if(skiparray[count])
634                         continue;
635                 /* Play the sound; unless the channel is paused, then pause it instead */
636                 if(!gst_element_set_state(chanarray[count]->pipeline, chanarray[count]->paused? GST_STATE_PAUSED : GST_STATE_PLAYING)) {
637                         WARNING_S(_("Could not set GstElement state to"), chanarray[count]->paused? "PAUSED" : "PLAYING");
638                         skiparray[count] = TRUE;
639                         clean_up_after_playing_sound(chanarray[count]);
640                         continue;
641                 }
642                 successes++;
643         }
644         g_free(skiparray);
645         return successes;
646 #else
647         return 0;
648 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
649 }
650
651 /**
652  * glk_schannel_stop:
653  * @chan: Channel to silence.
654  *
655  * Stops any sound playing in the channel. No notification event is generated,
656  * even if you requested one. If no sound is playing, this has no effect.
657  */
658 void 
659 glk_schannel_stop(schanid_t chan)
660 {
661         VALID_SCHANNEL(chan, return);
662 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
663         clean_up_after_playing_sound(chan);
664 #endif
665 }
666
667 /**
668  * glk_schannel_pause:
669  * @chan: Channel to pause.
670  *
671  * Pause any sound playing in the channel. This does not generate any
672  * notification events. If the channel is already paused, this does nothing.
673  * 
674  * New sounds started in a paused channel are paused immediately.
675  * 
676  * A volume change in progress is <emphasis>not</emphasis> paused, and may
677  * proceed to completion, generating a notification if appropriate.
678  */
679 void
680 glk_schannel_pause(schanid_t chan)
681 {
682         VALID_SCHANNEL(chan, return);
683
684         if(chan->paused)
685                 return; /* Silently do nothing */
686
687         /* Mark the channel as paused even if there is no sound playing yet */
688         chan->paused = TRUE;
689
690 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
691         GstState state;
692         if(gst_element_get_state(chan->pipeline, &state, NULL, GST_CLOCK_TIME_NONE) != GST_STATE_CHANGE_SUCCESS) {
693                 WARNING(_("Could not get GstElement state"));
694                 return;
695         }
696         if(state != GST_STATE_PLAYING)
697                 return; /* Silently do nothing if no sound is playing */
698
699         if(!gst_element_set_state(chan->pipeline, GST_STATE_PAUSED)) {
700                 WARNING_S(_("Could not set GstElement state to"), "PAUSED");
701                 return;
702         }
703 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
704 }
705
706 /**
707  * glk_schannel_unpause:
708  * @chan: Channel to unpause.
709  *
710  * Unpause the channel. Any paused sounds begin playing where they left off. If
711  * the channel is not already paused, this does nothing.
712  *
713  * <note><para>
714  *   This means, for example, that you can pause a channel that is currently
715  *   not playing any sounds. If you then add a sound to the channel, it will
716  *   not start playing; it will be paused at its beginning. If you later
717  *   unpaise the channel, the sound will commence.
718  * </para></note>
719  */
720 void
721 glk_schannel_unpause(schanid_t chan)
722 {
723         VALID_SCHANNEL(chan, return);
724
725         if(!chan->paused)
726                 return; /* Silently do nothing */
727
728         /* Mark the channel as not paused in any case */
729         chan->paused = FALSE;
730
731 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
732         GstState state;
733         if(gst_element_get_state(chan->pipeline, &state, NULL, GST_CLOCK_TIME_NONE) != GST_STATE_CHANGE_SUCCESS) {
734                 WARNING(_("Could not get GstElement state"));
735                 return;
736         }
737         if(state != GST_STATE_PAUSED)
738                 return; /* Silently do nothing */
739
740         if(!gst_element_set_state(chan->pipeline, GST_STATE_PLAYING)) {
741                 WARNING_S(_("Could not set GstElement state to"), "PLAYING");
742                 return;
743         }
744 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
745 }
746
747 /**
748  * glk_schannel_set_volume:
749  * @chan: Channel to set the volume of.
750  * @vol: Integer representing the volume; 0x10000 is 100&percnt;.
751  *
752  * Sets the volume in the channel, from 0 (silence) to 0x10000 (full volume).
753  * Again, you can overdrive the volume by setting a value greater than 0x10000,
754  * but this is not recommended.
755  *
756  * The glk_schannel_set_volume() function does not include duration and notify
757  * values. Both are assumed to be zero: immediate change, no notification.
758  *
759  * You can call this function between sounds, or while a sound is playing.
760  * However, a zero-duration change while a sound is playing may produce
761  * unpleasant clicks.
762  * 
763  * At most one volume change can be occurring on a sound channel at any time.
764  * If you call this function while a previous volume change is in progress, the
765  * previous change is interrupted.
766  *
767  * Not all libraries support this function. You should test the
768  * %gestalt_SoundVolume selector before you rely on it; see <link
769  * linkend="chimara-Testing-for-Sound-Capabilities">Testing for Sound
770  * Capabilities</link>.
771  *
772  * <note><title>Chimara</title>
773  *   <para>Chimara supports volumes from 0 to 1000&percnt;, that is, values of
774  *   @vol up to 0xA0000.</para>
775  * </note>
776  */
777 void 
778 glk_schannel_set_volume(schanid_t chan, glui32 vol)
779 {
780         glk_schannel_set_volume_ext(chan, vol, 0, 0);
781 }
782
783 static double
784 volume_glk_to_gstreamer(glui32 volume_glk)
785 {
786         return CLAMP(((double)volume_glk / 0x10000), 0.0, 10.0);
787 }
788
789 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
790 static gboolean
791 volume_change_timeout(schanid_t chan)
792 {
793         GTimeVal now;
794         g_get_current_time(&now);
795
796         if(now.tv_sec >= chan->target_time_sec && now.tv_usec >= chan->target_time_usec) {
797                 /* We're done - make sure the volume is at the requested level */
798                 g_object_set(chan->filter, "volume", chan->target_volume, NULL);
799
800                 if(chan->volume_notify)
801                         event_throw(chan->glk, evtype_VolumeNotify, NULL, 0, chan->volume_notify);
802
803                 chan->volume_timer_id = 0;
804                 return FALSE;
805         }
806
807         /* Calculate the appropriate step every time - a busy system may delay or
808          * drop timer ticks */
809         double time_left_msec = (chan->target_time_sec - now.tv_sec) * 1000.0
810                 + (chan->target_time_usec - now.tv_usec) / 1000.0;
811         double steps_left = time_left_msec / VOLUME_TIMER_RESOLUTION;
812         double current_volume;
813         g_object_get(chan->filter, "volume", &current_volume, NULL);
814         double volume_step = (chan->target_volume - current_volume) / steps_left;
815
816         g_object_set(chan->filter, "volume", current_volume + volume_step, NULL);
817
818         return TRUE;
819 }
820 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
821
822 /**
823  * glk_schannel_set_volume_ext:
824  * @chan: Channel to set the volume of.
825  * @vol: Integer representing the volume; 0x10000 is 100&percnt;.
826  * @duration: Length of volume change in milliseconds, or 0 for immediate.
827  * @notify: If nonzero, requests a notification when the volume change finishes.
828  *
829  * Sets the volume in the channel, from 0 (silence) to 0x10000 (full volume).
830  * Again, you can overdrive the volume by setting a value greater than 0x10000,
831  * but this is not recommended.
832  *
833  * If the @duration is zero, the change is immediate. Otherwise, the change
834  * begins immediately, and occurs smoothly over the next @duration milliseconds.
835  *
836  * The @notify value should be nonzero in order to request a volume notification
837  * event. If you do this, when the volume change is completed, you will get an
838  * event with type #evtype_VolumeNotify. The window will be %NULL, @val1 will be
839  * zero, and @val2 will be the nonzero value you passed as @notify.
840  *
841  * You can call this function between sounds, or while a sound is playing.
842  * However, a zero-duration change while a sound is playing may produce
843  * unpleasant clicks.
844  *
845  * At most one volume change can be occurring on a sound channel at any time. If
846  * you call this function while a previous volume change is in progress, the
847  * previous change is interrupted. The beginning point of the new volume change
848  * should be wherever the previous volume change was interrupted (rather than
849  * the previous change's beginning or ending point).
850  *
851  * Not all libraries support these functions. You should test the appropriate
852  * gestalt selectors before you rely on them; see "Testing for Sound
853  * Capabilities".
854  */
855 void
856 glk_schannel_set_volume_ext(schanid_t chan, glui32 vol, glui32 duration, glui32 notify)
857 {
858         VALID_SCHANNEL(chan, return);
859         /* Silently ignore out-of-range volume values */
860
861 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
862         /* Interrupt a previous volume change */
863         if(chan->volume_timer_id > 0)
864                 g_source_remove(chan->volume_timer_id);
865         
866         double target_volume = volume_glk_to_gstreamer(vol);
867
868         if(duration == 0) {
869                 g_object_set(chan->filter, "volume", target_volume, NULL);
870
871                 if(notify != 0)
872                         event_throw(chan->glk, evtype_VolumeNotify, NULL, 0, notify);
873
874                 return;
875         }
876
877         GTimeVal target_time;
878         g_get_current_time(&target_time);
879         g_time_val_add(&target_time, (long)duration * 1000);
880
881         chan->target_volume = target_volume;
882         chan->target_time_sec = target_time.tv_sec;
883         chan->target_time_usec = target_time.tv_usec;
884         chan->volume_notify = notify;
885
886         /* Set up a timer for the volume */
887         chan->volume_timer_id = g_timeout_add(VOLUME_TIMER_RESOLUTION, (GSourceFunc)volume_change_timeout, chan);
888 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
889 }
890
891 /**
892  * glk_sound_load_hint:
893  * @snd: Resource number of a sound.
894  * @flag: Nonzero to tell the library to load the sound, zero to tell the
895  * library to unload it.
896  *
897  * This gives the library a hint about whether the given sound should be loaded
898  * or not. If the @flag is nonzero, the library may preload the sound or do
899  * other initialization, so that glk_schannel_play() will be faster. If the
900  * @flag is zero, the library may release memory or other resources associated
901  * with the sound. Calling this function is always optional, and it has no
902  * effect on what the library actually plays.
903  */
904 void 
905 glk_sound_load_hint(glui32 snd, glui32 flag)
906 {
907 #if defined(GSTREAMER_0_10_SOUND) || defined(GSTREAMER_1_0_SOUND)
908         ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key);
909         giblorb_result_t resource;
910         giblorb_err_t result;
911
912         /* Sound load hints only work for Blorb resource maps */
913         if(!glk_data->resource_map)
914                 return;
915
916         if(flag) {
917                 /* The sound load hint simply loads the resource from the resource map;
918                  loading a chunk more than once does nothing */
919                 result = giblorb_load_resource(glk_data->resource_map, giblorb_method_Memory, &resource, giblorb_ID_Snd, snd);
920                 if(result != giblorb_err_None) {
921                         WARNING_S( _("Error loading resource"), giblorb_get_error_message(result) );
922                         return;
923                 }
924         } else {
925                 /* Get the Blorb chunk number by loading the resource with
926                  method_DontLoad, then unload that chunk - has no effect if the chunk
927                  isn't loaded */
928                 result = giblorb_load_resource(glk_data->resource_map, giblorb_method_DontLoad, &resource, giblorb_ID_Snd, snd);
929                 if(result != giblorb_err_None) {
930                         WARNING_S( _("Error loading resource"), giblorb_get_error_message(result) );
931                         return;
932                 }
933                 result = giblorb_unload_chunk(glk_data->resource_map, resource.chunknum);
934                 if(result != giblorb_err_None) {
935                         WARNING_S( _("Error unloading chunk"), giblorb_get_error_message(result) );
936                         return;
937                 }
938         }
939 #endif /* GSTREAMER_0_10_SOUND || GSTREAMER_1_0_SOUND */
940 }