8ビット風の音楽をよりダイナミックにカスタマイズし、音楽制作を楽しむゲーム。
画像のピクセルデータに基づいた多様な音が生成され、曲として再生されます。
コードをメモ帳などのテキストエディタに貼り付け、ファイル名を「index.html」として保存します。その後、保存したファイルをブラウザで開けば、コードが実行されます。
スライダーによる調整:
基本周波数 (Hz) を調整することで、生成される音の全体的な高さを変えられます。
周波数変動幅を調整することで、音程の変動の強さを調整可能。
再生速度も調整でき、音のテンポを変えることができます。
インタラクティブな操作: 画像のサイズや音のパラメータをリアルタイムで変更し、結果を即座に反映させて再生できます。
がんばれば、8ビット風の音楽をよりダイナミックにカスタマイズし、音楽制作を楽しむことができます。
モールスのほうが落ち着く。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>8ビット音楽生成</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
margin: 20px;
}
#canvas, #uploadedImage {
display: block;
margin: 20px auto;
}
#canvas {
border: 1px solid black;
}
input[type="range"] {
width: 300px;
}
</style>
</head>
<body>
<h1>画像から8ビット音楽生成</h1>
<input type="file" id="imageInput" accept="image/*"><br>
<label for="sizeSlider">画像サイズ: <span id="sizeValue">256</span> x <span id="sizeValue2">256</span></label><br>
<input type="range" id="sizeSlider" min="16" max="512" value="256"><br>
<label for="frequencyBaseSlider">基本周波数 (Hz): <span id="frequencyBaseValue">100</span></label><br>
<input type="range" id="frequencyBaseSlider" min="50" max="500" value="100"><br>
<label for="frequencyRangeSlider">周波数変動幅: <span id="frequencyRangeValue">200</span></label><br>
<input type="range" id="frequencyRangeSlider" min="50" max="1000" value="200"><br>
<label for="speedSlider">再生速度: <span id="speedValue">256</span></label><br>
<input type="range" id="speedSlider" min="50" max="1000" value="256"><br>
<button id="playSound">8ビット音楽を再生</button>
<img id="uploadedImage" alt="アップロードされた画像">
<canvas id="canvas"></canvas>
<script>
const imageInput = document.getElementById('imageInput');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const uploadedImage = document.getElementById('uploadedImage');
const playSoundButton = document.getElementById('playSound');
const sizeSlider = document.getElementById('sizeSlider');
const sizeValue = document.getElementById('sizeValue');
const sizeValue2 = document.getElementById('sizeValue2');
const frequencyBaseSlider = document.getElementById('frequencyBaseSlider');
const frequencyBaseValue = document.getElementById('frequencyBaseValue');
const frequencyRangeSlider = document.getElementById('frequencyRangeSlider');
const frequencyRangeValue = document.getElementById('frequencyRangeValue');
const speedSlider = document.getElementById('speedSlider');
const speedValue = document.getElementById('speedValue');
let pixelData = [];
let imgWidth = 256;
let imgHeight = 256;
// スライダーの値で画像サイズを変更
sizeSlider.addEventListener('input', function() {
imgWidth = imgHeight = sizeSlider.value;
sizeValue.textContent = imgWidth;
sizeValue2.textContent = imgHeight;
canvas.width = imgWidth;
canvas.height = imgHeight;
if (uploadedImage.src) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(uploadedImage, 0, 0, imgWidth, imgHeight);
pixelData = ctx.getImageData(0, 0, imgWidth, imgHeight).data;
}
});
// 周波数とスピードのスライダーに応じて値を更新
frequencyBaseSlider.addEventListener('input', function() {
frequencyBaseValue.textContent = frequencyBaseSlider.value;
});
frequencyRangeSlider.addEventListener('input', function() {
frequencyRangeValue.textContent = frequencyRangeSlider.value;
});
speedSlider.addEventListener('input', function() {
speedValue.textContent = speedSlider.value;
});
// 画像を読み込み、スライダーに応じてリサイズし、ピクセルデータを取得
imageInput.addEventListener('change', function(event) {
const file = event.target.files[0];
const img = new Image();
const reader = new FileReader();
reader.onload = function(e) {
img.src = e.target.result;
uploadedImage.src = e.target.result; // アップロードされた画像を表示
};
img.onload = function() {
canvas.width = imgWidth;
canvas.height = imgHeight;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, imgWidth, imgHeight);
pixelData = ctx.getImageData(0, 0, imgWidth, imgHeight).data;
alert('ピクセルデータを取得しました');
};
reader.readAsDataURL(file);
});
// 8ビット風音楽生成
playSoundButton.addEventListener('click', function() {
if (pixelData.length === 0) {
alert('まず画像をアップロードしてください');
return;
}
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const sampleRate = audioCtx.sampleRate;
const buffer = audioCtx.createBuffer(1, sampleRate * 10, sampleRate); // 10秒間のバッファ
const channelData = buffer.getChannelData(0);
let time = 0;
const baseFrequency = parseFloat(frequencyBaseSlider.value);
const frequencyRange = parseFloat(frequencyRangeSlider.value);
const playbackSpeed = parseInt(speedSlider.value);
// ピクセルデータを基に音を生成(8ビット風の矩形波と音程の急激な変化)
for (let i = 0; i < pixelData.length; i += 4) {
const r = pixelData[i];
const g = pixelData[i + 1];
const b = pixelData[i + 2];
// RGB値を基に周波数を急激に変化させる
let frequency = baseFrequency + (r + g + b) / 3 + Math.sin(i / 500) * frequencyRange; // 音程をダイナミックに変化
// 矩形波を生成(8ビットスタイル)
for (let j = 0; j < sampleRate / playbackSpeed; j++) {
const t = j / sampleRate;
const squareWave = Math.sign(Math.sin(2 * Math.PI * frequency * t));
channelData[time++] = squareWave;
if (time >= channelData.length) break;
}
if (time >= channelData.length) break;
}
// ループ再生用にバッファを作成
const bufferSource = audioCtx.createBufferSource();
bufferSource.buffer = buffer;
bufferSource.loop = true; // ループ再生
bufferSource.connect(audioCtx.destination);
bufferSource.start();
});
</script>
</body>
</html>