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

Come faccio a rendere una macchina "schermo vuoto" per un periodo di tempo (come penalità) se si raggiungono certi livelli di rumore?

I miei figli (4 e 5) urlano molto quando giocano al computer. Ho trovato una cura efficace per questo. Quando sento dei rumori forti, mi collego al computer di gioco e faccio:

chvt 3; sleep 15; chvt 7

Questo spegnerà lo schermo per 15 secondi su Linux. Ho detto loro che il computer non ama i rumori forti. Loro ci credono completamente e implorano il computer di perdonarli. Sono diventati molto più silenziosi, ma non al livello in cui io sarei felice, e quindi ho bisogno di continuare questo processo educativo. Tuttavia, non sono sempre in giro per fare questo manualmente.

È possibile automatizzare questo? Un microfono è attaccato alla scatola. Se il livello di volume supera una certa soglia, allora voglio eseguire un comando.

Risposte (6)

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

Usa sox da * SoX ** per analizzare un breve campione audio:

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

Con -t .wav specifichiamo di elaborare il tipo wav, "|arecord -d 2" esegue il programma arecord per due secondi, -n esce nel file null e con stat specifichiamo di volere le statistiche.

L'output di questo comando, sul mio sistema con un po’ di rumore di fondo, è:

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

L'ampiezza massima può essere estratta tramite:

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

Noi grep per la linea che vogliamo, usiamo tr per tagliare via i caratteri di spazio e poi cut per il carattere : e prendiamo la seconda parte che ci dà 0.068383 in questo esempio. Come suggerito dai commenti, RMS è una migliore misura dell'energia rispetto alla massima ampiezza.

Puoi infine usare bc sul risultato per confrontare valori in virgola mobile dalla riga di comando:

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

Se costruisci un ciclo (vedi Bash examples ) che chiama sleep per 1 minuto, testa il volume, e poi ripete, puoi lasciarlo in esecuzione in background. L'ultimo passo è aggiungerlo agli script di init o ai file di servizio (a seconda del vostro sistema operativo/distro), in modo da non doverlo nemmeno lanciare manualmente.

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

Ecco come può essere fatto con Pure Data :

Metro è un metronomo, e “metro 100” continua a battere ogni 100 ms.

L'audio proviene da adc~, il volume è calcolato da env~. “pd dsp 0” spegne il DSP quando batte, “pd dsp 1” lo accende. “shell” esegue il comando passato in una shell, io uso l'API xrandr di Linux per impostare la luminosità su X, dovete adattarlo per Wayland.

Come potete vedere, il periodo di grazia e il blocco occupano molto più spazio del codice audio.

Fare una soluzione con ring buffer e/o medie mobili dovrebbe essere molto più facile che farlo con sox. Quindi non penso che sia una cattiva idea usare Pure Data per questo. Ma lo stesso blanking dello schermo e il bloccaggio non si adattano al paradigma del flusso di dati.

Il file PD è a gist.github.com: ysangkok - kidsyell.pd .

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

Controlla “Come rilevare la presenza di suono/audio” di Thomer M. Gil .

Fondamentalmente registra il suono ogni 5 secondi, poi controlla l'ampiezza del suono, usando sox, e decide se attivare o meno uno script. Penso che tu possa facilmente adattare lo script ruby per i tuoi bambini! Oppure potete scegliere di lavorare sullo script Python (usando PyAudio) che ha fornito anche lui.

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

Potete ottenere informazioni dal microfono facendo qualcosa come:

arecord -d1 /dev/null -vvv

Potreste dover giocare un po’ con le impostazioni, come:

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

Da lì in poi, è una semplice questione di analizzare l'output.

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

Questa è una delle domande più divertenti che ho visto. Vorrei ringraziare tucuxi per una risposta così bella; che ho impostato come 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
42
42
42
2013-02-01 17:32:58 +0000

I miei 2 centesimi per la soluzione C o C++: forse non è l'approccio più efficace, ma su Linux, si può usare la ALSA API (libreria di gestione audio integrata di Linux) e usare qualche tecnica numerica (per esempio, calcolando il livello sonoro medio ogni secondo) per ottenere il livello di rumore.

Poi si può controllare in un ciclo infinito, e se è maggiore di una soglia prestabilita, si può usare la libreria X11 per spegnere lo schermo per alcuni secondi, o in alternativa (meno elegante, ma funziona) invocare il comando chvt usando system("chvt 3; sleep 15; chvt 7 ");.