メトロノーム - タップテンポBPM検出器&クリックトラック オンライン
音楽に合わせてタップしてBPMを検出し、調整可能なテンポ、拍子記号、サブディビジョン、視覚的ビートインジケーターで正確なクリックトラックを再生 — Web Audio APIを使用した100%クライアントサイド。
耳を保護してください。低い音量から始めてください。
タップして開始...
よくある質問
メトロノームとは何ですか?何に使いますか?
メトロノームは、BPM(1分あたりの拍数)で測定される設定可能なテンポで、一定のクリックやビートを生成するデバイスまたはツールです。ミュージシャンはメトロノームを使用して、一貫したタイミングを身につけ、特定のテンポで練習し、リズムの正確さを維持しながら徐々にスピードを上げていきます。このオンラインメトロノームには、ビートに合わせてタップすることで曲のBPMを検出できるタップテンポ機能も搭載されています。
タップテンポ機能はどのように使いますか?
聴いている音楽のリズムに合わせて大きなTAPボタンを繰り返しタップしてください。2回以上タップすると、ツールがタップ間の平均間隔を計算し、検出されたBPMを表示します。最高の精度を得るには、キックドラムやメインパルスに合わせて4〜8拍タップしてください。安定性インジケーターはタッピングの一貫性を示します。BPMの読み取り値が得られたら、「Use this BPM」をクリックして練習用のメトロノームに直接転送してください。
メトロノームのクリックトラックはどのように使いますか?
メトロノームタブに切り替え、スライダーまたは数値入力を使用して希望のBPMを設定し、拍子記号(例:4/4の場合は一般的な拍子)を選択して、再生を押します。メトロノームは1拍目にアクセントされたダウンビートを含む可聴クリックを生成します。ビジュアルビートインジケーターを見て、小節内の現在位置を確認してください。練習のニーズに合わせて音量、サブディビジョン、クリック音を調整してください。
データはサーバーに送信されますか?
いいえ。このツールは100%クライアントサイドで動作し、ブラウザに内蔵されたWeb Audio APIを使用します。すべてのオーディオ合成、テンポ検出、ビートスケジューリングは完全にお使いのデバイス上で行われます。オーディオデータ、BPM読み取り値、設定がサーバーに送信されることは一切ありません。初回ページ読み込み後は完全にオフラインで動作します。
正確なタイミングが重要な理由と、このメトロノームがそれをどう実現しているか教えてください
音楽の練習には数ミリ秒以内のタイミング精度が必要です。JavaScriptの組み込みsetTimeout/setIntervalは、メインスレッドが他のタスクによって遅延する可能性があるため、それ単体では十分に正確ではありません。このメトロノームは業界標準のルックアヘッドスケジューラーパターンを使用しています:setIntervalタイマーが頻繁に起動し、Web Audio APIの高解像度AudioContext.currentTimeクロックを使用してオーディオイベントを事前にスケジュールします。これにより、長い練習セッションでもドリフトなしに1〜2ミリ秒以内の正確なクリックが保証されます。
拍子記号とは何ですか?どの拍子記号がサポートされていますか?
拍子記号は各小節に何拍あるか、どの音符の値が1拍を受けるかを示します。このツールは以下をサポートしています:4/4(一般的な拍子、ほとんどのポップ/ロックで使用)、3/4(ワルツ)、2/4(行進曲)、6/8(複合2拍子、ジグで一般的)、5/4(変拍子、Take Fiveのように)、7/8(変拍子、バルカン音楽で一般的)。各拍子記号にはリズム構造を感じるのに役立つ適切なアクセントパターンがあります。
サブディビジョンの違いは何ですか?
サブディビジョンは各メインビートをより小さな単位に分割し、より細かいリズム練習を可能にします。「なし」は4分音符のビートのみを再生します。「8分音符」は各ビートの間にクリックを追加します(1拍につき2つ)。「3連符」は各ビートを3等分します。「16分音符」は各ビートを4等分します。サブディビジョンのクリックはパルスの階層を維持するため、メインビートよりも音が小さくなっています。
コード例
// Web Audio API Metronome with Lookahead Scheduler
class Metronome {
constructor(bpm = 120, beatsPerMeasure = 4) {
this.bpm = bpm;
this.beatsPerMeasure = beatsPerMeasure;
this.isPlaying = false;
this.currentBeat = 0;
this.nextNoteTime = 0;
this.timerID = null;
this.audioContext = null;
}
start() {
if (this.isPlaying) return;
this.audioContext = new AudioContext();
this.isPlaying = true;
this.currentBeat = 0;
this.nextNoteTime = this.audioContext.currentTime;
this.timerID = setInterval(() => this._scheduler(), 25);
}
stop() {
this.isPlaying = false;
if (this.timerID) clearInterval(this.timerID);
if (this.audioContext) this.audioContext.close();
}
_scheduler() {
while (this.nextNoteTime < this.audioContext.currentTime + 0.1) {
this._playClick(this.nextNoteTime, this.currentBeat === 0);
this.nextNoteTime += 60.0 / this.bpm;
this.currentBeat = (this.currentBeat + 1) % this.beatsPerMeasure;
}
}
_playClick(time, isAccent) {
const osc = this.audioContext.createOscillator();
const gain = this.audioContext.createGain();
osc.frequency.value = isAccent ? 1000 : 800;
gain.gain.setValueAtTime(isAccent ? 1.0 : 0.7, time);
gain.gain.exponentialRampToValueAtTime(0.001, time + 0.03);
osc.connect(gain);
gain.connect(this.audioContext.destination);
osc.start(time);
osc.stop(time + 0.03);
}
}
// Tap Tempo Detector
function createTapDetector(maxTaps = 8, resetMs = 2000) {
const taps = [];
let resetTimer = null;
return {
tap() {
const now = performance.now();
if (resetTimer) clearTimeout(resetTimer);
resetTimer = setTimeout(() => { taps.length = 0; }, resetMs);
taps.push(now);
if (taps.length > maxTaps) taps.shift();
if (taps.length < 2) return null;
const intervals = [];
for (let i = 1; i < taps.length; i++) {
intervals.push(taps[i] - taps[i - 1]);
}
const avg = intervals.reduce((a, b) => a + b) / intervals.length;
return Math.round(60000 / avg);
},
reset() {
taps.length = 0;
},
};
}
// Usage
const metronome = new Metronome(120, 4);
metronome.start();
setTimeout(() => metronome.stop(), 5000);