As with graphics, so with sound. Sounds, however, obviously don't appear in windows. To play a sound in Glk, you must first create a sound channel to hold it. This is an entirely new class of opaque objects; there are create and destroy and iterate and get_rock functions for channels, just as there are for windows and streams and filerefs.
A channel can be playing exactly one sound at a time. If you want to play more than one sound simultaneously, you need more than one sound channel. On the other hand, a single sound can be played on several channels at the same time, or overlapping itself.
Sound is an optional capability in Glk.
As with images, sounds are kept in resources, and your program does not have to worry about the formatting or storage. A resource is referred to by an integer identifier.
A resource can theoretically contain any kind of sound data, of any length. A resource can even be infinitely long. [This would be represented by some sound encoding with a built-in repeat-forever flag -- but that is among the details which are hidden from you.] A resource can also contain two or more channels of sound (stereo data). Do not confuse such in-sound channels with Glk sound channels. A single Glk sound channel suffices to play any sound, even stereo sounds.
[Again, Blorb is the official resource-storage format of Glk. Sounds in Blorb files can be encoded as AIFF, MOD, or MOD song data. See the Blorb specification for details.]
schanid_t glk_schannel_create(glui32 rock);
This creates a sound channel, about as you'd expect.
Remember that it is possible that the library will be unable to create a new channel, in which case glk_schannel_create() will return NULL.
void glk_schannel_destroy(schanid_t chan);
Destroy the channel. If the channel is playing a sound, the sound stops immediately (with no notification event).
glui32 glk_schannel_play(schanid_t chan, glui32 snd)
Begin playing the given sound on the channel. If the channel was already playing a sound (even the same one), the old sound is stopped (with no notification event).
This returns 1 if the sound actually started playing, and 0 if there was any problem. [The most obvious problem is if there is no sound resource with the given identifier. But other problems can occur. For example, the MOD-playing facility in a library might be unable to handle two MODs at the same time, in which case playing a MOD resource would fail if one was already playing.]
glui32 glk_schannel_play_ext(schanid_t chan, glui32 snd, glui32 repeats, glui32 notify);
This works the same as glk_schannel_play(), but lets you specify additional options. glk_schannel_play(chan, snd) is exactly equivalent to glk_schannel_play_ext(chan, snd, 1, 0).
The repeats value is the number of times the sound should be repeated. A repeat value of -1 (or rather 0xFFFFFFFF) means that the sound should repeat forever. A repeat value of 0 means that the sound will not be played at all; nothing happens. (Although a previous sound on the channel will be stopped, and the function will return 1.)
The notify value should be nonzero in order to request a sound notification event. If you do this, when the sound is completed, you will get an event with type evtype_SoundNotify. The window will be NULL, val1 will be the sound's resource id, and val2 will be the nonzero value you passed as notify.
If you request sound notification, and the repeat value is greater than one, you will get the event only after the last repetition. If the repeat value is 0 or -1, you will never get a notification event at all. Similarly, if the sound is stopped or interrupted, or if the channel is destroyed while the sound is playing, there will be no notification event.
Not all libraries support sound notification. You should test the gestalt_SoundNotify selector before you rely on it; see section 8.5, "Testing for Sound Capabilities".
void glk_schannel_stop(schanid_t chan);
Stops any sound playing in the channel. No notification event is generated, even if you requested one. If no sound is playing, this has no effect.
void glk_schannel_set_volume(schanid_t chan, glui32 vol);
Sets the volume in the channel. When you create a channel, it has full volume, represented by the value 0x10000. Half volume would be 0x8000, three-quarters volume would be 0xC000, and so on. A volume of zero represents silence, although the sound is still considered to be playing.
You can call this function between sounds, or while a sound is playing. The effect is immediate.
You can overdrive the volume of a channel by setting a volume greater than 0x10000. However, this is not recommended; the library may be unable to increase the volume past full, or the sound may become distorted. You should always create sound resources with the maximum volume you will need, and then call glk_schannel_set_volume() to reduce the volume when appropriate.
Not all libraries support this function. You should test the gestalt_SoundVolume selector before you rely on it; see section 8.5, "Testing for Sound Capabilities".
void glk_sound_load_hint(glui32 snd, glui32 flag);
This gives the library a hint about whether the given sound should be loaded or not. If the flag is nonzero, the library may preload the sound or do other initialization, so that glk_schannel_play() will be faster. If the flag is zero, the library may release memory or other resources associated with the sound. Calling this function is always optional, and it has no effect on what the library actually plays.
schanid_t glk_schannel_iterate(schanid_t chan, glui32 *rockptr);
This function can be used to iterate through the list of all open channels. See section 1.6.2, "Iterating Through Opaque Objects".
As that section describes, the order in which channels are returned is arbitrary.
glui32 glk_schannel_get_rock(schanid_t chan);
This retrieves the channel's rock value. See section 1.6.1, "Rocks".
Before calling Glk sound functions, you should use the following gestalt selectors.
glui32 res; res = glk_gestalt(gestalt_Sound, 0);
This returns 1 if the overall suite of sound functions is available. This includes glk_schannel_create(), glk_schannel_destroy(), glk_schannel_iterate(), glk_schannel_get_rock(), glk_schannel_play(), glk_schannel_play_ext(), glk_schannel_stop(), glk_schannel_set_volume(), and glk_sound_load_hint().
If this selector returns 0, you should not try to call these functions. They may have no effect, or they may cause a run-time error.
If you are writing a C program, there is an additional complication. A library which does not support sound may not implement the sound functions at all. Even if you put gestalt tests around your sound calls, you may get link-time errors. If the glk.h file is so old that it does not declare the sound functions and constants, you may even get compile-time errors.
To avoid this, you can perform a preprocessor test for the existence of GLK_MODULE_SOUND. If this is defined, so are all the functions and constants described in this section. If not, not.
res = glk_gestalt(gestalt_SoundMusic, 0);
This returns 1 if the library is capable of playing music sound resources. If it returns 0, only sampled sounds can be played.["Music sound resources" means MOD songs -- the only music format that Blorb currently supports. The presence of this selector is, of course, an ugly hack. It is a concession to the current state of the Glk libraries, some of which can handle AIFF but not MOD sounds.]
glui32 res; res = glk_gestalt(gestalt_SoundVolume, 0);
This selector returns 1 if the glk_schannel_set_volume() function works. If it returns zero, glk_schannel_set_volume() has no effect.
glui32 res; res = glk_gestalt(gestalt_SoundNotify, 0);
This selector returns 1 if the library supports sound notification events. If it returns zero, you will never get such events.