Beat Detection
Learning Objectives
- Understand how beat detection works
- Learn about onset detection
- Implement beat tracking algorithms
- See how MixMind finds beats
What is Beat Detection?
Beat detection is the process of identifying the rhythmic pulse in music. The beat is what you tap your foot to—the regular, repeating pattern that makes you want to dance.
Beat detection algorithms analyze audio to find:
- Beat positions: When each beat occurs (in milliseconds)
- Tempo (BPM): How many beats per minute
- Beat strength: How prominent each beat is
- Time signature: How beats are grouped (4/4, 3/4, etc.)
Onset Detection
Onsets are the moments when a new sound begins—like a drum hit or a plucked string. Beat detection starts by finding onsets.
// Detect onsets by finding energy increases
function detectOnsets(audioData, sampleRate) {
const windowSize = Math.floor(sampleRate * 0.02); // 20ms windows
const hopSize = Math.floor(sampleRate * 0.01); // 10ms hop
const energy = [];
// Calculate energy in each window
for (let i = 0; i < audioData.length - windowSize; i += hopSize) {
let sum = 0;
for (let j = 0; j < windowSize; j++) {
sum += audioData[i + j] * audioData[i + j];
}
energy.push(sum / windowSize);
}
// Find onsets (sudden energy increases)
const onsets = [];
const threshold = 1.5; // Energy must increase by 50%
for (let i = 1; i < energy.length; i++) {
const ratio = energy[i] / energy[i - 1];
if (ratio > threshold) {
onsets.push({
time: i * hopSize / sampleRate,
strength: ratio
});
}
}
return onsets;
}
Beat Tracking
Once we have onsets, we need to find the regular pattern. This is called beat tracking.
// Simple beat tracking using autocorrelation
function trackBeats(onsets, minBPM = 60, maxBPM = 200) {
// Convert BPM range to interval range (in seconds)
const minInterval = 60 / maxBPM;
const maxInterval = 60 / minBPM;
// Test different tempos
let bestTempo = 120;
let bestScore = 0;
for (let bpm = minBPM; bpm <= maxBPM; bpm += 0.5) {
const interval = 60 / bpm;
let score = 0;
// Count how many onsets align with this tempo
for (let i = 1; i < onsets.length; i++) {
const diff = onsets[i].time - onsets[i - 1].time;
// Check if this interval matches our tempo
const remainder = diff % interval;
const tolerance = interval * 0.1; // 10% tolerance
if (remainder < tolerance || (interval - remainder) < tolerance) {
score += onsets[i].strength;
}
}
if (score > bestScore) {
bestScore = score;
bestTempo = bpm;
}
}
return bestTempo;
}
// Place beats at regular intervals
function placeBeats(tempo, duration, startTime = 0) {
const interval = 60 / tempo;
const beats = [];
for (let t = startTime; t < duration; t += interval) {
beats.push(t);
}
return beats;
}
Advanced Beat Detection
Real beat detection is more sophisticated:
- Frequency bands: Analyze bass, mid, and treble separately (drums are usually in bass)
- Dynamic programming: Find the most likely beat sequence
- Metrical levels: Detect beats, bars, and phrases
- Tempo changes: Handle songs that speed up or slow down
🎵 MixMind Connection
How MixMind Detects Beats
// MixMind's beat detection system
class BeatDetector {
async analyze(audioBuffer) {
// Focus on bass frequencies (where drums are)
const bassData = this.extractBass(audioBuffer);
// Detect onsets
const onsets = this.detectOnsets(bassData, audioBuffer.sampleRate);
// Track tempo using multiple methods
const tempo1 = this.trackBeatsAutocorrelation(onsets);
const tempo2 = this.trackBeatsSpectral(onsets);
// Use the more confident result
const bpm = this.selectBestTempo(tempo1, tempo2);
// Generate beat positions
const beats = this.placeBeats(bpm, audioBuffer.duration);
return {
bpm: bpm,
beats: beats,
confidence: this.calculateConfidence(onsets, beats)
};
}
// Extract bass frequencies (20-250 Hz)
extractBass(audioBuffer) {
// Apply low-pass filter
const filtered = this.applyFilter(audioBuffer, 'lowpass', 250);
return filtered.getChannelData(0);
}
}
// Used for:
// - Syncing tracks
// - Beat grid visualization
// - Quantizing effects
// - Transition timing
Exercise 19.1: Practice
Goal: Apply what you've learned in this chapter
Try the concepts from this chapter in your browser's console or a simple HTML file. Experiment with the code examples and modify them to see what happens.
Review the key concepts from this chapter and make sure you understand each one before moving to the next chapter.