Sonic Syntax — Global Optimization CSP Solver

"Caesura Logic" — Finds the globally optimal sequence of cuts using dynamic programming with hard and soft constraints.

Algorithm: Global Boundary Detector (Dynamic Programming) Type: Constraint Satisfaction Problem Solver Domain: Audio Segmentation & Phrasing Implementation: Praat Script
Contents:

What this does

This script implements global optimization for audio boundary detection — a dynamic programming approach to finding the optimal sequence of cuts (phrase boundaries) in speech or music audio. Unlike local or rule-based detectors, this solver evaluates all possible cut combinations under defined constraints to find the globally optimal path through candidate boundary points.

Key Features:

Why global optimization? Traditional boundary detectors use local decisions: "Is this point a good boundary?" Global optimization asks: "What is the best set of boundaries overall?" This avoids problems like boundary clustering (too many cuts close together) or missing boundaries that only make sense in context. The algorithm treats boundary selection as a Constraint Satisfaction Problem (CSP) with:
  • Variables: Candidate cut positions
  • Hard Constraints: Must be satisfied (e.g., minimum spacing)
  • Soft Constraints: Weighted preferences (e.g., falling pitch preferred)
  • Objective: Maximize total score across all selected cuts
Use cases: Speech phrasing analysis, musical phrase segmentation, audio editing automation, linguistic research, and any task requiring optimal boundary placement.

Quick start

  1. In Praat, select exactly one Sound object.
  2. Run script…Sonic_Syntax_Global_Optimizer.praat.
  3. Set Hard Constraints:
    • Silence_threshold_relative_to_max_(dB): e.g., -25 dB
    • Min_duration_between_cuts_(s): e.g., 0.5 seconds
  4. Set Soft Constraint Weights:
    • Weight_Pitch_Slope: Higher = prefer falling pitch at boundaries
    • Weight_Centering: Higher = prefer cuts centered in silent intervals
  5. Adjust Insertion_bonus (50.0 default):
    • Higher = more cuts allowed
    • Lower = stricter quality control
  6. Set analysis parameters (pitch range, window size, etc.)
  7. Enable Create_TextGrid and Print_debug_log for output
  8. Click OK — algorithm runs, outputs optimal boundaries
Quick tip: Start with default parameters for your audio type. For speech, try Silence_threshold = -25 dB, Min_duration = 0.3s. For music, adjust pitch ceiling (e.g., 1000 Hz for instruments). Use Insertion_bonus to control density: 30-50 for normal speech, 70-100 for dense segmentation. Enable Print_debug_log to see candidate counts and final path score. The algorithm may take a few seconds for long files with many candidates.
Important: The algorithm requires silence candidates to work. If no silences are detected (threshold too high), it will exit. Adjust Silence_threshold if needed (more negative = stricter). Min_duration_between_cuts is a HARD constraint — no two cuts will be closer than this. Dynamic programming complexity is O(n²) in number of candidates — very long files with many silences may be slower. Insertion_bonus dominates scoring — if set too high, the algorithm may select too many cuts; if too low, may select none.

Algorithm Theory

Dynamic Programming Formulation

🎯 Bellman Optimality Principle

Problem: Choose subset of candidate cuts maximizing total score while respecting minimum spacing.

State: dp_max_score[i] = best total score ending at cut i

Transition: dp_max_score[i] = max(dp_max_score[j] + local_score[i]) for all j where distance(i,j) ≥ min_duration

Initialization: dp_max_score[i] = local_score[i] if distance from start ≥ min_duration

Solution: Backtrack from best ending node using dp_prev_index[]

Mathematical Formulation

Let: C = {c₁, c₂, ..., cₙ} candidate cut times S(cᵢ) = local score of candidate i (soft constraints + insertion bonus) Dₘᵢₙ = minimum duration between cuts (hard constraint) Objective: Maximize Σ S(cᵢ) over selected cuts Subject to |cᵢ - cⱼ| ≥ Dₘᵢₙ for all selected i,j Dynamic Programming Recurrence: Let F(i) = maximum score ending with cut i F(i) = S(cᵢ) + max{ F(j) : cᵢ - cⱼ ≥ Dₘᵢₙ } Base: F(i) = S(cᵢ) if cᵢ ≥ Dₘᵢₙ (can be first cut) Complexity: O(n²) where n = number of candidates

