3 #include <glib/gi18n.h>
4 #include <libchimara/glk.h>
10 #include "chimara-glk-private.h"
15 extern GPrivate *glk_data_key;
17 #ifdef GSTREAMER_SOUND
19 on_pipeline_message(GstBus *bus, GstMessage *message, schanid_t s)
21 /* g_print("Got %s message\n", GST_MESSAGE_TYPE_NAME(message)); */
23 switch(GST_MESSAGE_TYPE(message)) {
24 case GST_MESSAGE_ERROR: {
28 gst_message_parse_error(message, &err, &debug);
29 g_print("Error: %s\n", err->message);
38 /* unhandled message */
44 on_ogg_demuxer_pad_added(GstElement *demux, GstPad *pad, schanid_t s)
48 /* We can now link this pad with the vorbis-decoder sink pad */
49 sinkpad = gst_element_get_static_pad(s->decode, "sink");
50 gst_pad_link(pad, sinkpad);
51 gst_object_unref(sinkpad);
55 on_type_found(GstElement *typefind, guint probability, GstCaps *caps, schanid_t s)
57 gchar *type = gst_caps_to_string(caps);
58 if(strcmp(type, "application/ogg") == 0)
60 s->demux = gst_element_factory_make("oggdemux", NULL);
61 s->decode = gst_element_factory_make("vorbisdec", NULL);
62 if(!s->demux || !s->decode)
64 WARNING(_("Could not create one or more GStreamer elements"));
67 gst_bin_add_many(GST_BIN(s->pipeline), s->demux, s->decode, NULL);
68 if(!gst_element_link(s->typefind, s->demux) || !gst_element_link(s->decode, s->convert))
70 WARNING(_("Could not link GStreamer elements"));
73 /* We link the demuxer and decoder together dynamically, since the
74 demuxer doesn't know what source pads it will have until it starts
75 demuxing the stream */
76 g_signal_connect(s->demux, "pad-added", G_CALLBACK(on_ogg_demuxer_pad_added), s);
78 else if(strcmp(type, "audio/x-aiff") == 0)
80 s->decode = gst_element_factory_make("aiffparse", NULL);
83 WARNING(_("Could not create 'aiffparse' GStreamer element"));
86 gst_bin_add(GST_BIN(s->pipeline), s->decode);
87 if(!gst_element_link_many(s->typefind, s->decode, s->convert, NULL))
89 WARNING(_("Could not link GStreamer elements"));
95 WARNING("Can't play that type, you FOOL!");
101 #endif /* GSTREAMER_SOUND */
104 * glk_schannel_create:
105 * @rock: The rock value to give the new sound channel.
107 * This creates a sound channel, about as you'd expect.
109 * Remember that it is possible that the library will be unable to create a new
110 * channel, in which case glk_schannel_create() will return %NULL.
112 * Returns: A new sound channel, or %NULL.
115 glk_schannel_create(glui32 rock)
117 #ifdef GSTREAMER_SOUND
118 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
120 schanid_t s = g_new0(struct glk_schannel_struct, 1);
121 s->magic = MAGIC_SCHANNEL;
123 if(glk_data->register_obj)
124 s->disprock = (*glk_data->register_obj)(s, gidisp_Class_Schannel);
126 /* Add it to the global sound channel list */
127 glk_data->schannel_list = g_list_prepend(glk_data->schannel_list, s);
128 s->schannel_list = glk_data->schannel_list;
130 /* Create a GStreamer pipeline for the sound channel */
131 gchar *pipeline_name = g_strdup_printf("pipeline-%p", s);
132 s->pipeline = gst_pipeline_new(pipeline_name);
133 g_free(pipeline_name);
135 /* Watch for messages from the pipeline */
136 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(s->pipeline));
137 gst_bus_add_signal_watch(bus);
138 g_signal_connect(bus, "message", G_CALLBACK(on_pipeline_message), s);
139 gst_object_unref(bus);
141 /* Create GStreamer elements to put in the pipeline */
142 s->source = gst_element_factory_make("giostreamsrc", NULL);
143 s->typefind = gst_element_factory_make("typefind", NULL);
144 s->convert = gst_element_factory_make("audioconvert", NULL);
145 s->filter = gst_element_factory_make("volume", NULL);
146 s->sink = gst_element_factory_make("autoaudiosink", NULL);
147 if(!s->source || !s->typefind || !s->convert || !s->filter || !s->sink) {
148 WARNING(_("Could not create one or more GStreamer elements"));
152 gst_bin_add_many(GST_BIN(s->pipeline), s->source, s->typefind, s->convert, s->filter, s->sink, NULL);
153 /* Link elements: Source -> typefinder -> ??? -> Converter -> Volume filter -> Sink */
154 if(!gst_element_link(s->source, s->typefind) || !gst_element_link_many(s->convert, s->filter, s->sink, NULL)) {
155 WARNING(_("Could not link GStreamer elements"));
158 g_signal_connect(s->typefind, "have-type", G_CALLBACK(on_type_found), s);
163 glk_schannel_destroy(s);
167 #endif /* GSTREAMER_SOUND */
171 * glk_schannel_destroy:
172 * @chan: The sound channel to destroy.
174 * Destroys the channel. If the channel is playing a sound, the sound stops
175 * immediately (with no notification event).
178 glk_schannel_destroy(schanid_t chan)
180 VALID_SCHANNEL(chan, return);
182 #ifdef GSTREAMER_SOUND
183 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
185 if(!gst_element_set_state(chan->pipeline, GST_STATE_NULL))
186 WARNING_S(_("Could not set GstElement state to"), "NULL");
188 glk_data->schannel_list = g_list_delete_link(glk_data->schannel_list, chan->schannel_list);
190 if(glk_data->unregister_obj)
192 (*glk_data->unregister_obj)(chan, gidisp_Class_Schannel, chan->disprock);
193 chan->disprock.ptr = NULL;
197 gst_object_unref(chan->pipeline);
199 chan->magic = MAGIC_FREE;
205 * glk_schannel_iterate:
206 * @chan: A sound channel, or %NULL.
207 * @rockptr: Return location for the next sound channel's rock, or %NULL.
209 * This function can be used to iterate through the list of all open channels.
210 * See <link linkend="chimara-Iterating-Through-Opaque-Objects">Iterating
211 * Through Opaque Objects</link>.
213 * As that section describes, the order in which channels are returned is
216 * Returns: the next sound channel, or %NULL if there are no more.
219 glk_schannel_iterate(schanid_t chan, glui32 *rockptr)
221 VALID_SCHANNEL_OR_NULL(chan, return NULL);
223 #ifdef GSTREAMER_SOUND
224 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
228 retnode = glk_data->schannel_list;
230 retnode = chan->schannel_list->next;
231 schanid_t retval = retnode? (schanid_t)retnode->data : NULL;
233 /* Store the sound channel's rock in rockptr */
234 if(retval && rockptr)
235 *rockptr = glk_schannel_get_rock(retval);
240 #endif /* GSTREAMER_SOUND */
244 * glk_schannel_get_rock:
245 * @chan: A sound channel.
247 * Retrieves the channel's rock value. See <link
248 * linkend="chimara-Rocks">Rocks</link>.
250 * Returns: A rock value.
253 glk_schannel_get_rock(schanid_t chan)
255 VALID_SCHANNEL(chan, return 0);
261 * @chan: Channel to play the sound in.
262 * @snd: Resource number of the sound to play.
264 * Begins playing the given sound on the channel. If the channel was already
265 * playing a sound (even the same one), the old sound is stopped (with no
266 * notification event.
268 * This returns 1 if the sound actually started playing, and 0 if there was any
271 * The most obvious problem is if there is no sound resource with the given
272 * identifier. But other problems can occur. For example, the MOD-playing
273 * facility in a library might be unable to handle two MODs at the same time,
274 * in which case playing a MOD resource would fail if one was already playing.
277 * Returns: 1 on success, 0 on failure.
280 glk_schannel_play(schanid_t chan, glui32 snd)
282 return glk_schannel_play_ext(chan, snd, 1, 0);
286 * glk_schannel_play_ext:
287 * @chan: Channel to play the sound in.
288 * @snd: Resource number of the sound to play.
289 * @repeats: Number of times to repeat the sound.
290 * @notify: If nonzero, requests a notification when the sound is finished.
292 * This works the same as glk_schannel_play(), but lets you specify additional
293 * options. <code>glk_schannel_play(chan, snd)</code> is exactly equivalent to
294 * <code>glk_schannel_play_ext(chan, snd, 1, 0)</code>.
296 * The @repeats value is the number of times the sound should be repeated. A
297 * repeat value of -1 (or rather 0xFFFFFFFF) means that the sound should repeat
298 * forever. A repeat value of 0 means that the sound will not be played at all;
299 * nothing happens. (Although a previous sound on the channel will be stopped,
300 * and the function will return 1.)
302 * The @notify value should be nonzero in order to request a sound notification
303 * event. If you do this, when the sound is completed, you will get an event
304 * with type %evtype_SoundNotify. The @window will be %NULL, @val1 will be the
305 * sound's resource id, and @val2 will be the nonzero value you passed as
308 * If you request sound notification, and the repeat value is greater than one,
309 * you will get the event only after the last repetition. If the repeat value is
310 * 0 or -1, you will never get a notification event at all. Similarly, if the
311 * sound is stopped or interrupted, or if the channel is destroyed while the
312 * sound is playing, there will be no notification event.
314 * Not all libraries support sound notification. You should test the
315 * %gestalt_SoundNotify selector before you rely on it; see <link
316 * linkend="chimara-Testing-for-Sound-Capabilities">Testing for Sound
317 * Capabilities</link>.
319 * Returns: 1 on success, 0 on failure.
322 glk_schannel_play_ext(schanid_t chan, glui32 snd, glui32 repeats, glui32 notify)
324 VALID_SCHANNEL(chan, return 0);
325 #ifdef GSTREAMER_SOUND
326 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
328 if(!glk_data->resource_map) {
329 if(!glk_data->resource_load_callback) {
330 WARNING(_("No resource map has been loaded yet."));
333 WARNING(_("Loading sound resources from alternative location not yet supported."));
337 giblorb_result_t resource;
338 giblorb_err_t result = giblorb_load_resource(glk_data->resource_map, giblorb_method_Memory, &resource, giblorb_ID_Snd, snd);
339 if(result != giblorb_err_None) {
340 WARNING_S( _("Error loading resource"), giblorb_get_error_message(result) );
343 g_printerr("playing sound resource %d on channel %p\n", snd, chan);
344 GInputStream *stream = g_memory_input_stream_new_from_data(resource.data.ptr, resource.length, NULL);
345 g_object_set(chan->source, "stream", stream, NULL);
347 if(!gst_element_set_state(chan->pipeline, GST_STATE_PLAYING)) {
348 WARNING_S(_("Could not set GstElement state to"), "PLAYING");
359 * @chan: Channel to silence.
361 * Stops any sound playing in the channel. No notification event is generated,
362 * even if you requested one. If no sound is playing, this has no effect.
365 glk_schannel_stop(schanid_t chan)
367 VALID_SCHANNEL(chan, return);
368 #ifdef GSTREAMER_SOUND
369 if(!gst_element_set_state(chan->pipeline, GST_STATE_READY))
370 WARNING_S(_("Could not set GstElement state to"), "READY");
375 * glk_schannel_set_volume:
376 * @chan: Channel to set the volume of.
377 * @vol: Integer representing the volume; 0x10000 is 100%.
379 * Sets the volume in the channel. When you create a channel, it has full
380 * volume, represented by the value 0x10000. Half volume would be 0x8000,
381 * three-quarters volume would be 0xC000, and so on. A volume of zero represents
382 * silence, although the sound is still considered to be playing.
384 * You can call this function between sounds, or while a sound is playing. The
385 * effect is immediate.
387 * You can overdrive the volume of a channel by setting a volume greater than
388 * 0x10000. However, this is not recommended; the library may be unable to
389 * increase the volume past full, or the sound may become distorted. You should
390 * always create sound resources with the maximum volume you will need, and then
391 * call glk_schannel_set_volume() to reduce the volume when appropriate.
393 * Not all libraries support this function. You should test the
394 * %gestalt_SoundVolume selector before you rely on it; see <link
395 * linkend="chimara-Testing-for-Sound-Capabilities">Testing for Sound
396 * Capabilities</link>.
398 * <note><title>Chimara</title>
399 * <para>Chimara supports volumes from 0 to 1000%, that is, values of
400 * @vol up to 0xA0000.</para>
404 glk_schannel_set_volume(schanid_t chan, glui32 vol)
406 VALID_SCHANNEL(chan, return);
407 #ifdef GSTREAMER_SOUND
408 gdouble volume_gst = (gdouble)vol / 0x10000;
409 g_printerr("Volume set to: %f\n", volume_gst);
410 g_object_set(chan->filter, "volume", CLAMP(volume_gst, 0.0, 10.0), NULL);
415 * glk_sound_load_hint:
416 * @snd: Resource number of a sound.
417 * @flag: Nonzero to tell the library to load the sound, zero to tell the
418 * library to unload it.
420 * This gives the library a hint about whether the given sound should be loaded
421 * or not. If the @flag is nonzero, the library may preload the sound or do
422 * other initialization, so that glk_schannel_play() will be faster. If the
423 * @flag is zero, the library may release memory or other resources associated
424 * with the sound. Calling this function is always optional, and it has no
425 * effect on what the library actually plays.
427 * <warning><para>This function is not implemented yet.</para></warning>
430 glk_sound_load_hint(glui32 snd, glui32 flag)