Home > OS >  Is there a way to get OscillatorNode to produce a sound on an iOS device?
Is there a way to get OscillatorNode to produce a sound on an iOS device?

Time:10-20

I'm working on a music web app that has a piano keyboard. When a user presses a piano key, I'm using OscillatorNode to play a brief tone corresponding to the key:

const audioCtx = new (window.AudioContext || window.webkitAudioContext)();

function playNote(note) {
    let oscillator;
    let freq = notes[note];
    console.debug(note   " ("   freq   " Hz)");
    oscillator = audioCtx.createOscillator(); // create Oscillator node
    oscillator.type = wavetypeEl.val(); // triangle wave by default
    oscillator.frequency.setValueAtTime(freq, audioCtx.currentTime); // freq = value in hertz
    oscillator.connect(audioCtx.destination);
    oscillator.start();
    oscillator.stop(audioCtx.currentTime   0.5);
}

$('#keyboard button').on('click', (e) => {
        playNote(e.target.dataset.note);
});

This works on all the desktop and Android browsers I've tried, but iOS stubbornly refuses to play any sound. I see that I need a user interaction to "unlock" an AudioContext on iOS, but I would have thought calling playNote() from my click function would have done the trick.

According to Apple, I should be able to use noteOn() on my oscillator object, instead of oscillator.start() the way I've got it in my example. But that doesn't seem to be a valid method.

I must be missing something simple here. Anybody know?

CodePudding user response:

I have an iPhone XS Max and the demo works on it producing sound as you have it right now... I've also read that for iOS the element needs both onClick handler and a style of {cursor: pointer} set to work properly.(as of a few years ago) seems like it's working though.

CodePudding user response:

If everything seems to be working fine it could be that the device itself is on mute. For some reason (or for no reason at all) Safari doesn't play any sound coming from the Web Audio API when the device is muted. But it plays everything else.

There are some hacky ways to circumvent this bug which basically work by playing something with an audio element first before using the Web Audio API.

unmute-ios-audio is for example a library which implements the hack mentioned above.

  • Related