Files
WeAreSyncing/scripts/detect_claps.py
T
ThePendulum ff127a8c21 Add clap detection sensitivity settings (Tools menu)
Threshold and min-interval (the librosa delta/wait knobs) were only
ever tunable via the CLI's -t/-m flags. Added a Clap Detection
Settings dialog (Tools menu) with both as spin boxes, an explicit
Reset to Defaults button, and Cancel that leaves MainWindow's current
settings untouched.

Exposed DEFAULT_THRESHOLD=0.7/DEFAULT_MIN_INTERVAL=0.3 as named
constants in clap_detection.py so the CLI script, DetectWorker's
defaults, and the dialog's reset button all reference the same source
of truth instead of three copies of the same magic numbers that could
drift apart.
2026-07-26 05:56:50 +02:00

80 lines
2.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Detect sharp audio onsets (claps, snaps) in audio/video files.
Outputs timestamps in hh:mm:ss format.
"""
import sys
import argparse
import os
from datetime import timedelta
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from clap_detection import detect_claps, ClapDetectionUnavailable, DEFAULT_THRESHOLD, DEFAULT_MIN_INTERVAL
def format_timestamp(seconds):
"""Convert seconds to hh:mm:ss.mmm format."""
td = timedelta(seconds=seconds)
total_seconds = int(td.total_seconds())
hours = total_seconds // 3600
minutes = (total_seconds % 3600) // 60
secs = td.total_seconds() % 60
return f"{hours:02d}:{minutes:02d}:{secs:06.3f}"
def main():
parser = argparse.ArgumentParser(
description='Detect claps/snaps in audio/video files',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
%(prog)s audio.wav
%(prog)s video.mp4 -t 0.7 -m 1.0
%(prog)s audio.wav -t 0.3 -s # Show onset strengths
Threshold guide:
0.3 = Very sensitive (detects most transients)
0.5 = Moderate (typical claps/snaps)
0.7 = Less sensitive (only loud, sharp claps)
0.9 = Very strict (only very loud events)
"""
)
parser.add_argument('input_file', help='Audio or video file')
parser.add_argument('-t', '--threshold', type=float, default=DEFAULT_THRESHOLD,
help=f'Detection threshold (0-1, default: {DEFAULT_THRESHOLD}, higher = less sensitive)')
parser.add_argument('-m', '--min-interval', type=float, default=DEFAULT_MIN_INTERVAL,
help=f'Minimum seconds between detections (default: {DEFAULT_MIN_INTERVAL})')
parser.add_argument('-s', '--show-strength', action='store_true',
help='Show onset strength values')
args = parser.parse_args()
if not os.path.exists(args.input_file):
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
try:
events = detect_claps(
args.input_file,
threshold=args.threshold,
min_interval=args.min_interval,
)
except ClapDetectionUnavailable as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
print(f"\nFound {len(events)} onset(s):\n", file=sys.stderr)
for event in events:
timestamp = format_timestamp(event.time_sec)
if args.show_strength:
print(f"{timestamp} (strength: {event.strength:.2f})")
else:
print(timestamp)
if __name__ == '__main__':
main()