mwg API
    Preparing search index...

    Class AdaptiveMusic

    Adaptive music from stems that play in lockstep: every stem of a version starts on the same clock tick at the same offset, each through its own gain, so raising or lowering a stem (or a named group of them) with a fade changes the intensity without changing the file or losing the beat. Several versions of the arrangement can be loaded; switching between them crossfades at the same position, counted in frames, so a calm version and a combat version stay in step. Stems come from renderMidiStems or from separately recorded layers; all stems of a version must have the same length and sample rate, and versions must agree on the sample rate.

    import { AdaptiveMusic, renderMidiStems, parseMidi, toAudioBuffer } from '@datamoc/mwg/audio';

    declare const context: AudioContext;
    declare const midiBytes: ArrayBuffer;

    const rendered = renderMidiStems(parseMidi(midiBytes), { rhythm: [9], melody: [0], pads: [1] });
    const stems = Object.fromEntries(Object.entries(rendered).map(([name, r]) => [name, toAudioBuffer(context, r)]));

    const music = new AdaptiveMusic(context);
    music.load('calm', stems, { groups: { intensity: ['rhythm', 'melody'] } });
    music.play({ levels: { pads: 1 } });
    music.setLevel('intensity', 1, 2); // fade the fight in over two seconds
    Index
    • sets a stem's or group's level (0 to 1), fading over fadeSeconds; with quantize: 'bar' the fade starts at the next bar line, so a layer comes in on the measure

      Parameters

      • target: string
      • level: number
      • OptionalfadeSeconds: number
      • quantize: Quantize = 'now'

      Returns void

    • stops every stem, fading over fadeSeconds first when positive; the position is forgotten

      Parameters

      • fadeSeconds: number = 0

      Returns void

    • Crossfades to another loaded version at the position the current one has reached, in frames, so the beat carries over. Levels carry over too: a stem or group of the same name keeps the level it had. With quantize: 'bar' the crossfade starts at the next bar line of the version that sounds now, so a scene change never cuts a measure; version reports the new name from the call, the sound changes at the bar.

      Parameters

      • name: string
      • OptionalfadeSeconds: number
      • quantize: Quantize = 'now'

      Returns void