Candidate Generation

STEP 1: Detect silences using intensity threshold Intensity object → TextGrid (silences) Label "silent" intervals as candidate regions STEP 2: Extract candidate points For each silent interval [start, end]: Candidate time = (start + end) / 2 (center point) Store: time, original interval index STEP 3: Calculate local scores For each candidate: Pitch slope score = -slope × weight_Pitch_Slope (falling slope → positive score) Centering score = -deviation × 100 × weight_Centering (more centered → higher score) Insertion bonus = constant (encourages cuts) Total local score = sum of above

Path Reconstruction

After forward DP pass: 1. Find node with maximum dp_max_score[i] 2. Initialize empty path list 3. While current node > 0: Add candidate time to path current = dp_prev_index[current] 4. Reverse path (was built backwards) Result: Globally optimal sequence of cut times

Constraint System

Hard Constraints

⛔ Must Be Satisfied

Silence Threshold: Candidates must be within silent intervals (relative to max amplitude)

Minimum Duration Between Cuts: No two selected cuts can be closer than this value

Implementation: These constraints prune the search space during DP — invalid transitions are never considered.

Soft Constraints (Scoring)

⚖️ Weighted Preferences

Pitch Slope: Prefer boundaries where pitch is falling (negative slope)

Score = -slope × weight_Pitch_Slope Example: slope = -50 Hz/s, weight = 2.0 → score = 100

Centering: Prefer cuts centered within silent intervals

deviation = |cut_time - interval_center| Score = -deviation × 100 × weight_Centering Example: deviation = 0.02s, weight = 1.0 → score = -2.0

Insertion Bonus: Constant added to every selected cut

Score += insertion_bonus Purpose: Controls density (higher = more cuts preferred)

Constraint Interaction

How constraints work together:
  1. Hard constraints define the feasible solution space
  2. Soft constraints score each candidate locally
  3. Insertion bonus biases toward more/less cuts
  4. DP algorithm finds the combination maximizing total score

Trade-offs: A candidate with excellent pitch slope but poor centering might still be selected if it allows other high-scoring cuts later (global optimality). The insertion bonus ensures the algorithm doesn't overly penalize simply having cuts.

Parameters

Hard Constraints

ParameterTypeDefaultDescription
Silence_threshold_relative_to_max_(dB)real-25Relative dB below max for silence detection (negative)
Min_duration_between_cuts_(s)positive0.5Minimum time between any two cuts

Soft Constraints (Weights)

ParameterTypeDefaultDescription
Weight_Pitch_Slopepositive2.0Importance of falling pitch at boundaries
Weight_Centeringpositive1.0Importance of cut centered in silence

Density Control

ParameterTypeDefaultDescription
Insertion_bonuspositive50.0Base score for selecting any cut (higher = more cuts)

Analysis Parameters

ParameterTypeDefaultDescription
Silent_interval_min_duration_(s)positive0.05Minimum silence duration to consider
Pitch_analysis_window_(s)positive0.05Window for pitch slope calculation
Pitch_floor_(Hz)positive75Minimum pitch for analysis
Pitch_ceiling_(Hz)positive500Maximum pitch for analysis

Output Options

ParameterTypeDefaultDescription
Create_TextGridboolean1Create TextGrid with boundary tier
Print_debug_logboolean1Print algorithm progress to info window
Output_tier_namesentence"Boundaries"Name of TextGrid tier

Processing Workflow

