Chapter 22
Phrase Detection
Learning Objectives
- Understand musical phrases
- Learn phrase boundary detection
- Analyze song structure
- See how MixMind detects phrases
What are Musical Phrases?
A phrase is a musical sentenceโa complete musical thought, typically 4, 8, 16, or 32 bars long.
Songs are built from phrases:
- Intro: Opening section (8-16 bars)
- Verse: Main storytelling section (16 bars)
- Chorus: Catchy, repeated section (8 bars)
- Bridge: Contrasting section (8 bars)
- Outro: Ending section (8-16 bars)
๐ก DJ Mixing:
Good mixes align phrases. Start track 2's intro when track 1's verse begins. This creates smooth, musical transitions.
Detecting Phrase Boundaries
Phrase boundaries often occur where there are changes in the music:
- Energy changes (drums drop out, new instruments enter)
- Structural changes (verse to chorus)
- Silence or pauses
- Drum fills
// Detect phrase boundaries using energy changes
function detectPhrases(audioBuffer, beatPositions) {
const energy = calculateEnergyEnvelope(audioBuffer);
const boundaries = [];
// Look for energy drops (common at phrase ends)
const windowSize = 4; // 4 beats
for (let i = windowSize; i < beatPositions.length - windowSize; i++) {
const beforeBeat = beatPositions[i - windowSize];
const afterBeat = beatPositions[i];
const energyBefore = getAverage(energy, beforeBeat, beatPositions[i]);
const energyAfter = getAverage(energy, beatPositions[i], afterBeat);
// Significant energy drop
if (energyAfter < energyBefore * 0.7) {
boundaries.push({
beat: i,
time: beatPositions[i],
strength: energyBefore - energyAfter
});
}
}
return boundaries;
}
Structural Analysis
Detect the overall structure (intro, verse, chorus, etc.) by analyzing patterns:
// Analyze song structure
function analyzeStructure(audioBuffer, phrases) {
const sections = [];
// Extract features for each phrase
const features = phrases.map(phrase => ({
energy: calculateEnergy(phrase),
spectralCentroid: calculateCentroid(phrase),
chroma: calculateChroma(phrase)
}));
// Cluster similar phrases
const clusters = clusterPhrases(features);
// Label sections
// First cluster = verse (most common)
// Highest energy cluster = chorus
// First section = intro
// Last section = outro
return sections;
}
// Simple clustering
function clusterPhrases(features) {
// Use similarity metrics to group phrases
// Similar energy + timbre = same section
}
๐ต MixMind Connection
How MixMind Detects Phrases
// MixMind's phrase detection
class PhraseDetector {
async analyze(audioBuffer, beats) {
// Calculate multi-band energy
const energy = {
bass: this.calculateEnergy(audioBuffer, 20, 250),
mid: this.calculateEnergy(audioBuffer, 250, 4000),
high: this.calculateEnergy(audioBuffer, 4000, 20000),
total: this.calculateEnergy(audioBuffer, 20, 20000)
};
// Detect phrase boundaries
const boundaries = this.detectBoundaries(energy, beats);
// Group into phrases (typically 8 or 16 beats)
const phrases = this.groupIntoPhrases(boundaries, beats);
// Analyze structure
const structure = this.analyzeStructure(phrases);
return {
phrases: phrases,
structure: structure, // intro, verse, chorus, etc.
phraseLength: this.detectPhraseLength(phrases)
};
}
// Suggest mix points
suggestMixPoints(structure) {
const suggestions = [];
// Intro end = good entry point
if (structure.intro) {
suggestions.push({
time: structure.intro.end,
reason: "End of intro - good for bringing in next track"
});
}
// Before chorus = high energy entry
if (structure.verse) {
suggestions.push({
time: structure.verse[0].start,
reason: "Start of verse - build up to chorus"
});
}
return suggestions;
}
}
// Used for:
// - Suggesting mix-in/out points
// - Phrase-aligned transitions
// - Structure visualization
Exercise 22.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.
๐ Quick Reference:
Review the key concepts from this chapter and make sure you understand each one before moving to the next chapter.