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

¿Cómo puedo hacer que una máquina se quede con la pantalla en blanco durante un periodo de tiempo (a modo de penalización) si se alcanzan ciertos niveles de ruido?

Mis hijos (4 y 5 años) gritan mucho cuando juegan en el ordenador. He encontrado un remedio eficaz para esto. Cuando oigo ruidos fuertes, me meto en el ordenador del juego y hago

chvt 3; sleep 15; chvt 7

Esto apagará la pantalla durante 15 segundos en Linux. Les he dicho que al ordenador no le gustan los ruidos fuertes. Se lo creen totalmente y le piden perdón al ordenador. Se volvieron mucho más silenciosos, pero no al nivel que yo estaría feliz, y por eso necesito continuar este proceso educativo. Sin embargo, no siempre estoy cerca para hacerlo manualmente.

¿Es posible automatizar esto? Se conecta un micrófono a la caja. Si el nivel de sonoridad supera algún umbral, quiero ejecutar un comando.

Respuestas [6]

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

Utilice sox de * SoX ** para analizar una muestra corta de audio:

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

Con -t .wav especificamos que procesamos el tipo wav, "|arecord -d 2" ejecuta el programa arecord durante dos segundos, -n sale al archivo null y con stat especificamos que queremos estadísticas.

La salida de este comando, en mi sistema con algo de discurso de fondo, es:

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

La amplitud máxima se puede extraer entonces mediante:

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

Tomamos grep para la línea que queremos, usamos tr para recortar los caracteres de espacio y luego cut por el carácter : y tomamos la segunda parte que nos da 0.068383 en este ejemplo. Como sugieren los comentarios, RMS es una mejor medida de la energía que la amplitud máxima.

Finalmente puede usar bc en el resultado para comparar valores de punto flotante desde la línea de comandos:

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

Si construye un bucle (vea Bash examples ) que llame a sleep durante 1 minuto, pruebe el volumen y luego lo repita, puede dejarlo funcionando en segundo plano. El último paso es añadirlo a los scripts de init o a los archivos de servicio (dependiendo de tu sistema operativo / distro), de forma que ni siquiera tengas que lanzarlo manualmente.

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

Así es como se puede hacer con Pure Data :

Kid yell prevention using Pure Data Metro es un metrónomo, y "metro 100" sigue sonando cada 100 ms.

El audio viene de adc~, el volumen es calculado por env~. "pd dsp 0" apaga el DSP cuando se golpea, "pd dsp 1" lo enciende. "shell" ejecuta el comando pasado en una shell, yo uso la API xrandr de Linux para poner el brillo en X, tienes que adaptar esto para Wayland.

Como puedes ver, el periodo de gracia y el bloqueo ocupan mucho más espacio que el código de audio.

Hacer una solución con ring buffers y/o medias móviles debería ser mucho más fácil que hacerlo con sox. Así que no creo que sea una mala idea usar Pure Data para esto. Pero el propio blanqueo de la pantalla y el bloqueo no encajan con el paradigma del flujo de datos.

El archivo PD está en gist.github.com: ysangkok - kidsyell.pd .

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

Revise "Cómo detectar la presencia de sonido/audio" por Thomer M. Gil .

Básicamente graba el sonido cada 5 segundos, luego comprueba la amplitud del sonido, usando sox, y decide si dispara un script o no. Creo que puedes adaptar fácilmente el script ruby para tus hijos. O puedes optar por hackear el script de Python (usando PyAudio) que él ha proporcionado también.

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

Puedes obtener información del micrófono haciendo algo como

arecord -d1 /dev/null -vvv

Puede que tengas que jugar un poco con los ajustes, como por ejemplo

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

A partir de ahí, es una simple cuestión de analizar la salida.

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

Esta es una de las preguntas más divertidas que he visto. Me gustaría agradecer a tucuxi por tan buena respuesta; que he puesto como 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
46
42
2013-02-01 17:32:58 +0000

Mis dos centavos para la solución en C o C++: tal vez no sea el enfoque más efectivo, pero en Linux, puedes usar la API ALSA (biblioteca de manejo de audio incorporada en Linux) y usar alguna técnica numérica (por ejemplo, calcular el nivel de sonido promedio cada segundo) para obtener el nivel de ruido.

Luego puedes comprobarlo en un bucle infinito, y si es mayor que un umbral preestablecido, puedes usar la biblioteca X11 para apagar la pantalla durante algunos segundos, o alternativamente (menos elegante, pero funciona) invocar el comando chvt usando system("chvt 3; sleep 15; chvt 7 ");.

42