Reverb#

Goal: add a global reverb, then layer positioned reverb zones so the listener walks through a sequence of distinct acoustic environments.

Walks through Demo05_Reverb: one global reverb, four positioned zones (bathroom, hall, sewer pipe, and a custom-parameter zone) lined up along the z-axis. As the listener moves forward they pass through each in turn.

Source: Demo05_Reverb.cpp.

Global reverb#

The global reverb is a singleton always available via YSE::System().getGlobalReverb(). It is disabled by default — turn it on and pick a preset:

  // set global reverb
  YSE::System().getGlobalReverb().setActive(true);
  YSE::System().getGlobalReverb().setPreset(YSE::REVERB_GENERIC);
  YSE::ChannelMaster().attachReverb();

The last line attaches the reverb processor to the master channel. Without that step, the reverb runs but is not routed to the output.

Positioned reverb zones#

Each positioned reverb is a YSE::reverb instance with a position, a size (full-strength radius), and a rolloff (the fade-out distance beyond the radius). The demo places four of them along the z-axis:

  // add reverb at 5 meter
  bathroom.create();
  bathroom.setPosition(YSE::Pos(0, 0, 5)).setSize(1).setRollOff(1);
  bathroom.setPreset(YSE::REVERB_BATHROOM);

  // add reverb at 10 meter
  hall.create();
  hall.setPosition(YSE::Pos(0, 0, 10)).setSize(1).setRollOff(1);
  hall.setPreset(YSE::REVERB_HALL);

  // add reverb at 15 meter
  sewer.create();
  sewer.setPosition(YSE::Pos(0, 0, 15)).setSize(1).setRollOff(1);
  sewer.setPreset(YSE::REVERB_SEWERPIPE);

Setter chaining is the idiomatic style — every setter returns reverb& so you can stack setPosition(...).setSize(...).setRollOff(...) on one line.

The engine blends overlapping zones by proximity. The global reverb fills in wherever no positioned zone reaches at full strength.

Custom reverb parameters#

Beyond presets, every individual reverb parameter is exposed. The fourth zone in the demo skips setPreset and dials in its own settings:

  // add reverb at 20 meter
  custom.create();
  custom.setPosition(YSE::Pos(0, 0, 20)).setSize(1).setRollOff(1);
  // for this reverb we use custom parameters instead of a preset
  // (these are meant to sound awkward)
  custom.setRoomSize(1.0f).setDamping(0.1f).setDryWetBalance(0.0f, 1.0f).setModulation(6.5, 0.7);
  custom.setReflection(0, 1000, 0.5f).setReflection(1, 1500, 0.6f);
  custom.setReflection(2, 2100, 0.8f).setReflection(3, 2999, 0.9f);

What the parameters do:

  • setRoomSize — simulated room size. Larger values mean longer tails.

  • setDamping — high-frequency damping. Higher values darken the tail faster (soft materials).

  • setDryWetBalance(dry, wet) — pass-through level vs. reverb level. Usually dry + wet ≈ 1.

  • setModulation(frequency, width) — slow LFO across the tail to break up metallic resonances.

  • setReflection(n, time, gain) — one of the four early reflections. Reflections are short echoes layered on top of the diffuse tail to suggest specific surfaces.

Walking through the zones#

Moving the listener forward in the demo also moves the test source — keep the sound near the listener so it’s audible at every position:

void DemoReverb::MoveForward()
{
  YSE::Pos pos = YSE::Listener().pos();
  pos.z += 0.1;
  YSE::Listener().pos(pos);
  snare.pos(pos);
}

void DemoReverb::MoveBack()
{
  YSE::Pos pos = YSE::Listener().pos();
  pos.z -= 0.1;
  YSE::Listener().pos(pos);
  snare.pos(pos);
}

As z increases, the listener crosses into each zone’s full-strength radius and the reverb character shifts smoothly.

What you learned#

  • Enable the global reverb via System().getGlobalReverb().setActive(true) and route it with channel.attachReverb().

  • Positioned zones are YSE::reverb instances with a position, size, and rolloff. Build them with the chainable setters.

  • Use REVERB_PRESET enums for quick configurations or tune the individual room-size / damping / dry-wet / modulation / reflection knobs yourself.

Next#