Monitoring the microphone level with a command line tool in Linux

17

6

I am looking for a tool that will tell me, in less than half a second, if the microphone is picking up any sound above a certain threshold. (I plan to then mute the Master channel with another command line tool, like amixer.)

Christian Neverdal

Posted 2011-07-05T20:14:03.463

Reputation: 612

Answers

8

This solution will avoid writing repeatedly to disk, and even though it in worst case takes a second instead of the desired less than half a second, I found it to be fast enough after trying it. So, here are the two scripts I use:

./detect:

while true; do
    arecord -d 1 /dev/shm/tmp_rec.wav ; sox -t .wav /dev/shm/tmp_rec.wav -n stat 2>\
    &1 | grep "Maximum amplitude" | cut -d ':' -f 2 | ./check.py
    if [ $? -eq 0 ] ; then
         amixer set Master 0
    else
         amixer set Master 80
    fi
done

./check.py:

#!/usr/bin/env python
import sys

number = 0.0
thing="NO"

line = sys.stdin.readline()
thing = line.strip()
number = float(thing)

if number < 0.15:
    raise Exception,"Below threshold"

Hardly elegant, but it works.

Note: If you want a more gradual thing, add something like this:

   for i in `seq 0 80 | tac`; do
      amixer set Master $i
   done

for muting and

   for i in `seq 0 80`; do
      amixer set Master $i
   done

for unmuting.

Christian Neverdal

Posted 2011-07-05T20:14:03.463

Reputation: 612

1

Python is a bit overkill, http://math-blog.com/2012/07/23/floating-point-arithmetic-in-the-bourne-again-shell-bash/ result=$(AUDIODEV=hw:1 rec -n stat trim 0 .5 2>&1 | grep "Maximum amplitude" | grep -o "[0-9].[0-9]*$"); echo "$result > 0.01" | bc

– kevinf – 2016-06-15T05:55:52.340

1Just keep in mind that 'Maximum amplitude' isn't the only indicator of a loud sound. A sound with a high frequency (e.g. clinking of glasses) may be perceived as really loud by human ears but the sox' 'Maximum amplitude' won't be very different from the lowest one. So in some cases it would make sense to analyze 'Rough frequency' as well. – ka3ak – 2017-05-19T15:05:39.130

7A slightly more elegant solution, which supports half-second resolution and doesn't require a temporary file:

while true; do amixer set Master $(rec -n stat trim 0 .5 2>&1 | awk '/^Maximum amplitude/ { print $3 < .15 ? 80 : 0 }'); done – nandhp – 2012-06-29T13:17:59.717

2

Just version without python script and TALKING_PERIOD, that sets up how many seconds will sound be on DOWN_SOUND_PERC level, then goes to UP_SOUND_PERC level.

#!/bin/bash

TALKING_PERIOD=16
UP_SOUND_PERC=65
DOWN_SOUND_PERC=45
counter=0
while true; do

echo "counter: " $counter

if [ "$counter" -eq 0 ]; then
    nmb=$(arecord -d 1 /dev/shm/tmp_rec.wav ; sox -t .wav /dev/shm/tmp_rec.wav -n stat 2>&1 | grep "Maximum amplitude" | cut -d ':' -f 2)

    echo "nmb: " $nmb

    if (( $(echo "$nmb > 0.3" |bc -l) )); then
        echo "ticho"
        amixer -D pulse sset Master 45%
        counter=$TALKING_PERIOD
    else
        echo "hlasno"
        amixer -D pulse sset Master 65%
    fi
fi

if [[ $counter -gt 0 ]]; then
        ((counter--))
fi

sleep 1

done

R4v0

Posted 2011-07-05T20:14:03.463

Reputation: 21

0

There is a tool called pavumeter that lets you see the microphone level, Open capture interface of pavumeter,

Then adjust the capture sound level using pavucontrol, In pavucontrol, go to input devices, and adjust microphone sensitivity.

