I'm aware that I need a user action to start Web Audio on mobile. However I have followed the recommendation to resume (in the case of Tone.js call Tone.start()) on user action but it still don't work. Here are the relevant parts of my code:
keyElement.addEventListener("touchstart", notePressed, false);
keyElement.addEventListener("touchend", noteReleased, false);
function notePressed(event) {
let dataset = event.target.dataset;
if (!dataset["pressed"]) {
let octave = +dataset["octave"];
oscList[octave][dataset["note"]] = playTone(dataset["frequency"]);
dataset["pressed"] = "yes";
}
event.preventDefault(); event.stopPropagation();
}
function noteReleased(event) {
let dataset = event.target.dataset;
if (dataset && dataset["pressed"]) {
let octave = +dataset["octave"];
oscList[octave][dataset["note"]].triggerRelease();
delete oscList[octave][dataset["note"]];
delete dataset["pressed"];
}
}
function playTone(freq) {
let synth = new Tone.Synth().toDestination();
let now = Tone.now();
Tone.start();
synth.triggerAttack(freq, now);
return synth;
}
It works fine on the second touch, but after the first touch I get a warning about the audio context being suspended, even though the standard is that it is resumed when start() is called by a user action. I'm stumped here.
That Tone code looks correct. I simplified it in a CodePen and it worked on mobile on first click (iOS).
var keyElement = document.getElementById("play");
keyElement.addEventListener("touchstart", notePressed, false);
keyElement.addEventListener("touchend", noteReleased, false);
// Added mouse ELs to test on non-mobile.
keyElement.addEventListener("mousedown", notePressed, false);
keyElement.addEventListener("mouseup", noteReleased, false);
var pressedTone;
function notePressed(event) {
console.log("notePressed");
pressedTone = playTone(440);
event.preventDefault();
event.stopPropagation();
}
function noteReleased(event) {
pressedTone.triggerRelease();
}
function playTone(freq) {
console.log("playTone", freq);
let synth = new Tone.Synth().toDestination();
let now = Tone.now();
Tone.start();
synth.triggerAttack(freq, now);
return synth;
}
Here's the link to the CodePen: https://codepen.io/joeweiss/pen/gOmeQVW