Search code examples
javascriptweb-audio-api

Play buffer by PeriodicWave in Web Audio API, can I set Gain as loud as buffer?


I tried to play Oscillator (buffer -> FFT -> PeriodicWave -> Oscillator).

// PeriodicWave (-> Oscillator)
var wave = fft(buffer), periodicwave = ctx.createPeriodicWave(wave[0], wave[1]);
function fft(input) {
    var n = input.length, theta = 2 * Math.PI / n,
        ar = new Float32Array(n), ai = new Float32Array(n),
        m, mh, i, j, k, irev,
        wr, wi, xr, xi,
        cos = Math.cos, sin = Math.sin;

    for(i=0; i<n; ++i) {
        ar[i] = input[i];
    }

    // scrambler
    i=0;
    for(j=1; j<n-1; ++j) {
        for(k = n>>1; k>(i ^= k); k>>=1);
        if(j<i) {
            xr = ar[j];
            xi = ai[j];
            ar[j] = ar[i];
            ai[j] = ai[i];
            ar[i] = xr;
            ai[i] = xi;
        }
    }
    for(mh=1; (m = mh << 1) <= n; mh=m) {
        irev = 0;
        for(i=0; i<n; i+=m) {
            wr = cos(theta * irev);
            wi = sin(theta * irev);
            for(k=n>>2; k > (irev ^= k); k>>=1);
            for(j=i; j<mh+i; ++j) {
                k = j + mh;
                xr = ar[j] - ar[k];
                xi = ai[j] - ai[k];
                ar[j] += ar[k];
                ai[j] += ai[k];
                ar[k] = wr * xr - wi * xi;
                ai[k] = wr * xi + wi * xr;
            }
        }
    }

    return [ar, ai];
}

This code is good however this Oscillator's gain is standardized automatically. I want to set gain as loud as BufferSource (buffer -> AudioBuffer -> BufferSource), but it doesn't work I have tried using AudioGainNode, see this test code.


Solution

  • createPeriodicWave automatically scales the output waveform so that it has a max amplitude of 1. This means the volume is lower than you might expect. You'll have to experiment a bit with the gain to make the oscillator output match the buffer output volume. The scaling depends on the wave used for createPeriodicWave.

    However, I think the beta (or canary) versions of Chrome support the recently introduced parameter disableNormalization: true for createPeriodicWave to disable the normalization. Then the oscillator volume should match the buffer volume.