document.write(`
<style>
body {
text-align: center;
margin: 20px;
padding: 20px;
display: flex;
flex-direction: column;
}
.sequencer {
border-radius: 5px;
width: fit-content;
display: grid;
grid-template-rows: repeat(6, 1fr);
grid-template-columns: fit-content;
margin: auto;
}
.note {
border-radius: 5px;
height: 4em;
width: 4em;
border-style: solid;
border-width: 1px;
border-color: lightgray;
margin: 2px;
outline: none;
}
.sequencer-row {
display: inline-block;
white-space: nowrap;
}
.note-is-active {
background-color: green;
border: 1px solid black;
}
.note-not-active {
background-color: solid grey;
}
.toggle-play {
display: flex;
}
.play-button {
margin: auto;
}
</style>
<div id="sequencer" class="container sequencer">
</div>
<div class="toggle-play">
<button id="play-button" class="play-button">Play</button>
</div>
`);
// Load Tone.js and then execute the rest of the code
$.getScript("https://cdn.skypack.dev/tone", function () {
window.onload = function () {
const synths = makeSynths(6);
const notes = ["F4", "Eb4", "C4", "Bb3", "Ab3", "F3"];
let grid = makeGrid(notes);
let beat = 0;
let playing = false;
let started = false;
const configLoop = () => {
const repeat = (time) => {
grid.forEach((row, index) => {
let synth = synths[index];
let note = row[beat];
if (note.isActive) {
synth.triggerAttackRelease(note.note, "8n", time);
}
});
beat = (beat + 1) % 8;
};
Tone.Transport.bpm.value = 120;
Tone.Transport.scheduleRepeat(repeat, "8n");
};
const makeSequencer = () => {
const sequencer = document.getElementById("sequencer");
grid.forEach((row, rowIndex) => {
const seqRow = document.createElement("div");
seqRow.id = `rowIndex`;
seqRow.className = "sequencer-row";
row.forEach((note, noteIndex) => {
const button = document.createElement("button");
button.className = "note";
button.addEventListener("click", function (e) {
handleNoteClick(rowIndex, noteIndex, e);
});
seqRow.appendChild(button);
});
sequencer.appendChild(seqRow);
});
};
const handleNoteClick = (clickedRowIndex, clickedNoteIndex, e) => {
grid.forEach((row, rowIndex) => {
row.forEach((note, noteIndex) => {
if (clickedRowIndex === rowIndex && clickedNoteIndex === noteIndex) {
note.isActive = !note.isActive;
e.target.className = classNames(
"note",
{ "note-is-active": !!note.isActive },
{ "note-not-active": !note.isActive }
);
}
});
});
};
const configPlayButton = () => {
const button = document.getElementById("play-button");
button.addEventListener("click", (e) => {
if (!started) {
Tone.start();
Tone.getDestination().volume.rampTo(-10, 0.001);
configLoop();
started = true;
}
if (playing) {
e.target.innerText = "Play";
Tone.Transport.stop();
playing = false;
} else {
e.target.innerText = "Stop";
Tone.Transport.start();
playing = true;
}
});
};
window.addEventListener("DOMContentLoaded", () => {
configPlayButton();
makeSequencer();
});
};
});