Desktop application for estimating the fundamental frequency (F0) of a speech waveform in the time domain with an autocorrelation-based approach.
Written by Chau Truong Long
- Email: truonglongchau@gmail.com
This project loads a .wav file, splits it into overlapping analysis windows, computes an autocorrelation curve for each window, and estimates the fundamental frequency when a valid periodic structure is detected.
The UI shows:
After median filter: the smoothed pitch contourBefore median filter: the raw pitch contourWave file: the waveform used for analysisWindow Details: a hover preview panel that shows the local waveform window and its autocorrelation response
- Time-domain
F0estimation based on autocorrelation - FFT-based autocorrelation implementation for better performance
- Adjustable:
- window length
- median filter kernel size
- autocorrelation threshold
- Interactive waveform hover preview for local window inspection
- Tkinter desktop UI with Matplotlib plots
The codebase has been refactored into small modules so the application is easier to understand and maintain.
.
├── app
│ ├── analysis
│ │ └── pitch.py
│ ├── services
│ │ ├── audio_loader.py
│ │ ├── pitch_service.py
│ │ ├── results.py
│ │ └── worker_runner.py
│ ├── ui
│ │ ├── main_window.py
│ │ └── preview_panel.py
│ ├── config.py
│ ├── controller.py
│ ├── preview_controller.py
│ └── state.py
├── audio
├── image
├── screenshots
├── tests
└── main.py
main.py- Thin application entrypoint kept at the repository root for easy startup.
app/controller.py- Main application coordinator.
- Wires the window, services, worker runner, and shared state together.
app/preview_controller.py- Handles hover-panel lifecycle, delayed preview rendering, and drag behavior.
app/config.py- Centralized UI strings, theme values, layout constants, and analysis defaults.
app/state.py- Shared state models for audio data, worker state, analysis settings, and hover state.
app/analysis/pitch.py- Signal-processing functions for autocorrelation, peak detection, median filtering, and pitch contour extraction.
app/services/audio_loader.py- Loads and normalizes wave files.
app/services/pitch_service.py- Builds pitch computations and preview-window analysis data.
app/services/results.py- Typed service result models used between background work and the UI thread.
app/services/worker_runner.py- Small helper that manages the single background worker thread.
app/ui/main_window.py- Builds the Tk window, sidebar controls, main graphs, and loader UI.
app/ui/preview_panel.py- Floating in-app preview panel used by waveform hover inspection.
tests/test_pitch_analysis.py- Lightweight unit tests for analysis and service behavior.
- Python 3
tkintermatplotlibnumpyscipy
Run the application from the project root:
python main.pyIf you use a virtual environment:
source .venv/bin/activate
python main.pyIf you use the project virtual environment:
.venv/bin/python -m unittest discover -s tests -p "test_*.py"- Click
Open file. - Select a
.wavfile. - Choose:
Window lengthKernel sizeThreshold
- Click
Pitch contour. - Move the mouse over the waveform plot to inspect local windows in the
Window Detailspanel.
The waveform is processed in overlapping windows. A Hamming window is applied before autocorrelation to reduce edge discontinuities.
The application uses an FFT-based autocorrelation method in normal operation because it is significantly faster than the direct O(n^2) implementation.
A window is accepted as periodic only when:
- a valid local maximum exists in the expected delay range
- the peak is above the configured threshold
- the peak-to-valley difference is strong enough
- the resulting
F0falls inside the supported speech range
The raw pitch contour is post-processed with a median filter to reduce isolated pitch outliers.
This project originally lived in a single large script. It has been refactored to:
- separate signal-processing logic from UI code
- centralize configuration and UI copy
- reduce duplicated logic
- make hover, loader, and worker behavior easier to follow
- keep
main.pysimple and readable






