Marcus/Voice/builtin_mic.py

59 lines
1.9 KiB
Python

"""
builtin_mic.py — backward-compat shim.
The G1 on-board microphone implementation now lives in
[Voice/audio_io.py](Voice/audio_io.py) where it can be paired with the
matching BuiltinSpeaker via `AudioIO.from_profile("builtin", ...)` —
the same structure Sanad uses.
This module exists so existing imports (`from Voice.builtin_mic import
BuiltinMic`) keep working for the non-Gemini voice paths and for
`API/audio_api.py`. It subclasses the canonical `BuiltinMic` and adds
`read_seconds()`, which is used by `API/audio_api.record()`.
Do not add new code here — extend Voice/audio_io.py instead.
"""
from __future__ import annotations
import time
from Voice.audio_io import BuiltinMic as _BaseBuiltinMic
class BuiltinMic(_BaseBuiltinMic):
"""G1 on-board mic + `read_seconds()` convenience."""
def read_seconds(self, seconds: float) -> bytes:
"""Capture `seconds` of audio and return as bytes."""
num_bytes = int(seconds * self.sample_rate * 2)
out = bytearray()
chunk_bytes = 1024
while len(out) < num_bytes:
out.extend(self.read_chunk(min(chunk_bytes, num_bytes - len(out))))
return bytes(out)
# Standalone test — capture 3 s and print energy stats
if __name__ == "__main__":
import array
print("BuiltinMic standalone test — capturing 3 s from G1...")
mic = BuiltinMic()
mic.start()
time.sleep(0.3)
raw = mic.read_seconds(3.0)
mic.stop()
samples = array.array("h", raw)
if not samples:
print(" FAIL — got zero samples")
else:
mn = min(samples); mx = max(samples)
mean_abs = sum(abs(s) for s in samples) / len(samples)
print(f" samples={len(samples)} min={mn} max={mx} mean|s|={mean_abs:.0f}")
if mean_abs > 30:
print(" OK — mic is capturing audio")
else:
print(" WARN — signal very low")