#!/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()