Search code examples
javascriptweb-audio-api

Convert Sample Rate in Web Audio API


How could I convert sample rate of a buffer from 44100 to 48000 Hz in a browser?

I found a library https://github.com/taisel/XAudioJS/blob/master/resampler.js that should allow me to do that, but don't have an idea how to use it.


Solution

  • There seemed to be a bug in mobile safari which didn't decode the loaded audio correctly when the sample rate for the audio context was different than the sample rate for the audio file. Moreover, the sample rate for the audio context changed randomly from 44100 to 48000 usually but not always depending if the website was loading with the iPhone sound switched on or off.

    The workaround for this issue is to read the sample rate of the audio context and then to load different audio files for each sample rate, like this:

    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    var audio_context = new AudioContext();
    var actual_sample_rate = audio_context.sampleRate;
    if (actual_sample_rate != 48000) {
        actual_sample_rate = 44100;
    }
    
    function finished_loading_sounds(sounds) {
        buffers['piano_do'] = {
            buffer: sounds.piano,
            rate: 1
        };
        // ...do something when the sounds are loaded...
    }
    
    var buffer_loader = new BufferLoader(
        audio_context,
        {
            piano: "audio/" + actual_sample_rate + "/piano.m4a",
        },
        finished_loading_sounds
    );
    
    buffer_loader.load();
    

    The buffer loader is defined like in this tutorial.

    To change the sample rate for the audio file, one can use Audacity.


    UPDATE

    It seems that even when you try to load a file with the correct sample rate, occasionally the sound still gets distorted on iOS devices.

    To fix the issue, I found a hack for your AudioContext:

    function createAudioContext(desiredSampleRate) {
        var AudioCtor = window.AudioContext || window.webkitAudioContext;
    
        desiredSampleRate = typeof desiredSampleRate === 'number'
            ? desiredSampleRate
            : 44100;
        var context = new AudioCtor();
    
        // Check if hack is necessary. Only occurs in iOS6+ devices
        // and only when you first boot the iPhone, or play a audio/video
        // with a different sample rate
        if (/(iPhone|iPad)/i.test(navigator.userAgent) && context.sampleRate !== desiredSampleRate) {
            var buffer = context.createBuffer(1, 1, desiredSampleRate);
            var dummy = context.createBufferSource();
            dummy.buffer = buffer;
            dummy.connect(context.destination);
            dummy.start(0);
            dummy.disconnect();
    
            context.close(); // dispose old context
            context = new AudioCtor();
        }
        return context;
    }
    

    Then to use it, create the audio context as follows:

    var audio_context = createAudioContext(44100);