flutter3d
Showcase Changelog 38 packages API reference

A blended engine loop

since 0.1.0 or earlier Simulation, audio and XR

An engine's note is one or more recordings, each at a different rev range, crossfaded by whatever number is driving them. A single stretched recording sounds like a siren at the ends; BlendedLoop mixes a handful of loops instead, weighted so the change from one to the next is not audible.

Step 1: Bands, each centred on the value it was recorded at #

LoopBand.centre is what a recording actually is: a loop taken at three quarters of the revs has a centre of 0.75.

_engine = BlendedLoop(
  scene: _scene,
  bands: <LoopBand>[
    LoopBand(
      sound: const SoundDef(name: 'idle', asset: 'idle.wav', loop: true),
      centre: 0.2,
    ),
    LoopBand(
      sound: const SoundDef(name: 'mid', asset: 'mid.wav', loop: true),
      centre: 0.6,
    ),
    LoopBand(
      sound: const SoundDef(name: 'high', asset: 'high.wav', loop: true),
      centre: 1.0,
    ),
  ],
);

Step 2: Drive it every frame #

update takes the current value and mixes the bands' gains and playback rates to match it.

@override
void update(DemoContext context, double dt) {
  _engine.update(revs);
  _scene.update(AudioListener());
}

Move the slider and the mix shifts smoothly between the idle, mid and high recordings.

Step 3: Check the loudness stays level #

// The bands are normalised, so the total weight is one wherever the
// revs sit, including exactly between two bands.
revs = 0.4;
_engine.update(revs);
var total = 0.0;
for (var i = 0; i < 3; i++) {
  total += _engine.gainOf(i);
}

The weights are normalised, so the three bands' gains always add up to full loudness, even sitting exactly between two of them — without that, the middle of a crossfade would read as the engine cutting out.