analyze_dynamics
Analyze the dynamic range of a rendered REAPER project by measuring RMS, peak levels, crest factor, and calculating a simplified DR score from 3-second blocks.
Instructions
Render the project and measure dynamic range: RMS, peak, crest factor, and a simplified DR score (average peak-to-RMS over 3-second blocks).
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/reaper_mcp/analysis_tools.py:106-150 (handler)The handler function for the 'analyze_dynamics' tool. Renders the project to a temp WAV file, loads it, computes RMS, peak, crest factor, and a simplified DR score over 3-second blocks, and returns the results as a dict.
@mcp.tool() def analyze_dynamics() -> dict: """ Render the project and measure dynamic range: RMS, peak, crest factor, and a simplified DR score (average peak-to-RMS over 3-second blocks). """ try: import soundfile as sf from reaper_mcp.render_tools import render_to_temp_file tmp = render_to_temp_file() try: data, rate = sf.read(tmp) finally: if os.path.exists(tmp): os.unlink(tmp) mono = np.mean(data, axis=1) if data.ndim > 1 else data rms = float(np.sqrt(np.mean(mono ** 2))) peak = float(np.max(np.abs(mono))) rms_db = float(20 * np.log10(rms)) if rms > 0 else -120.0 peak_db = float(20 * np.log10(peak)) if peak > 0 else -120.0 crest_db = peak_db - rms_db # Simplified DR score: average crest factor over 3-second blocks block_size = rate * 3 n_blocks = len(mono) // block_size dr_scores = [] for i in range(n_blocks): block = mono[i * block_size:(i + 1) * block_size] blk_peak = np.max(np.abs(block)) blk_rms = np.sqrt(np.mean(block ** 2)) if blk_rms > 0: dr_scores.append(float(20 * np.log10(blk_peak / blk_rms))) dr = float(np.mean(dr_scores)) if dr_scores else 0.0 return { "success": True, "rms_db": round(rms_db, 1), "peak_db": round(peak_db, 1), "crest_factor_db": round(crest_db, 1), "dr_score": round(dr, 1), } except Exception as e: return {"success": False, "error": str(e)} - src/reaper_mcp/server.py:18-28 (registration)Registration: the analysis_tools module's register_tools function is imported as _reg_analysis and called with the mcp instance on line 28. This triggers the @mcp.tool() decorator that registers analyze_dynamics.
from reaper_mcp.analysis_tools import register_tools as _reg_analysis _reg_project(mcp) _reg_track(mcp) _reg_midi(mcp) _reg_fx(mcp) _reg_audio(mcp) _reg_mixing(mcp) _reg_render(mcp) _reg_mastering(mcp) _reg_analysis(mcp) - src/reaper_mcp/analysis_tools.py:21-22 (registration)The register_tools function that defines all analysis tools, including analyze_dynamics, using the @mcp.tool() decorator pattern.
def register_tools(mcp): - src/reaper_mcp/render_tools.py:47-56 (helper)The render_to_temp_file helper used by analyze_dynamics to render the REAPER project to a temporary WAV file for analysis.
def render_to_temp_file(sample_rate: int = 48000) -> str: """ Render the current project to a temporary WAV file and return its path. Used by analysis and mastering tools. Caller is responsible for deleting the file. """ import tempfile tmp = tempfile.mktemp(suffix=".wav") _set_render_settings(tmp, "wav", sample_rate, 24, 2, bounds=0) RPR.Main_OnCommand(41824, 0) return tmp