Come posso rendere una macchina "schermo vuoto" per un periodo di tempo (come penalità) se vengono raggiunti determinati livelli di rumore?


1549

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

chvt 3;  sleep 15;  chvt 7 

Questo spegnerà lo schermo per 15 secondi su Linux. Ho detto loro che al computer non piacciono i rumori forti. Ci credono totalmente e chiedono perdono al computer. Sono diventati molto più silenziosi, ma non al livello in cui sarei felice, e quindi devo continuare questo processo educativo. Tuttavia, non sono sempre pronto a farlo manualmente.

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


3
Fino a quando non impareranno a premere CTRL + ALT + F7
Suici Doga il

1
@SuiciDoga Hey; non sanno cosa sta succedendo!
wizzwizz4,

Complimenti per una soluzione tecnica. Ma penso, è importante dire sempre la verità ai bambini.
Peter

Risposte:


645

Utilizzare soxda SoX per analizzare un breve campione audio:

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

Con -t .wavspecifichiamo elaboriamo il tipo wav, "|arecord -d 2"eseguiamo il arecord programma per due secondi, eseguiamo l' -noutput nel file null e con statspecifichiamo che vogliamo statistiche.

L'output di questo comando, sul mio sistema con alcuni discorsi di sottofondo, è:

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ò quindi essere estratta tramite:

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

Noi grepper la linea che vogliamo, usiamo trper tagliare i caratteri dello spazio e poi cutper il :personaggio e prendere la seconda parte che ci dà 0.068383in questo esempio. Come suggerito dai commenti, RMS è una misura di energia migliore della massima ampiezza.

Puoi infine utilizzare bcil risultato per confrontare i valori in virgola mobile dalla riga di comando:

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

Se crei un loop (vedi esempi Bash ) che chiama sleep per 1 minuto, verifica il volume e quindi si ripete, puoi lasciarlo in esecuzione in background. L'ultimo passaggio è aggiungerlo agli script di init o ai file di servizio (a seconda del sistema operativo / della distribuzione), in modo tale da non dover nemmeno avviarlo manualmente.


282
Consiglio di prendere la massima ampiezza. Non è bello per i bambini quando il loro schermo si oscura solo perché qualcuno ha applaudito o qualcosa di simile. La media sembra più appropriata.
orlp,

34
Solo un chiarimento, per "media" intendi RMS Amplitude giusto? L'ampiezza media sarà prossima a 0 se il rumore ha un volume costante per 2 secondi (le metà positiva e negativa si annulleranno a vicenda).
Luca,

6
Un semplice rivelatore di "energia" per una serie di campioni è semplicemente quello di sommare il valore di tutti i picchi. Non dovresti nemmeno fare una media se non lo volessi. Un picco è qualsiasi punto in cui l' sample[n]>sample[n-1]&&sample[n]>sample[n+1]ho usato come meccanismo rudimentale per misurare l'energia di una canzone e funziona abbastanza bene. Basta cercare un numero magico al quale sei soddisfatto del livello del volume.
Kaslai,

3
Vorrei vedere un esempio di output del tuo primo comando quando si tratta davvero di un bambino che urla, per riferimento.
Alvin Wong,

3
Per l'uso descritto (avvia automaticamente + esegui ogni pochi minuti) un cron job è lo strumento giusto da usare. Molto più semplice da installare e più robusto rispetto all'uso di init script + bash loop + sleep.
m000,

131

Ecco come si può fare con Pure Data :

Prevenzione dell'urlo nei bambini con Pure Data

Metro è un metronomo e "metro 100" continua a suonare ogni 100 ms.

L'audio proviene da adc ~, il volume viene calcolato da env ~. "pd dsp 0" disattiva il DSP quando viene sbattuto, "pd dsp 1" lo attiva. "shell" esegue il comando passato in una shell, utilizzo l'API xrandr di Linux per impostare la luminosità su X, è necessario adattarlo per Wayland.

Come puoi vedere, il periodo di tolleranza e il blocco occupano molto più spazio rispetto al codice audio.

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

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


11
molto bella! Puoi rendere questo molto reattivo usando questa tecnica: traccia il livello medio del suono in un minuto, quindi usalo come base, in modo che quando i bambini superano i 20 dB sopra la linea di base, si inneschi. Quindi si adatterà automaticamente al livello del suono ambientale.
Hans-Christoph Steiner,

1
Sì, ha senso @ Hans-ChristophSteiner. Ma in un certo senso, il livello di rumore ambientale non richiederebbe ai bambini di urlare più forte, dal momento che costituirebbero una proporzione minore del rumore complessivo? Ciò ovviamente si applicherebbe solo se il rumore esistente è bianco o rosa o altrimenti ignorato.
Janus Troelsen,

4
se fosse più silenzioso del solito, come una mattina del fine settimana, lo renderebbe più sensibile, dato che sarebbe sempre 20 dB sopra il livello ambientale
Hans-Christoph Steiner

Questo è il PD esteso?
nullpotent

@iccthedral: ho usato pd-extended per realizzarlo, ma non so se ho usato costrutti specifici con pd-extended.
Janus Troelsen,

103

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

Fondamentalmente registra il suono ogni 5 secondi, quindi controlla l'ampiezza del suono, usando soxe decide se attivare o meno uno script. Penso che tu possa adattare facilmente la rubysceneggiatura ai tuoi figli! Oppure puoi scegliere di hackerare lo script Python (usando PyAudio) che ha fornito anche lui.


5
Che dire di quelle esplosioni meno di 5 secondi che evitano il rilevamento?
RhysW

53

Puoi ottenere informazioni dal microfono facendo qualcosa del tipo:

arecord -d1 /dev/null -vvv

Potrebbe essere necessario giocare un po 'con le impostazioni, come ad esempio:

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

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


44

Questa è una delle domande più divertenti che ho visto. Vorrei ringraziare Tucuxi per una risposta così eccellente; 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

7
Se inizi a correre aggiungendo una linea a /etc/rc4.d/S99rc.local e poi cambiando il microfono di ingresso da non amplificato al 100%, anche tu puoi finire per essere gettato su tty3 (puoi saltare indietro prima che il sonno sia finito con Ctrl + Alt + F7), e se la tua tastiera è troppo forte per aprire un terminale, per eseguire sudo killall too_loud quindi Ctrl + Alt + F1 e accedere lì.)
Alexx Roche

41

I miei 2 centesimi per la soluzione C o C ++: forse non l'approccio più efficace, ma su Linux, puoi usare l' API ALSA (libreria di gestione audio integrata di Linux) e usare una tecnica numerica (ad esempio, calcolare il suono medio ogni secondo) per ottenere il livello di rumore.

Quindi puoi controllarlo in un ciclo infinito e se è maggiore di una treshold preimpostata, puoi utilizzare la libreria X11 per spegnere lo schermo per alcuni secondi o in alternativa (meno elegante, ma funziona) invocare il chvtcomando utilizzando system("chvt 3; sleep 15; chvt 7 ");.


2
Se usando il comando considererei qualcosa di diverso allora chvt. ArchWiki ha dei buoni esempi.
d.C.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.