toes-audio/test-mics.sh
2026-04-17 11:14:45 -07:00

131 lines
2.8 KiB
Bash
Executable File

#!/bin/bash
# Capture a short stereo sample from the barepi mic path and print per-channel stats.
# Usage:
# ./test-mics.sh [seconds] [out.wav]
# ./test-mics.sh --thsel-high [seconds] [out.wav]
# ./test-mics.sh --thsel-low [seconds] [out.wav]
set -euo pipefail
RATE=48000
FORMAT=S32_LE
CHANNELS=2
DURATION=3
OUT=""
THSEL=""
CAPTURE_PCM="${CAPTURE_PCM:-barepi_capture}"
usage() {
cat <<'EOF'
Usage:
./test-mics.sh [seconds] [out.wav]
./test-mics.sh --thsel-high [seconds] [out.wav]
./test-mics.sh --thsel-low [seconds] [out.wav]
EOF
}
set_thsel() {
local level="$1"
command -v pinctrl >/dev/null 2>&1 || return 0
if [ "$level" = "high" ]; then
sudo pinctrl set 8 op pn dh >/dev/null
else
sudo pinctrl set 8 op pn dl >/dev/null
fi
}
prepare_wake_pin() {
command -v pinctrl >/dev/null 2>&1 || return 0
sudo pinctrl set 13 ip pn >/dev/null 2>&1 || true
}
show_pins() {
command -v pinctrl >/dev/null 2>&1 || return 0
sudo pinctrl get 8,13 || true
}
positional=()
while [ $# -gt 0 ]; do
case "$1" in
--thsel-high)
THSEL="high"
shift
;;
--thsel-low)
THSEL="low"
shift
;;
-h|--help)
usage
exit 0
;;
*)
positional+=("$1")
shift
;;
esac
done
if [ ${#positional[@]} -ge 1 ]; then
DURATION="${positional[0]}"
fi
if [ ${#positional[@]} -ge 2 ]; then
OUT="${positional[1]}"
fi
if [ -z "$OUT" ]; then
OUT="/tmp/barepi-mics-$(date +%Y%m%d-%H%M%S).wav"
fi
if ! arecord -L 2>/dev/null | grep -qx 'barepi_capture'; then
CAPTURE_PCM="plughw:CARD=barepiaudio,DEV=0"
fi
if [ -n "$THSEL" ]; then
set_thsel "$THSEL"
fi
prepare_wake_pin
show_pins
echo "Recording ${DURATION}s from ${CAPTURE_PCM} -> ${OUT}"
arecord -q -D "$CAPTURE_PCM" -f "$FORMAT" -c "$CHANNELS" -r "$RATE" -d "$DURATION" "$OUT"
python3 - <<'PY' "$OUT"
import math
import struct
import sys
import wave
path = sys.argv[1]
with wave.open(path, 'rb') as w:
channels = w.getnchannels()
width = w.getsampwidth()
rate = w.getframerate()
frames = w.getnframes()
data = w.readframes(frames)
if channels != 2 or width != 4:
print(f"Recorded {channels}ch / {width * 8}bit at {rate} Hz")
sys.exit(0)
samples = list(struct.iter_unpack('<ii', data))
left = [l for l, _ in samples]
right = [r for _, r in samples]
def rms(xs):
return math.sqrt(sum(x * x for x in xs) / len(xs)) if xs else 0.0
def peak(xs):
return max((abs(x) for x in xs), default=0)
l_rms = rms(left)
r_rms = rms(right)
l_peak = peak(left)
r_peak = peak(right)
full_scale = float(2**31 - 1)
print(f"Saved: {path}")
print(f"Rate: {rate} Hz Frames: {frames}")
print(f"Left : rms={int(l_rms):>10} peak={l_peak:>10} peak_dBFS={20*math.log10(max(l_peak,1)/full_scale):6.1f}")
print(f"Right: rms={int(r_rms):>10} peak={r_peak:>10} peak_dBFS={20*math.log10(max(r_peak,1)/full_scale):6.1f}")
PY