ギターのチューニングアプリです。
Guitar TunerGuitar Tuner
<p>Click the "Start Tuner" button and play each string. The app will help you tune your guitar.</p>
<button id="startButton">Start Tuner</button>
<div id="tuner">
<div>
<h2>Current Note:</h2>
<div id="currentNote"></div>
</div>
<div>
<h2>Detected Note:</h2>
<div id="detectedNote"></div>
</div>
</div>
<script>
// 音声入力用のメディアストリーム
let audioContext;
let mediaStream;
let analyser;
// ギターの標準チューニング
const standardTuning = ['E2', 'A2', 'D3', 'G3', 'B3', 'E4'];
// ターゲットの周波数と許容誤差(Hz)の定義
const targetFrequencies = {
'E2': 82.41,
'A2': 110.00,
'D3': 146.83,
'G3': 196.00,
'B3': 246.94,
'E4': 329.63
};
const tolerance = 5;
// ユーザーの入力を制御するためのフラグ
let isTuning = false;
// チューニングの結果を表示するための要素への参照
const currentNoteElement = document.getElementById('currentNote');
const detectedNoteElement = document.getElementById('detectedNote');
// スタートボタンをクリックしたときの処理
document.getElementById('startButton').addEventListener('click', async () => {
if (!isTuning) {
isTuning = true;
startTuner();
document.getElementById('startButton').textContent = 'Stop Tuner';
} else {
isTuning = false;
stopTuner();
document.getElementById('startButton').textContent = 'Start Tuner';
}
});
// チューナーを開始する関数
async function startTuner() {
try {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
const audioSource = audioContext.createMediaStreamSource(mediaStream);
analyser = audioContext.createAnalyser();
audioSource.connect(analyser);
analyser.fftSize = 2048;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
analyser.getByteTimeDomainData(dataArray);
// チューニングの検出を行うループ
const detectTuning = () => {
analyser.getByteTimeDomainData(dataArray);
// 波形データから周波数を取得
const pitch = getPitch(dataArray, audioContext.sampleRate);
// デフォルトのチューニングとの一致を確認
const detectedNote = getClosestNote(pitch);
detectedNoteElement.textContent = detectedNote;
if (isTuning) {
// チューニングが続いている場合、再帰呼び出し
requestAnimationFrame(detectTuning);
}
};
detectTuning();
} catch (error) {
console.error(error);
}
}
// チューナーを停止する関数
function stopTuner() {
if (mediaStream) {
mediaStream.getTracks().forEach(track => track.stop());
}
if (audioContext) {
audioContext.close();
}
currentNoteElement.textContent = '';
detectedNoteElement.textContent = '';
}
// 周波数データからピッチ(音程)を取得する関数
function getPitch(dataArray, sampleRate) {
// ピークを検出
const peak = findPeak(dataArray);
// ピークの位置をサンプル数から周波数に変換
const frequency = peak / dataArray.length * sampleRate;
return frequency;
}
// ピークを検出する関数
function findPeak(dataArray) {
let peakIndex = 0;
let peakValue = 0;
for (let i = 0; i < dataArray.length; i++) {
if (dataArray[i] > peakValue) {
peakIndex = i;
peakValue = dataArray[i];
}
}
return peakIndex;
}
// 最も近いノートを取得する関数
function getClosestNote(frequency) {
let closestNote = '';
let minDiff = Infinity;
for (const note in targetFrequencies) {
const targetFrequency = targetFrequencies[note];
const diff = Math.abs(frequency - targetFrequency);
if (diff < minDiff && diff <= tolerance) {
closestNote = note;
minDiff = diff;
}
}
currentNoteElement.textContent = closestNote;
return closestNote;
}
</script>