Very is a remote-first company. Our team is spread across the country, and so are our clients — which means everyone spends a good part of their days on conference calls or pair-programming sessions.
Proper etiquette keeps us sane. We all use headsets or external microphones, but we’re also big advocates of the mute button — because background noise can be incredibly noisy. For push-to-talk or push-to-mute functionality, most of us prefer to use Shush.
Shush is an amazing tool for our team, but it doesn’t come with a crystal ball, and it doesn’t work on toddlers. If you’ve ever been on the phone when your kid throws a(nother) tantrum, you know that it’s impossible to predict exactly when you’ll need to mute. Most of the time, you just can’t hit that button fast enough.
The mute-worthy cross that I bear is my dog, Darcy. She hates anyone who walks near our house — which is great because I don’t need an alarm system. But it’s also not great because I need to hear and be heard on my calls. Recently, during one of her spirited sessions, I thought, There has to be a better way. (Spoiler alert: there was.)
The Big Picture
Using a cheap microphone and an Arduino that I had lying around, I realized I should be able to detect loud noises and send the mute key to my computer automatically via Arduino's keyboard emulation capabilities.
Signal Processing FTW
In my past life, I was a Control Systems Engineer, where I learned signal processing techniques before Data Science was cool. Most microphones send an analog signal which must be sampled at a given rate and then processed to extract the features necessary to make control decisions. Luckily for us, we simply want to extract the peak-to-peak amplitude over a given time period, which represents the intensity of the audio signal.
const int sampleWindow = 50; // Sample window width in mS (50 mS = 20Hz)
unsigned long startMillis= millis(); // Start of sample window
unsigned int peakToPeak = 0; // peak-to-peak level
unsigned int signalMax = 0;
unsigned int signalMin = 1024;
// collect data for 50 mS
while (millis() - startMillis < sampleWindow)
sample = analogRead(0);
if (sample < 1024) // toss out spurious readings
if (sample > signalMax)
signalMax = sample; // save just the max levels
else if (sample < signalMin)
signalMin = sample; // save just the min levels
peakToPeak = signalMax - signalMin; // max - min = peak-peak amplitude
The code sample above shows how simple it is to calculate the peak-to-peak amplitude from an analog signal. Of course, when sampling, we always have to be aware of missing peaks due to aliasing — but in practice, with these audio signals, it doesn't seem to be an issue.
For the current implementation of AutoShusher, I simply send the mute key every time the peak-to-peak amplitude exceeds a hard-coded threshold. It seems to work fairly well in practice, but I’m definitely interested in improving it over time.
Wrapping Things Up
The projects that live outside my server closet require a high "wife acceptance factor." I've learned (the hard way) that this means two things: it has to work well, and it can't look like an elementary school arts and crafts project. So I took the time to design a decent-looking case in Fusion360 and print it on my 3D printer.
Getting Your Hands on One
Head on over to the github repo for more detailed instructions, including the CAD files. Don't forget that this is a living work in progress, so things aren't perfect yet. My future plans include:
- Improving the muting algorithm.
- Adding a command line configuration tool (so you don't have to hard-code functionality.)
If you use it and think it sucks, that's okay — feel free to submit a PR. I spent longer writing this post than I did making the AutoShusher ¯_(ツ)_/¯, and it won't be long until I've saved more time holding down my mute button than I've spent working on the project. (That’s some pretty sweet ROI.)