1. SETUP & FEATURE EXTRACTION Select Sound object Create Intensity object (for silence detection) Create Pitch object (for slope calculation) Detect silent intervals → candidate regions 2. CANDIDATE PREPARATION For each silent interval: - Calculate center time as candidate - Compute local score: • Pitch slope across analysis window • Centering within interval • Add insertion bonus - Store candidate data in arrays 3. DYNAMIC PROGRAMMING SOLVER Initialize DP arrays (size = n_candidates) Forward pass: For i = 1 to n_candidates: - Consider as first cut (if far enough from start) - For all j < i: If distance(i,j) ≥ min_duration: new_score = dp_max_score[j] + local_score[i] If new_score > dp_max_score[i]: Update dp_max_score[i], dp_prev_index[i] Find node with maximum score 4. PATH RECONSTRUCTION Trace back through dp_prev_index[] from best node Reverse to get chronological order Extract cut times 5. OUTPUT GENERATION Create TextGrid with boundaries at cut times Label intervals as "Phrase 1", "Phrase 2", etc. Clean up temporary objects Print summary statistics

Visualization of DP Process

Example with 5 candidates:

Candidates: c₁@1.0s, c₂@2.2s, c₃@3.1s, c₄@4.5s, c₅@5.0s
Min duration: 1.0s

DP Table:
dp_max_score[1] = 60 (first possible cut)
dp_max_score[2] = max(60+55, 70) = 115 (from c₁)
dp_max_score[3] = 75 (cannot come from c₂: 2.2→3.1 = 0.9s < 1.0s)
dp_max_score[4] = max(115+65, 75+65, 80) = 180 (from c₂)
dp_max_score[5] = max(180+50, 80+50) = 230 (from c₄)

Best path: c₁ → c₂ → c₄ → c₅ (score 230)
Not selected: c₃ (conflicts with spacing)

Applications

Speech Phrasing Analysis

Use case: Automatic detection of phrase boundaries in speech

Typical settings:

Musical Phrase Segmentation

Use case: Finding phrase boundaries in instrumental music

Adjustments:

Audio Editing Automation

Use case: Automatic cut placement for editing dialogue or podcasts

Workflow:

Linguistic Research

Use case: Studying prosodic phrasing across languages or speakers

Advantages:

Practical Examples

🗣️ Conversational Speech

Goal: Natural phrase boundaries in dialogue

Settings:

  • Silence threshold: -28 dB
  • Min duration: 0.4 s
  • Weight_Pitch_Slope: 2.5
  • Insertion_bonus: 50

Result: Boundaries at natural breath points and prosodic breaks

🎵 Classical Music Phrases

Goal: Musical phrase segmentation

Settings:

  • Silence threshold: -35 dB (stricter)
  • Min duration: 1.2 s
  • Weight_Pitch_Slope: 4.0
  • Pitch ceiling: 800 Hz

Result: Boundaries at cadence points and breath marks

📚 Audio Book Chapter Markers

Goal: Detect natural pauses for chapter breaks

Settings:

  • Silence threshold: -20 dB (lenient)
  • Min duration: 1.5 s (long pauses only)
  • Insertion_bonus: 30 (sparse selection)

Result: Key pause points suitable for chapter divisions

Troubleshooting Common Issues

Problem: No candidates found
Cause: Silence threshold too high (not negative enough) or audio has no silences
Solution: Lower threshold (e.g., -20 dB), check audio content
Problem: Too many/few cuts
Cause: Insertion_bonus too high/low
Solution: Adjust insertion_bonus (20-80 typical range)
Problem: Cuts too close together
Cause: Min_duration_between_cuts too small
Solution: Increase to 0.3-1.0 s depending on application
Problem: Slow processing
Cause: Many silence candidates (long file with many pauses)
Solution: Algorithm is O(n²) — consider increasing silent_interval_min_duration to reduce candidates

Advanced Techniques

Parameter tuning strategy:
  1. Start with defaults for your audio type
  2. Run with Print_debug_log = yes
  3. Check candidate count (should be reasonable: 10-200 for 1 min audio)
  4. Adjust insertion_bonus to get desired cut count
  5. Fine-tune weights based on which boundaries seem wrong
  6. Use Create_TextGrid to visually verify boundaries
Extending the algorithm:
  • Additional soft constraints: Add energy drop, spectral change, etc.
  • Multiple feature weights: Expand scoring function with more terms
  • Hierarchical processing: Run coarse-to-fine (first find major boundaries, then subdivide)
  • Learning weights: Use machine learning to optimize weights for your corpus