Edit: In the bash script by R4v0, done is inside code.

Edit2: I wanted to raise the volume each time there is noise, so i just edited more than to be less than and cancelled talking peroid

    if (( $(echo "$nmb < 0.3" |bc -l) )); then

haytham-med haytham

Posted 2011-07-05T20:14:03.463

Reputation: 17

5"command line tool" – deltaray – 2016-10-26T21:38:01.233

0

I modified bash script to increase volume according to surrounding noise level.

You can change minimum_volume, maximum_volume [value is in percent].

To_Do: increment not tested yet. sox and bc need to be installed.

#!/bin/bash

minimum_volume=20
maximum_volume=60
increment=10

counter=0
while true; do

# echo "counter: " $counter


nmb=$(arecord -d 1 /dev/shm/tmp_rec.wav ; sox -t .wav /dev/shm/tmp_rec.wav -n stat 2>&1 | grep "Maximum amplitude" | cut -d ':' -f 2)
echo "nmb: " $nmb

    if (( $(echo "$nmb <= 0.1" |bc -l) )); then
    amixer -D pulse sset Master $minimum_volume%
    else 
        if (( $(echo "$nmb <= 0.2" |bc -l) )); then
        amixer -D pulse sset Master $(($minimum_volume+ $increment))%
        else
            if (( $(echo "$nmb <= 0.3" |bc -l) )); then
            amixer -D pulse sset Master $(($minimum_volume+ $increment+ $increment))%
                else
                    if (( $(echo "$nmb <= 0.4" |bc -l) & maximum_volume>=40)); then
                    amixer -D pulse sset Master $(($minimum_volume+ $increment+ $increment+ $increment))%
                    else
                        if (( $(echo "$nmb <= 0.5" |bc -l) & maximum_volume>=50)); then
                        amixer -D pulse sset Master $(($minimum_volume+ $increment+ $increment+ $increment+ $increment))%
                        else
                            if (( $(echo "$nmb <= 0.6" |bc -l) & maximum_volume>=60)); then
                            amixer -D pulse sset Master $(($minimum_volume+ $increment+ $increment+ $increment+ $increment+ $increment))%  
                            else
                                if (( $(echo "$nmb <= 0.7" |bc -l) & maximum_volume>=70)); then
                                amixer -D pulse sset Master $(($minimum_volume+ $increment+ $increment+ $increment+ $increment+ $increment+ $increment))%
                                else
                                    if (( $(echo "$nmb <= 0.8" |bc -l) & maximum_volume>=80)); then
                                    amixer -D pulse sset Master $(($minimum_volume+ $increment+ $increment+ $increment+ $increment+ $increment+ $increment+ $increment))%
                                    else
                                        if (( $(echo "$nmb <= 0.9" |bc -l) & maximum_volume>=90)); then
                                        amixer -D pulse sset Master $(($minimum_volume+ $increment+ $increment+ $increment+ $increment+ $increment+ $increment+ $increment+ $increment))%
                                        else
                                            amixer -D pulse sset Master $(($maximum_volume+ $minimum_volume))%
                                        fi
                                    fi
                                fi
                            fi
                        fi
                    fi
                fi
            fi
        fi

sleep 1
done

haytham-med haytham

Posted 2011-07-05T20:14:03.463

Reputation: 17

And set end-of-line in your code editor to unix. – haytham-med haytham – 2019-08-31T09:16:23.480

Could I use this to 1. listen for a noise level, 2. 'fade' in playing an audio file, 3. timeout after x minutes, 4. 'fade' out and stop audio, 5. if noise level met again resume from previous point in said audio file? The fade in fade out functionality isn't as important as the resume portion for me. Would this be easy to implement? I'm trying to figure out how to make an automated white noise generator using bash and standard utilities if possible. I almost made my own post but this seems part way to the solution I'm looking for. – BasicObject – 2019-09-07T16:50:24.237