Zero Crossing Rate — v1.0 User Guide

Frame‑by‑frame analysis of the rate at which the signal crosses zero. High ZCR indicates noisy/unvoiced content; low ZCR indicates voiced/tonal content. Uses Praat’s built‑in PointProcess (zeroes) (C‑level, no per‑sample script loop) for maximum efficiency. Outputs a ZCR time‑series curve, global statistics, voiced/unvoiced segmentation, and optionally exports the ZCR curve as a Sound object for further use.

Author: Shai Cohen Affiliation: Department of Music, Bar‑Ilan University, Israel Version: 1.0 (2025) License: MIT License Repo: GitHub
Contents:

What this does

Zero Crossing Rate (ZCR) measures the number of times the signal changes sign per second. It is a simple but powerful indicator of spectral content:

Efficiency: The script uses Praat’s To PointProcess (zeroes) to detect all zero crossings in one pass (C‑level, no Praat script loop). Then, for each analysis frame, it queries the PointProcess to count crossings within the window using Get high index and Get low index – two O(log n) operations per frame. This is orders of magnitude faster than a per‑sample loop.

Quick start

  1. In Praat, select exactly one Sound object (mono or stereo – stereo will be downmixed to mono for analysis).
  2. Run script…Zero_Crossing_Rate.praat.
  3. Choose an Analysis Preset:
    • Fine (10 ms window, 2.5 ms hop), Standard (20 ms, 5 ms), Speech (30 ms, 10 ms), Coarse (50 ms, 20 ms), Ultra‑Fine (5 ms, 1 ms)
  4. For custom mode (preset = Custom), set:
    • Window_duration_ms – length of each analysis frame.
    • Hop_duration_ms – step between frames.
    • VU_threshold_Hz – threshold above which a frame is considered unvoiced.
  5. Optionally enable Export_ZCR_curve to save the ZCR time series as a Sound object for further analysis.
  6. Click OK. The script analyses zero crossings, computes statistics, and draws a multi‑panel visualisation.
Tip: For speech analysis, start with Speech preset (30 ms window, 10 ms hop). For fine‑grained transient analysis, use Ultra‑Fine (5 ms window, 1 ms hop).
Important: This effect is implemented entirely in Praat – no Python required. The analysis is extremely fast even for long files (10 seconds at 44.1 kHz analysed in <1 s).

The 5 presets (+ Custom)

表表格 PresetWindow (ms)Hop (ms)Frames/sDescription Ultra‑Fine511000Very high temporal resolution, good for transients. Fine102.5400High resolution, suitable for percussion and rapid changes. Standard205200Balanced, general‑purpose. Speech3010100Typical for speech analysis (matches many Praat objects). Coarse502050Smooth envelope, good for long‑term trends. 表格

Analysis method

Algorithm:
  1. Convert to mono (if stereo).
  2. Create PointProcess (zeroes) – finds every sample where the signal crosses zero.
  3. For each frame [t, t+window]:
    • Find the first zero‑crossing index hi at or after t.
    • Find the last zero‑crossing index lo at or before t+window.
    • Number of crossings = lo – hi + 1 (if both exist).
    • ZCR = crossings / frame_duration (Hz).
  4. Compute global statistics (mean, std, min, max, voiced/unvoiced percentage).
  5. Optionally export ZCR time series as a Sound object (sample rate = 1/hop).

Because the PointProcess stores all zero‑crossing times as a sorted array, the per‑frame lookup is O(log n) – extremely efficient. The script avoids any per‑sample Praat loops.

Parameters & defaults

Analysis preset

Select one of the presets (Fine, Standard, Speech, Coarse, Ultra‑Fine) to set window and hop automatically. For custom, use the manual fields below.

Analysis parameters

表表格 ParameterRangeDefaultDescription Window_duration_ms≥ 1 ms20 msDuration of each analysis frame. Hop_duration_ms≤ window5 msStep between consecutive frames. VU_threshold_Hzany positive3000 HzZCR above this is considered unvoiced/noisy. Used for classification and visualisation. 表格

Output

表表格 ParameterDefaultDescription Export_ZCR_curveyesCreates a Sound object named ZCR_originalname with the ZCR time series (1 sample per frame). You can query it with Get value at time.... Draw_visualizationyesDraws input waveform, ZCR curve (colour‑coded by voiced/unvoiced), histogram, statistics panel, and summary. Play_resultnoIf Export_ZCR_curve is enabled, plays the ZCR curve Sound (a very low‑frequency signal – usually not audible). 表格

Visualization (Praat picture)

When Draw_visualization = 1, the script draws a 5‑panel figure:

Tip: The ZCR curve plot clearly shows which regions are voiced (blue, low ZCR) and unvoiced (red, high ZCR). The histogram gives an overview of the overall ZCR distribution.

FAQ / troubleshooting

ZCR values seem very high or very low

ZCR depends on the frequency content. A pure 100 Hz sine wave has 200 zero crossings per second (each period crosses twice). So ZCR ≈ 2 × frequency. For noisy signals, ZCR can be > 20 kHz. If your material is band‑limited, you may see lower values. The threshold for voiced/unvoiced can be adjusted.

The ZCR curve Sound is silent / very low‑frequency

The exported ZCR Sound has a sample rate = 1/hop. For a 10 ms hop, the SR is 100 Hz – far below the audible range. This Sound is intended for further analysis (e.g., using Praat’s query functions), not for listening. The Play_result option is mainly for debugging.

Analysis is slow for very long files

Even with the optimised method, a 10‑minute file at 44.1 kHz produces about 60,000 zero crossings. The per‑frame query is O(log n) and very fast; typical analysis time is still under 1 s per minute of audio. If you experience slowness, increase the hop size (coarser analysis) or reduce the window size.

Why use PointProcess (zeroes) instead of a loop?

Praat’s To PointProcess (zeroes) is implemented in C and scans the entire signal once, creating a list of zero‑crossing times. Then each frame only needs to find the indices of the first and last zero within that window – two binary searches (O(log n) each). This is far more efficient than a Praat script loop over every sample in each frame.

Voiced/unvoiced threshold

The default 3000 Hz is typical for speech, but you can adjust it based on your material. For music, a higher threshold (e.g., 5000 Hz) may be more appropriate. The visualisation shows the threshold line, and the statistics panel updates the voiced/unvoiced percentages.