A suite of commands like accelerometer, microphone, bandpass, keyboard-brightness, screen-brightness, and more that can be linked together using UNIX pipes.
All tools input and output a standardized mono audio signal that represents their sensor input/output values.
pip install mac-hardware-toys
### Examples
# flash your screen according to your microphone input
microphone | screen-brightness
# play a sine wave tone based on your screen lid-angle
lid-angle | speaker
# flash the keyboard according to your heartbeat (keep your wrists on palm rests)
accelerometer | metronome | keyboard-brightness
# see more detail about any given signal by piping it into visualizer
microphone | visualizer
sine 1000 | visualizer
gyroscope | tee >(speaker) | visualizer- Purpose: read Apple SPU accelerometer and emit mono signal.
- Args:
--rate <hz>(<= 800),--axis x|y|z|mag,--raw. - Notes: requires root; when run from a terminal it auto-prompts via
sudo.
- Purpose: read ambient light sensor and emit tone mapped from low light to high light.
- Default mapping:
500 Hz -> 5000 Hzand low volume -> high volume as light goes0% -> 100%. - Args:
--rate,--low-hz,--high-hz,--low-volume,--high-volume,--json. - Notes: requires root; when run from a terminal it auto-prompts via
sudo.
- Purpose: read lid angle sensor and emit tone mapped from lid closed to open.
- Default mapping:
500 Hz -> 5000 Hzand low volume -> high volume as angle goes--angle-min -> --angle-max. - Args:
--rate,--low-hz,--high-hz,--low-volume,--high-volume,--angle-min,--angle-max,--json. - Notes: requires root; when run from a terminal it auto-prompts via
sudo.
- Purpose: read fused orientation (accel+gyro, Mahony AHRS) and emit tone mapped from the selected orientation axis.
- Default mapping:
500 Hz -> 5000 Hzand low volume -> high volume as selected axis angle maps to0..360. - Args:
--rate,--low-hz,--high-hz,--low-volume,--high-volume,--json,--axis roll|pitch|yaw,--decimate. - Notes: requires root; when run from a terminal it auto-prompts via
sudo.roll/pitchare absolute to gravity;yawis relative and can drift without magnetometer.
- Purpose: capture mono mic signal and emit stream.
- Args:
--rate <hz>,--block-size <frames>.
- Purpose: emit metronome pulses; with piped stdin it auto-detects/follows BPM.
- Args: optional
bpm,--rate(fixed mode),--pulse-ms,--tone-hz,--level,--accent-every,--accent-gain,--block-size,--count,--min-bpm,--max-bpm,--detect-low-hz,--detect-high-hz,--self-echo-ms,--follow,--debug,--raw.
- Purpose: realtime cascaded high/low-pass filter.
- Args: positional cutoffs or
--low/--high,--chunk-bytes,--raw --rate.
- Purpose: best-effort realtime frequency scaling, takes a scalar multiplier like 0.1~1000.
- Args:
factor,--chunk-bytes,--raw --rate.
- Purpose: scalar amplitude gain.
- Args:
gain,--chunk-bytes,--raw --rate.
- Purpose: emit BPM/confidence JSON lines from incoming signal (typically bandpassed). When piped onward, it passes the signal through on stdout and writes JSON to stderr.
- Args:
--interval,--window-seconds,--emit-final,--chunk-bytes,--raw --rate.
- Purpose: play incoming stream on default output device.
- Args:
--device-rate,--block-size.
- Purpose: terminal waveform + level monitor.
- Args:
--fps,--window-seconds,--chunk-bytes,--raw --rate.
- Purpose: beat-follow keyboard backlight control.
- Args:
--send-hz,--fade-ms,--gain,--attack-ms,--release-ms,--baseline-ms,--decay-per-s,--debug,--as-root,--pulse,--on-time,--off-time,--set. - Notes:
--set=<0..100>without--pulsesets brightness and exits immediately (ignores stdin).--pulse=<N>ignores stdin and pulses N times;--setcontrols pulse max brightness.
- Purpose: beat-follow display brightness control.
- Args:
--send-hz,--min-level,--max-level,--gain,--attack-ms,--release-ms,--baseline-ms,--decay-per-s,--debug,--no-restore,--pulse,--on-time,--off-time,--set. - Notes:
--set=<0..100>without--pulsesets display brightness and exits immediately (ignores stdin).--pulse=<N>ignores stdin and pulses N times;--setcontrols pulse max brightness.
- Purpose: signal-follow fan RPM control (both fans in sync by default; beat-alternating optional).
- Args:
--send-hz,--min-rpm,--max-rpm,--min-frac,--max-frac,--pulse-depth,--couple,--alternate,--input-map,--beat-threshold,--beat-hold-ms,--gain,--attack-ms,--release-ms,--baseline-ms,--decay-per-s,--debug,--no-restore.
Heartbeat from accelerometer:
accelerometer | bandpass 0.8 3 | heartbeatAmbient light as signal source:
ambient-light | visualizerLid angle as JSONL:
lid-angle --jsonGyroscope fused orientation as JSONL:
gyroscope --axis roll --jsonMusic-reactive keyboard + speakers:
microphone --rate 44100 \
| tee >(keyboard-brightness --send-hz 30 --fade-ms 20) \
| volume-shift 0.8 \
| speakerMetronome to speakers:
metronome 120 | speakerAuto-follow metronome from mic input, emits a metronome tone in sync with the beat of whatever audio is playing:
microphone | metronome | speakerAuto-follow metronome from accelerometer, driving keyboard pulses:
accelerometer | metronome | keyboard-brightnessMetronome driving keyboard pulses:
metronome 120 | keyboard-brightnessHeartbeat telemetry while still driving keyboard brightness:
accelerometer | heartbeat | keyboard-brightnessSet keyboard backlight to 100% and exit:
keyboard-brightness --set=100Pulse keyboard 5 times (1.2s on / 5.5s off) at 100%:
keyboard-brightness --pulse=5 --on-time=1.2 --off-time=5.5 --set=100Set screen brightness to 40% and exit:
screen-brightness --set=40Pulse screen brightness 3 times:
screen-brightness --pulse=3 --on-time=1.2 --off-time=5.5 --set=100Metronome driving fan pulses:
metronome 120 | fan-speed --send-hz 4 --alternate --input-map beat --min-frac 0.30 --max-frac 0.70Slow sine fan sweep (sync L/R):
sine 0.1 | fan-speedOne source, multiple sinks:
accelerometer \
| bandpass 0.8 3 \
| tee >(keyboard-brightness) \
| frequency-shift 1000 \
| volume-shift 0.8 \
| tee >(speaker) \
| visualizeraccelerometerrequires root (AppleSPU HID access) and will auto-reexec throughsudoby default.ambient-light,lid-angle, andgyroscopedo the same for AppleSPU HID access.- Set
MSIG_AUTO_SUDO=0to disable auto-reexec and only print rerun guidance on stderr. microphone/speakerdepend onsounddevice+ PortAudio runtime.- Keyboard/display brightness tools need supported hardware/permissions.
keyboard-brightnessuses the bundled Apple Silicon KBPulse binary atlib/KBPulse(arm64).fan-speeduses AppleSMC private IOKit APIs on Apple Silicon; writing fan targets typically requiressudo.frequency-shiftis intentionally lightweight and artifact-prone at extreme factors.
git clone https://github.com/pirate/mac-hardware-toys
cd mac-hardware-toys
uv sync
source .venv/bin/activateAll stream tools read/write:
- header:
MSIG1 <sample_rate_hz>\n - payload: little-endian
float32mono samples
Most processors also support raw float32 input via --raw --rate <hz>.
It's fun. Here are some ideas to get started:
- make your keyboard lights flash for security alerts using Security Growler
- make your keyboard flash right before your display is about to sleep
- make your keyboard flash on incoming email
- make your keyboard flash to the beat of music
- make your keyboard flash when your boss's iPhone comes within bluetooth range
- https://github.com/olvvier/apple-silicon-accelerometer IOReg accelerometer reading code
- https://github.com/EthanRDoesMC/KBPulse/ keyboard brightness code for M1, M2, M3, etc. macs
- https://github.com/maxmouchet/LightKit
- https://github.com/tcr/macbook-brightness
- http://stackoverflow.com/questions/3239749/programmatically-change-mac-display-brightness
- https://web.archive.org/web/20110828210316/http://mattdanger.net:80/2008/12/adjust-mac-os-x-display-brightness-from-the-terminal/
- http://osxbook.com/book/bonus/chapter10/light/
- https://github.com/samnung/maclight/blob/master/lights_handle.cpp
- http://www.keindesign.de/stefan/Web/Sites/iWeb/Site/iSpazz.html the OG
- https://github.com/bhoeting/DiscoKeyboard

