# ================================================================================
# Timing Generator
# Use to manually create a timing array for synchronizing LED brightness to audio dialogue.
# ================================================================================
# Release Version: 2025.1.0
# Initial code generated by Claude Sonnet 4 on 2025-08-10
# ================================================================================
import time
import keyboard
import threading
# Configuration
output_filename = "test.tim" # Output timing file
max_brightness = 255 # Peak brightness for syllables
baseline_brightness = 50 # Baseline brightness between syllables
class TimingRecorder:
def __init__(self):
self.events = []
self.start_time = None
self.recording = False
def countdown_timer(self):
"""Added by Claude: 5-second countdown timer that prints every 0.1 seconds"""
print("\n๐ Starting 5-second countdown...")
for i in range(50, 0, -1): # Added by Claude: Count from 50 to 1 (5.0 to 0.1 seconds)
remaining_time = i / 10.0 # Added by Claude: Convert to decimal seconds
print(f"\rโณ {remaining_time:.1f} seconds remaining...", end='', flush=True) # Added by Claude: Print countdown with carriage return
time.sleep(0.1) # Added by Claude: Wait 0.1 seconds between updates
print("\n๐ฌ GO! Start tapping for syllables!\n") # Added by Claude: Signal that countdown is complete
def start_recording(self):
"""Start timing recording"""
print("=== Audio Timing Recorder ===")
print("Instructions:")
print("1. Press ENTER to start recording")
print("2. Play your audio file")
print("3. Press SPACEBAR, N, or M on each syllable/word") # Modified by Claude: Updated instructions for new trigger keys
print("4. Press ESC when done")
print()
input("Press ENTER to start recording...")
print(f"\n๐ด RECORDING STARTED")
# Added by Claude: Call the countdown timer function BEFORE setting start_time
self.countdown_timer()
# Fixed by Claude: Set start_time AFTER countdown to prevent 5-second offset
self.start_time = time.time()
self.recording = True
print("Play your audio now!")
print("Tap SPACEBAR, N, or M for each syllable") # Modified by Claude: Updated instruction for new trigger keys
print("Press ESC to stop\n")
# Add baseline event at start
self.events.append((0, baseline_brightness))
def add_event(self):
"""Add timing event when spacebar is pressed"""
if not self.recording:
return
current_time = time.time()
elapsed_ms = int((current_time - self.start_time) * 1000)
# Add peak brightness event
self.events.append((elapsed_ms, max_brightness))
print(f"โก Syllable at {elapsed_ms}ms")
# Schedule baseline event 200ms later (adjust this timing as needed)
fade_delay = 200
self.events.append((elapsed_ms + fade_delay, baseline_brightness))
def stop_recording(self):
"""Stop recording and save file"""
if not self.recording:
return
self.recording = False
print(f"\n๐ข RECORDING STOPPED")
# Sort events by timestamp
self.events.sort()
# Save to file
with open(output_filename, 'w') as f:
for timestamp, brightness in self.events:
f.write(f"{timestamp},{brightness}\n")
print(f"๐ Saved {len(self.events)} events to {output_filename}")
self.print_summary()
def print_summary(self):
"""Print recording summary"""
if not self.events:
return
duration = self.events[-1][0] / 1000.0
syllable_count = len([e for e in self.events if e[1] == max_brightness])
print(f"\nRecording Summary:")
print(f"Duration: {duration:.1f} seconds")
print(f"Syllables: {syllable_count}")
print(f"Events: {len(self.events)}")
print(f"\nFile ready for ESP32!")
def main():
recorder = TimingRecorder()
# Start recording
recorder.start_recording()
try:
while recorder.recording:
# Wait for key presses
event = keyboard.read_event()
if event.event_type == keyboard.KEY_DOWN:
if event.name in ['space', 'n', 'm']: # Modified by Claude: Added 'n' and 'm' as trigger keys along with spacebar
recorder.add_event()
elif event.name == 'esc':
recorder.stop_recording()
break
except KeyboardInterrupt:
recorder.stop_recording()
if __name__ == "__main__":
main()