I am trying to code a web page in which an input is given a list of frequencies separated by spaces, and then play these frequencies with Tone.js.
First, I had this piece of code that only play notes one by one and works as expected:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Play and Record Notes</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.26/Tone.js"></script>
</head>
<body>
<h1>Play and Record Notes</h1>
<label for="frequenciesInput">Enter frequencies (separated by spaces):</label><br>
<input type="text" id="frequenciesInput"><br>
<button id="playButton">Play</button>
<audio controls style="display: none;"></audio>
<script>
let playButton = document.getElementById('playButton');
let inputNotes = document.getElementById('frequenciesInput');
let started = false;
playButton.addEventListener('click', () => {
if (started) return;
started = true;
const audio = document.querySelector('audio');
const synth = new Tone.Synth();
const actx = Tone.context;
const dest = actx.createMediaStreamDestination();
const recorder = new MediaRecorder(dest.stream);
synth.connect(dest);
synth.toMaster();
const chunks = [];
const notes = inputNotes.value.split(' ').map(n => parseInt(n));
let note = 0;
Tone.Transport.cancel();
Tone.Transport.scheduleRepeat(time => {
if (note === 0) recorder.start();
if (note > notes.length) {
synth.triggerRelease(time)
recorder.stop();
Tone.Transport.stop();
} else synth.triggerAttack(notes[note], time);
note++;
}, '4n');
recorder.ondataavailable = evt => chunks.push(evt.data);
recorder.onstop = evt => {
let blob = new Blob(chunks, { type: 'audio/ogg; codecs=opus' });
audio.src = URL.createObjectURL(blob);
audio.style.display = 'block';
};
Tone.Transport.start();
started = false;
});
</script>
</body>
</html>
Then I added a checkbox for playing notes in chord (i.e. simultaneously) with Tone.PolySynth :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Play and Record Notes</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.26/Tone.js"></script>
</head>
<body>
<h1>Play and Record Notes</h1>
<label for="frequenciesInput">Enter frequencies (separated by spaces):</label><br>
<input type="text" id="frequenciesInput"><br>
<input type="checkbox" id="playSimultaneously">
<label for="playSimultaneously">Play all notes simultaneously</label><br>
<button id="playButton">Play</button>
<audio controls style="display: none;"></audio>
<script>
let playButton = document.getElementById('playButton');
let inputNotes = document.getElementById('frequenciesInput');
let checkboxSim = document.getElementById('playSimultaneously');
let started = false;
playButton.addEventListener('click', () => {
if (started) return;
started = true;
const audio = document.querySelector('audio');
const synth = new Tone.Synth();
const polySynth = new Tone.PolySynth()
const actx = Tone.context;
const dest = actx.createMediaStreamDestination();
const recorder = new MediaRecorder(dest.stream);
synth.connect(dest);
synth.toMaster();
polySynth.connect(dest);
polySynth.toMaster();
const chunks = [];
const notes = inputNotes.value.split(' ').map(n => parseInt(n));
if (!checkboxSim.checked) {
let note = 0;
Tone.Transport.cancel();
Tone.Transport.scheduleRepeat(time => {
if (note === 0) recorder.start();
if (note >= notes.length) {
synth.triggerRelease(time)
recorder.stop();
Tone.Transport.stop();
} else synth.triggerAttack(notes[note], time);
note++;
}, '4n');
}
else {
Tone.Transport.cancel();
Tone.Transport.scheduleRepeat(time => {
recorder.start();
polySynth.triggerAttack(notes, time);
polySynth.triggerRelease(time);
recorder.stop();
Tone.Transport.stop();
}, '4n');
}
recorder.ondataavailable = evt => chunks.push(evt.data);
recorder.onstop = evt => {
let blob = new Blob(chunks, { type: 'audio/ogg; codecs=opus' });
audio.src = URL.createObjectURL(blob);
audio.style.display = 'block';
};
Tone.Transport.start();
started = false;
});
</script>
</body>
</html>
However, when I activate the 'Play all notes simultaneously' option, the chord is played but I get an error message in the console that says: net::ERR_REQUEST_RANGE_NOT_SATISFIABLE. What have I done wrong?