Skip to main content

Prosodiff

tests

Same words. Different delivery—made visible.

Prosodiff is a small, training-free CLI for comparing two to four recordings of the same speaker saying the same text in different ways. It exports a publication-grade 4:5 figure and a versioned JSON record of explicit delivery-attribute deltas—without predicting emotions or collapsing the comparison into a single score.

Prosodiff synthetic demonstration

Built as a side tool for retrieval-augmented expressive TTS research (ProsodyRAG) at Universität Osnabrück.

Try the complete no-audio demonstration without cloning or installing:

uvx prosodiff demo --output prosodiff-card.png

Or install the command permanently:

pip install prosodiff

What it reports

  • utterance duration;
  • median F0 and robust pitch span (interquartile range in semitones);
  • recorded RMS level and within-take energy dynamics;
  • energy-defined internal pause count, time, and share;
  • pYIN coverage, clipping, level, pitch-boundary, and pause-sensitivity warnings;
  • every unordered pair as an explicit B − A attribute delta.

Prosodiff does not infer emotion, speaking rate, linguistic boundaries, listener response, naturalness, vocal effort, or an overall prosody score.

Local browser interface

Start the private, loopback-only interface:

uv run prosodiff ui

Prosodiff opens a browser page where you can record two to four takes directly from the microphone, replay or redo each take, edit labels, and generate the same 4:5 card and JSON as the CLI. Each take gets a nonblocking level/clipping check before analysis, and the page recommends a redo when the recorded level is below −35 dBFS, clipping is detected, the device changes, or a take differs from the reference by more than 6 dB. Allow microphone access when prompted. Selecting existing WAV files remains available as a secondary option.

Prosodiff local browser interface

The server binds only to 127.0.0.1; it has no telemetry, CDN assets, or external API calls. Live captures are encoded as mono PCM WAVs in the browser. Recordings use random temporary filenames on the server and are deleted immediately after the analysis succeeds or fails. Generated PNG/JSON results are deleted when the server stops. Do not modify the code to expose this development interface on 0.0.0.0 or deploy it publicly.

If a browser does not open automatically, copy the local URL printed in the terminal. Use uv run prosodiff ui --no-open-browser --port 7860 when you want a fixed port.

Fresh-clone quickstart

Requires Python 3.10+ and uv.

Install in one command:

uv sync --extra dev

Generate the complete synthetic demonstration in one command:

uv run prosodiff demo --output docs/prosodiff-card.png

The command creates docs/prosodiff-card.png and docs/prosodiff-card.json. No real audio is committed; the demo signals are deterministic synthetic fixtures and are labelled accordingly in the figure and JSON.

The first run can take roughly one to two minutes while librosa/Numba and Matplotlib build local caches; subsequent short-utterance runs are faster.

Exact usage example

Record the same sentence back-to-back, then run:

uv run prosodiff compare calm.wav encouraging.wav --label Calm --label Encouraging --text "Heute schaffen wir das gemeinsam." --output prosodiff-card.png

This writes prosodiff-card.png plus the adjacent prosodiff-card.json explicit delivery-attribute delta schema. Pass two, three, or four WAV files; repeat --label once per file.

Recording protocol

Recorded-level comparisons are only interpretable when every take uses:

  1. the same speaker and exact text;
  2. the same device, room, microphone direction, gain, and distance;
  3. one back-to-back recording session;
  4. disabled auto-gain, noise suppression, “voice enhancement,” and other automatic processing where possible;
  5. unclipped, unnormalized PCM WAV files.

The tool cannot verify these assumptions. It records them in the JSON and keeps microphone-sensitive measures visibly marked in the figure.

Method

