AI for Music: Timing analysis for mridangam practice

Last updated: August 2026

An MCP server that tells you which beats weren't at tempo — not which stroke you played.

Mridangam is an Indian percussion instrument, and is a staple of Indian Carnatic music. A mridangam player is somewhat like a drummer in a band: they provide the rhythmic foundation for the music, keep the performance moving in time, and adapt their playing to complement what the singer or other musicians are doing.

The problem

Recently I was helping someone get ready for a concert. This involved daily practice of playing mridangam and also learning the konnakol for the piece. Since this was a new piece for the person I was helping, who was just getting started on their mridangam journey, it was challenging to learn both the konnakol and the correct playing pattern.

This led me to think about whether technology could be leveraged here to make the learning process easier. As far as I know, for most musical instruments, the way you say the notes is the same as the way you play them. For example, if the guitar sheet says to play E, one plays E on the guitar. But for mridangam, how you say konnakol doesn't map one-to-one onto how you play it — it's a one-to-many relationship. That means the same note can be played in multiple ways.

This gave me an idea: maybe I can identify the note by the sound and then transcribe it, so the person can quickly learn the piece. And for this I looked at the mridangam stroke dataset and built a classifier using that. But the classifier did not work as expected, since the training data set was created in a studio setting, which meant there was no variance in data quality — and as a result, it failed when classifying sounds captured by phone.

As the next iteration, I targeted the second problem of practicing with a metronome. When practicing with a metronome, it is difficult to visually get any feedback from the metronome app on whether one is playing in sync or not, and which areas need focus. A proficient mridangam player can quickly identify, when practicing, which areas are not in sync when playing with a metronome — but for someone getting started, any additional feedback apart from their own judgement is very helpful. Built a simple JS-powered HTML file that can capture live playing and give feedback in real time on whether the musician is in sync.

In order to make this tool accessible for all, I built an MCP server that can process any uploaded mridangam piece and the bpm at which the practice was done. The MCP server calls a python script that runs the analysis and sends that data to an LLM for actionable feedback.

The MCP server (and standalone CLI) answers the question "analyze the timing of my practice recording at /path/to/file.wav, target tempo 80bpm" and get back exactly which gaps were off, by how much, and how consistent the whole take was.

How it works

Three steps, all in timing_analysis.py, with no fixed configuration required beyond an optional target tempo.

Timing Analysis
1. Onset detection
librosa detects when strokes were actually played
2. Gap-by-gap tempo
gap in seconds → BPM (60 ÷ gap) → compared to target BPM
3. Subdivision detection
infers strokes-per-beat from the gap pattern — adapts mid-recording
Report
per-gap deviations, consistency stats, optional chart PNG

Two ways to use it

CLI — no LLM involved

python timing_analysis.py recording.wav --bpm 80 prints a per-gap report and saves a chart. Tempo can be omitted and it auto-estimates. Useful on its own, with nothing sent anywhere.

MCP tool — analyze_timing(filepath, bpm)

Registered with Claude Desktop or Claude Code. The model calls the tool, gets back computed stats (and optionally a chart image), and discusses the results conversationally — "which gaps were rushed," "was the subdivision consistent," etc.

Privacy / security design

The main design constraint on the MCP wrapper: the LLM should get exactly what it needs to give useful feedback, and nothing more.

The tool takes a filepath, not audio data. It reads the file locally and returns only computed statistics — never the raw audio bytes, waveform, or sample array. stdin/stdout are reserved for the MCP protocol channel, so the server logs the exact payload it's about to return to stderr before sending it, keeping what's shared with the model inspectable. Nothing is uploaded or stored anywhere beyond your own chosen LLM client.

Source

github.com/jspoth/mcp — MIT licensed. Built around mridangam and konnakol practice, but the underlying method works for any single-line percussive recording.

What's next