Add binaural recording + tune spatial tracking
binaural_recorder.py: Records left/right ear streams as stereo WAV in rolling 5-minute segments. Training data for spatial audio models. Enabled via BINAURAL_RECORD=1 env var. spatial.py: Tune smoothing — alpha 0.3→0.4 (snappier response), idle return speed 0.05→0.03 (gentler drift), timeout 2s→1.5s. headmic.py: Wire binaural recorder into audio loop, add /recording endpoint for stats, feed both ear streams (not just best beam). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
33
headmic.py
33
headmic.py
@@ -170,6 +170,9 @@ sound_ring_buffer = None # collections.deque, filled by listener_loop
|
||||
# Speaker recognizer globals
|
||||
speaker_recognizer = None
|
||||
enrollment_buffer = None # list of frame bytes, set during enrollment
|
||||
|
||||
# Binaural recorder
|
||||
binaural_recorder = None
|
||||
enrollment_name = None
|
||||
|
||||
# Audio stream
|
||||
@@ -265,6 +268,13 @@ def listener_loop():
|
||||
|
||||
state.active_side = side
|
||||
|
||||
# Feed binaural recorder (both ears)
|
||||
if binaural_recorder:
|
||||
binaural_recorder.feed(
|
||||
dual_stream.left.get_frame(),
|
||||
dual_stream.right.get_frame() if dual_stream.right else None
|
||||
)
|
||||
|
||||
# Feed sound classifier ring buffer
|
||||
if sound_ring_buffer is not None:
|
||||
sound_ring_buffer.append(frame_data)
|
||||
@@ -454,7 +464,7 @@ app = FastAPI(title="HeadMic", description="Vixy's Ears 🦊👂 (Dual XVF3800)"
|
||||
|
||||
@app.on_event("startup")
|
||||
async def startup():
|
||||
global sound_classifier, sound_ring_buffer, speaker_recognizer, dual_stream, LEDS_AVAILABLE, spatial_tracker
|
||||
global sound_classifier, sound_ring_buffer, speaker_recognizer, dual_stream, LEDS_AVAILABLE, spatial_tracker, binaural_recorder
|
||||
|
||||
state.running = True
|
||||
|
||||
@@ -530,6 +540,15 @@ async def startup():
|
||||
logger.info("Spatial tracking started (%d Hz, %.0fmm baseline, pushing gaze to %s)",
|
||||
DOA_POLL_HZ, array_sep, EYE_SERVICE_URL)
|
||||
|
||||
# --- Binaural recording ---
|
||||
if os.environ.get("BINAURAL_RECORD", "").lower() in ("1", "true", "yes"):
|
||||
from binaural_recorder import BinauralRecorder
|
||||
rec_dir = os.environ.get("BINAURAL_DIR", os.path.expanduser("~/headmic/recordings"))
|
||||
binaural_recorder = BinauralRecorder(output_dir=rec_dir)
|
||||
binaural_recorder.start()
|
||||
else:
|
||||
logger.info("Binaural recording disabled (set BINAURAL_RECORD=1 to enable)")
|
||||
|
||||
# --- Main listener ---
|
||||
thread = threading.Thread(target=listener_loop, daemon=True)
|
||||
thread.start()
|
||||
@@ -540,6 +559,8 @@ async def startup():
|
||||
async def shutdown():
|
||||
state.running = False
|
||||
leds_off()
|
||||
if binaural_recorder:
|
||||
binaural_recorder.stop()
|
||||
if dual_stream:
|
||||
dual_stream.stop()
|
||||
|
||||
@@ -606,6 +627,16 @@ async def doa():
|
||||
}
|
||||
|
||||
|
||||
# --- Binaural recording ---
|
||||
|
||||
@app.get("/recording")
|
||||
async def recording():
|
||||
"""Binaural recording status."""
|
||||
if not binaural_recorder:
|
||||
return {"recording": False, "enabled": False}
|
||||
return binaural_recorder.stats
|
||||
|
||||
|
||||
# --- Device info ---
|
||||
|
||||
@app.get("/devices")
|
||||
|
||||
Reference in New Issue
Block a user