<!DOCTYPE html>
<html lang="jp">
<head>
<meta charset="UTF-8">
<title>作曲ページ</title>
<link rel="stylesheet" href="./kenban.css">
<style>
.hidden {
display: none;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
<script>
let synth = new Tone.Synth().toDestination();
const instruments = {
"synth": new Tone.Synth().toDestination(),
"piano": new Tone.Sampler({
"C3": "https://nbrosowsky.github.io/tonejs-instruments/samples/piano/C3.mp3",
"C4": "https://nbrosowsky.github.io/tonejs-instruments/samples/piano/C4.mp3",
"C5": "https://nbrosowsky.github.io/tonejs-instruments/samples/piano/C5.mp3",
"C6": "https://nbrosowsky.github.io/tonejs-instruments/samples/piano/C6.mp3",
"C7": "https://nbrosowsky.github.io/tonejs-instruments/samples/piano/C7.mp3"
}).toDestination(),
"violin": new Tone.Sampler({
"G3": "https://nbrosowsky.github.io/tonejs-instruments/samples/violin/G3.mp3",
"C4": "https://nbrosowsky.github.io/tonejs-instruments/samples/violin/C4.mp3",
"C5": "https://nbrosowsky.github.io/tonejs-instruments/samples/violin/C5.mp3",
"C6": "https://nbrosowsky.github.io/tonejs-instruments/samples/violin/C6.mp3",
"C7": "https://nbrosowsky.github.io/tonejs-instruments/samples/violin/C7.mp3"
}).toDestination(),
"trumpet": new Tone.Sampler({
"F3": "https://nbrosowsky.github.io/tonejs-instruments/samples/trumpet/F3.mp3",
"C4": "https://nbrosowsky.github.io/tonejs-instruments/samples/trumpet/C4.mp3",
"A5": "https://nbrosowsky.github.io/tonejs-instruments/samples/trumpet/A5.mp3",
"G4": "https://nbrosowsky.github.io/tonejs-instruments/samples/trumpet/G4.mp3",
"C6": "https://nbrosowsky.github.io/tonejs-instruments/samples/trumpet/C6.mp3",
}).toDestination()
};
let recordedNotes = [];
let noteLengths = [];
let pianoRoll = [];
let currentOctave = 4; // 初期オクターブ
window.onload = () => {
drawKeyboard();
};
const drawKeyboard = () => {
const musicalScaleArray = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
let baseKey;
for (let i = 0; i < 25; i++) {
const key = document.createElement("button");
key.id = `key_${musicalScaleArray[i % musicalScaleArray.length]}${Math.floor(i / 12) + 3}`;
key.onmousedown = recordNote;
key.onmouseup = stop;
key.onmouseleave = stop;
if (musicalScaleArray[i % 12].indexOf("#") > -1) {
key.classList.add("black");
} else {
key.classList.add("white");
baseKey = document.createElement("div");
}
baseKey.appendChild(key);
document.getElementById("keyboard").appendChild(baseKey);
}
};
const recordNote = (e) => {
const scale = e.target.id.split("_")[1];
const noteLength = document.getElementById("noteLength").value;
const octaveAdjustedScale = adjustOctave(scale);
recordedNotes.push(octaveAdjustedScale);
noteLengths.push(noteLength);
synth.triggerAttack(octaveAdjustedScale);
addToPianoRoll(octaveAdjustedScale, noteLength);
updatePianoRoll();
};
const adjustOctave = (scale) => {
const note = scale.slice(0, -1);
const octave = parseInt(scale.slice(-1));
const newOctave = octave + currentOctave - 4; // 初期オクターブからの差分を計算
return `${note}${newOctave}`;
};
const addToPianoRoll = (scale, length) => {
pianoRoll.push({ scale, length });
};
const updatePianoRoll = () => {
const pianoRollTable = document.getElementById("pianoRoll");
pianoRollTable.innerHTML = "<tr><th>音高</th><th>長さ</th></tr>";
pianoRoll.forEach((note, index) => {
const newRow = document.createElement("tr");
newRow.innerHTML = `<td>${note.scale}</td><td>${note.length}</td>`;
pianoRollTable.appendChild(newRow);
});
};
const play = async () => {
await Tone.start();
Tone.Transport.bpm.value = document.getElementById("tempo").value;
let currentTime = Tone.now();
recordedNotes.forEach((scale, index) => {
const duration = Tone.Time(noteLengths[index]).toSeconds();
const endTime = currentTime + duration;
if (scale !== "rest") {
synth.triggerAttackRelease(scale, noteLengths[index], currentTime);
}
currentTime = endTime;
});
};
const stop = async () => {
synth.triggerRelease();
};
const reset = () => {
recordedNotes = [];
noteLengths = [];
pianoRoll = [];
updatePianoRoll();
};
const toggleKeyboard = () => {
const keyboard = document.getElementById("keyboard");
if (keyboard.classList.contains("hidden")) {
keyboard.classList.remove("hidden");
} else {
keyboard.classList.add("hidden");
}
};
const setInstrument = (instrumentName) => {
synth = instruments[instrumentName];
};
const increaseOctave = () => {
if (currentOctave < 7) {
currentOctave++;
document.getElementById("currentOctave").textContent = currentOctave;
}
};
const decreaseOctave = () => {
if (currentOctave > 1) {
currentOctave--;
document.getElementById("currentOctave").textContent = currentOctave;
}
};
const recordRest = () => {
const noteLength = document.getElementById("noteLength").value;
recordedNotes.push("rest");
noteLengths.push(noteLength);
addToPianoRoll("休符", noteLength);
updatePianoRoll();
};
</script>
</head>
<body>
<p>キーボード</p>
<button onclick="toggleKeyboard()">show/hide</button>
<div id="keyboard" class="keyboard hidden"></div>
<p>
<label for="tempo">BPM:</label>
<input type="number" id="tempo" value="120" min="1">
</p>
<p>
<label for="noteLength">length of notes</label>
<select id="noteLength">
<option value="1n">1</option>
<option value="2n">2</option>
<option value="4n.">4.</option>
<option value="4n">4</option>
<option value="8n.">8.</option>
<option value="8n">8</option>
<option value="16n">16</option>
</select>
</p>
<p>
<label for="instrumentSelect">Instrument:</label>
<select id="instrumentSelect" onchange="setInstrument(this.value)">
<option value="synth">シンセサイザー</option>
<option value="piano">ピアノ</option>
<option value="violin">ヴァイオリン</option>
<option value="trumpet">トランペット</option>
</select>
</p>
<p>
<button onclick="recordRest()">休符を入力</button>
</p>
<p>
<button onclick="decreaseOctave()">-</button>
<span>Octave: <span id="currentOctave">4</span></span>
<button onclick="increaseOctave()">+</button>
</p>
<button onclick="play()">start</button>
<button onclick="reset()">reset</button>
<table id="pianoRoll"></table>
</body>
</html>