Prosodiff resamples analysis copies to 22.05 kHz but never peak-normalizes, denoises, pre-emphasizes, repairs pitch, or time-warps audio.

  • Pitch: librosa.pyin, 50–600 Hz by default. F0 selection follows pYIN's Viterbi-decoded voiced flag inside the detected utterance and outside pauses; voiced probability is retained as a diagnostic and controls only pale/solid contour emphasis. Summaries require at least 20 decoded frames and 25% eligible-frame coverage. Median F0 is compared on a take-balanced shared semitone reference. Pitch span is the IQR, reducing sensitivity to isolated extremes without silently deleting octave jumps.
  • Recorded energy: time-domain RMS in dBFS. The absolute active-frame median is retained for between-take deltas; contour display is relative to the pooled take median. This is recorded level—not calibrated SPL, loudness, intensity, or vocal effort.
  • Energy-defined pauses: an adaptive RMS threshold followed by removal of sub-50 ms energy islands and filling of sub-150 ms gaps. Internal gaps use a nominal 150 ms cutoff with one-hop (11.6 ms) boundary quantization. The detector repeats at ±3 dB and warns when the result changes materially.
  • Time: contours use raw seconds from the detected utterance onset. They are explicitly not phonetic alignment. Normalized coordinates are stored in JSON only as a coarse linear-time view and must not be treated as phone correspondence.

All calculations are descriptive. A difference between two recordings is not evidence that listeners perceived a different intention.

JSON contract

The machine-readable output uses schema prosodiff.explicit-delivery-attribute-delta, version 0.2.0. It contains:

  • fixed analysis parameters and assumptions;
  • input metadata, utterance spans, pitch/energy/pause attributes, and quality warnings;
  • auditable raw-time and normalized-time contours, including candidate F0, decoded voiced flags, eligibility masks, and probability diagnostics, with unavailable values encoded as JSON null;
  • all unordered input pairs in order, always identified as b_minus_a;
  • pair-level reliability fields and confound warnings.

The schema is intentionally multidimensional. There is no aggregate “expressivity” or quality score.

Honest approximations

  • The live recorder first requests disabled echo cancellation, noise suppression, and auto-gain as exact constraints, then falls back when a browser cannot satisfy them. Reported track settings and privacy-preserving capture provenance are stored in JSON, but the browser, operating system, or audio device can still omit or misreport settings; use the WAV upload route for tightly controlled recording chains.
  • pYIN probabilities are an engineering confidence signal, not calibrated certainty; tracker errors can remain.
  • Energy measurements are dominated by recording chain changes if the protocol is not controlled.
  • Energy-defined gaps are not syntactic, pragmatic, or linguistic pause labels.
  • Same-speaker and same-text assumptions are supplied by the user and are not verified.
  • Short-utterance acoustic deltas do not establish population effects or listener cognition.

Development

Run the synthetic test suite:

uv run pytest

The tests generate audio inside temporary directories. No recordings or research datasets are stored in the repository.

Roadmap

  1. Add optional transcript-aware phone alignment while retaining raw-time views.
  2. Add batch manifests for ProsodyRAG reference-versus-synthesis evaluation and Flowent tutor-voice QA.
  3. Validate acoustic deltas against preregistered listener judgments rather than assuming perceptual relevance.

Author and license

Created by Abdalla Sera (asera-1). Released under the MIT License.

Prosodiff’s authored source is MIT-licensed. Installed dependencies retain their own licenses; the locked librosa audio stack includes dynamically used or installed LGPL components such as libsndfile and python-soxr. They are not vendored or redistributed by this repository.

Metadata

Release files for prosodiff 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for prosodiff 0.2.0
File Size Uploaded
prosodiff-0.2.0.tar.gz 846.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for prosodiff 0.2.0
File Interpreter ABI Platform
prosodiff-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 900.4 kB

Release files / prosodiff-0.2.0.tar.gz

Download URL prosodiff-0.2.0.tar.gz
Size 846.6 kB
Tags Source
SHA-256 checksum
How to use checksums
e1e9682595fed93feddb1b09474e1f131dd519e57553845f6d1e062af3056dde
BLAKE2b-256 checksum
How to use checksums
0057205ab6697122190e2b2b19da483c33d4f384f7cb4e131967d103f4665e67
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.2

Release files / prosodiff-0.2.0-py3-none-any.whl

Download URL prosodiff-0.2.0-py3-none-any.whl
Size 53.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ec774658bcbf993da2773f933fa2e57c7193d2ba1849d2148a54ab39ae1f2433
BLAKE2b-256 checksum
How to use checksums
bea08a47fe9001309129f89f05ad4e72bdad4229b039f223d02042d0eb847954
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.6.2

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page