Como faço uma “tela em branco” da máquina por um período de tempo (como penalidade) se determinados níveis de ruído forem atingidos?

1534

Meus filhos (4 e 5) gritam muito quando jogam no computador. Eu encontrei uma cura eficaz para isso. Quando ouço ruídos altos, eu ssh no computador do jogo e faço:

chvt 3;  sleep 15;  chvt 7 

Isso desligará a tela por 15 segundos no Linux. Eu disse a eles que o computador não gosta de ruídos altos. Eles acreditam totalmente nisso e imploram perdão ao computador. Eles se tornaram muito mais silenciosos, mas não no nível que eu seria feliz, e por isso preciso continuar esse processo educacional. No entanto, nem sempre estou por perto para fazer isso manualmente.

É possível automatizar isso? Um microfone é anexado à caixa. Se o nível de volume ultrapassar algum limite, então eu quero executar um comando.

    
por Leonid Volnitsky 01.02.2013 / 18:14

6 respostas

640

Use sox de SoX para analisar uma pequena amostra de áudio:

sox -t .wav "|arecord -d 2" -n stat

Com -t .wav especificamos que processamos o tipo de wav, "|arecord -d 2" executa o programa arecord por dois segundos, -n envia para o arquivo nulo e com stat especificamos que queremos estatísticas.

A saída deste comando, no meu sistema com algum discurso de fundo, é:

Recording WAVE 'stdin' : Unsigned 8 bit, Rate 8000 Hz, Mono
Samples read:             16000
Length (seconds):      2.000000
Scaled by:         2147483647.0
Maximum amplitude:     0.312500
Minimum amplitude:    -0.421875
Midline amplitude:    -0.054688
Mean    norm:          0.046831
Mean    amplitude:    -0.000044
RMS     amplitude:     0.068383
Maximum delta:         0.414063
Minimum delta:         0.000000
Mean    delta:         0.021912
RMS     delta:         0.036752
Rough   frequency:          684
Volume adjustment:        2.370

A amplitude máxima pode então ser extraída via:

grep -e "RMS.*amplitude" | tr -d ' ' | cut -d ':' -f 2

Nós grep para a linha que queremos, use tr para aparar os caracteres de espaço e, em seguida, cut pelo caractere : e pegue a segunda parte que nos dá 0.068383 neste exemplo. Como sugerido pelos comentários, RMS é uma melhor medida de energia do que a amplitude máxima.

Finalmente, você pode usar bc no resultado para comparar os valores de ponto flutuante na linha de comando:

if (( $(echo "$value > $threshold" | bc -l) )) ; # ... 

Se você criar um loop (consulte Exemplos de Bash ) que chama dormir por 1 minuto, testa o volume e repete, você pode deixá-lo rodando em segundo plano. O último passo é adicioná-lo aos scripts de inicialização ou arquivos de serviço (dependendo do sistema operacional / distribuição), de tal forma que você nem precise ativá-lo manualmente.

    
por 01.02.2013 / 18:36
128

Veja como isso pode ser feito com Dados puros :

Metro é um metrônomo e "metro 100" continua batendo a cada 100 ms.

O áudio vem de adc ~, o volume é calculado por env ~. "pd dsp 0" desliga o DSP quando bateu, "pd dsp 1" o liga. "shell" executa o comando passado em um shell, eu uso o Linux xrandr API para definir o brilho para o X, você precisa adaptar isso para Wayland.

Como você pode ver, o período de tolerância e o bloqueio ocupam muito mais espaço do que o código de áudio.

Fazer uma solução com buffers de anel e / ou médias móveis deve ser muito mais fácil do que fazê-lo com sox . Então eu não acho uma má idéia usar o Pure Data para isso. Mas a tela em si e o bloqueio não se encaixam no paradigma do fluxo de dados.

O arquivo PD está em gist.github.com: ysangkok - kidsyell.pd .

    
por 05.02.2013 / 17:20
101

Verifique "Como detectar a presença de som / áudio" por Thomer M. Gil .

Basicamente, ele grava o som a cada 5 segundos, do que verifica a amplitude do som, usando sox , e decide se aciona um script ou não. Eu acho que você pode facilmente adaptar o script ruby para seus filhos! Ou você pode optar por hackar o script Python (usando PyAudio) que ele forneceu também.

    
por 01.02.2013 / 18:32
52

Você pode obter informações do microfone fazendo algo como:

arecord -d1 /dev/null -vvv

Você pode ter que brincar um pouco com as configurações, como:

arecord -d1 -Dhw:0 -c2 -fS16_LE /dev/null -vvv

A partir daí, é simples analisar a saída.

    
por 01.02.2013 / 18:28
43

Esta é uma das perguntas mais divertidas que eu já vi. Gostaria de agradecer tucuxi  para uma resposta tão boa; que eu defini como um script bash

#!/bin/bash

threshold=0.001
# we should check that sox and arecord are installed
if [ $1 ]; then threshold=$1; fi
while [ 1 -gt 0 ]; do
 if(( $(echo "$(sox -t .wav '|arecord -d 2' -n stat 2>&1|grep -e 'RMS.*amplitude'|tr -d ' '|cut -d ':' -f 2 ) > $threshold"|bc -l) ))
 then
  chvt 3; sleep 5; chvt 7;
 fi
done
    
por 08.02.2013 / 15:10
41

Meus 2 centavos para a solução C ou C ++: talvez não seja a abordagem mais eficaz, mas no Linux, você pode usar a API da ALSA (biblioteca interna de manipulação de áudio do Linux) e use alguma técnica numérica (por exemplo, calculando o nível médio de som a cada segundo) para obter o nível de ruído.

Então você pode verificá-lo em um loop infinito, e se for maior que um treshold pré-definido, você pode usar o X11 biblioteca para desligar a tela por alguns segundos, ou alternativamente (menos elegante, mas funciona) invocar o comando chvt usando system("chvt 3; sleep 15; chvt 7 "); .

    
por 01.02.2013 / 18:32