2013-02-01 17:14:09 +0000 2013-02-01 17:14:09 +0000
1554
1554

Como fazer uma máquina "ecrã em branco" durante um período de tempo (como penalização) se forem atingidos determinados níveis de ruído?

Os meus filhos (4 e 5) gritam muito quando jogam jogos no computador. Encontrei uma cura eficaz para isto. Quando ouço barulhos altos, meto-me no computador do jogo e faço:

chvt 3; sleep 15; chvt 7

Isto irá desligar o ecrã durante 15 segundos no Linux. Eu disse-lhes que o computador não gosta de ruídos altos. Eles acreditam totalmente nisto e imploram ao computador por perdão. Tornaram-se muito mais silenciosos, mas não ao nível que eu ficaria feliz, e por isso preciso de continuar este processo educacional. No entanto, nem sempre estou por perto para fazer isto manualmente.

É possível automatizar isto? Um microfone é anexado à caixa. Se o nível de ruído passar algum limiar, então quero executar um comando.

Respostas (6)

647
647
647
2013-02-01 17:36:38 +0000

Usar 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 wav, "|arecord -d 2" executa o programa arecord durante dois segundos, -n produz para o ficheiro 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, usamos tr para aparar os caracteres do espaço e depois cut pelo caracter : e pegamos na 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.

Pode finalmente usar bc no resultado para comparar valores de ponto flutuante da linha de comando:

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

Se construir um loop (ver Exemplos de Bash ) que chama sleep durante 1 minuto, testa o volume, e depois repete, pode deixá-lo a correr em segundo plano. O último passo é adicioná-lo aos scripts de inicialização ou ficheiros de serviço (dependendo do seu SO / distro), de modo a não ter sequer de o lançar manualmente.

133
133
133
2013-02-05 16:20:11 +0000

Eis como pode ser feito com Pure Data :

Metro é um metrónomo, e “metro 100” continua a bater 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” liga-o. “shell” executa o comando passado numa shell, eu uso a API xrandr do Linux para definir o brilho para X, é necessário adaptar isto para Wayland.

Como pode ver, o período de graça e o bloqueio ocupa 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. Por isso, não acho que seja má ideia usar Dados Puros para isto. Mas o próprio ecrã a apagar-se e o bloqueio não se enquadra no paradigma do fluxo de dados.

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

104
104
104
2013-02-01 17:32:18 +0000

Verificar “Como detectar a presença de som/áudio” de Thomer M. Gil .

Basicamente, grava o som a cada 5 segundos, do que verifica a amplitude do som, usando sox, e decide se dispara ou não um guião. Penso que pode facilmente adaptar o guião ruby para os seus filhos! Ou pode optar por piratear o guião Python (usando PyAudio) que ele também forneceu.

54
54
54
2013-02-01 17:28:44 +0000

Pode obter informações do microfone fazendo algo do género:

arecord -d1 /dev/null -vvv

Poderá ter de brincar um pouco com as configurações, como por exemplo

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

A partir daí, é uma simples questão de analisar a saída.

46
46
46
2013-02-08 14:10:44 +0000

Esta é uma das perguntas mais divertidas que já vi. Gostaria de agradecer tucuxi por uma resposta tão boa; que defini como um guião 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
42
42
42
2013-02-01 17:32:58 +0000

Os meus 2 cêntimos para a solução C ou C++: talvez não seja a abordagem mais eficaz, mas no Linux, pode usar a ALSA API (biblioteca de tratamento de áudio integrada do Linux) e usar alguma técnica numérica (por exemplo, calcular o nível sonoro médio a cada segundo) para obter o nível de ruído.

Depois pode verificá-lo num loop infinito, e se for maior que um limiar predefinido, pode usar a X11 library para desligar o ecrã durante alguns segundos, ou alternativamente (menos elegante, mas funciona) invocar o comando chvt usando system("chvt 3; sleep 15; chvt 7 ");.