59 lines
1.9 KiB
Python
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")
|