Channels#

Goal: group sounds into channels for shared volume control, and build a custom channel hierarchy.

Walks through Demo04_Channels: attach sounds to a pre-built channel (ChannelMusic) and a custom-created child of ChannelMaster, then ride the gain of each independently.

Source: Demo04_Channels.cpp.

Why channels#

Every sound is attached to a channel — either implicitly to MainMix (equivalent to ChannelMaster()) when no channel is supplied to sound::create, or explicitly to one of the pre-built channels or to a channel you create yourself. Channels do two things:

  • Shared mixing. Set the volume on a channel and every sound inside it shifts together. No need to walk a list of sounds.

  • Shared processing. Inserts and sends act on everything a channel carries (see Mixing with inserts and sends).

Choose your channels by how you want to mix, not for performance. A channel does not get a thread of its own. The engine renders the whole tree as one set of tasks that the audio thread and a small pool of render workers share, and it splits a busy channel’s sounds into several tasks by itself. Many sounds on one channel spread across cores just as well as the same sounds spread over several channels. One channel per category (music, ambient, voice, GUI, SFX) is still a good layout, because those are the groups you will want to fade separately. Threading model explains how the render is shared out.

Creating a custom channel#

The demo allocates a custom channel on the heap, parents it under ChannelMaster, and attaches a sound to it:

DemoChannels::DemoChannels() : customChannel(new YSE::channel)
{
	customChannel->create("myChannel", YSE::ChannelMaster());

	// add a sound to your custom channel
	kick.create(YSE_TEST_RESOURCES_DIR "/kick.ogg", customChannel, true);
	kick.play();

	// add a sound to the music channel
	pulse.create(YSE_TEST_RESOURCES_DIR "/pulse1.ogg", &YSE::ChannelMusic(), true);
	pulse.play();

A few things are happening here:

  • new YSE::channel — channels are dynamically allocated so they can be reparented and deleted without invalidating sound references.

  • customChannel->create("myChannel", YSE::ChannelMaster()) initialises the channel and attaches it under ChannelMaster. The name is for logging.

  • kick.create("...", customChannel, true) attaches the sound to the custom channel at load time. The true is the loop flag (see Volume, pitch, and looping).

  • pulse.create("...", &YSE::ChannelMusic(), true) shows the other pattern: attach to a pre-built channel by passing its address.

Adjusting channel volume#

Volume is per-channel, multiplied through the tree:

void DemoChannels::MasterIncVol()
{
	YSE::ChannelMaster().setVolume(YSE::ChannelMaster().getVolume() + 0.1f);
}

void DemoChannels::MasterDecVol()
{
	YSE::ChannelMaster().setVolume(YSE::ChannelMaster().getVolume() - 0.1f);
}

void DemoChannels::CustomIncVol()
{
	if (customChannel != nullptr) customChannel->setVolume(customChannel->getVolume() + 0.1f);
}

void DemoChannels::CustomDecVol()
{
	if (customChannel != nullptr) customChannel->setVolume(customChannel->getVolume() - 0.1f);
}

void DemoChannels::MusicIncVol()
{
	YSE::ChannelMusic().setVolume(YSE::ChannelMusic().getVolume() + 0.1f);
}

void DemoChannels::MusicDecVol()
{
	YSE::ChannelMusic().setVolume(YSE::ChannelMusic().getVolume() - 0.1f);

Notice the read-modify-write idiom: getVolume() + 0.1f. Range is [0, 1] — values above 1 clip the digital signal.

Deleting a channel#

Custom channels can be torn down cleanly. Sounds and subchannels move up to the parent:

void DemoChannels::CustomDelete()
{
	if (customChannel != nullptr) {
		delete customChannel;
		customChannel = nullptr;
		std::cout << "The custom channel is deleted. All sounds and subchannels are automatically moved to the parent channel." << std::endl;
	}
}

The destructor of DemoChannels also calls CustomDelete() — clean up before YSE::System().close() runs.

What you learned#

  • The pre-built channels (ChannelMaster, ChannelMusic, ChannelAmbient, ChannelVoice, ChannelGui, ChannelFX) cover the common categories.

  • Build your own channel with new YSE::channel + create(name, parent).

  • setVolume / getVolume work at every level; values cascade through the tree.

  • Deleting a custom channel reparents its sounds and subchannels to the parent automatically.

Next#

  • Reverb — add a positioned reverb effect to a channel.

  • YSE::channel — full channel API.