Bagaimana cara membuat mesin "layar kosong" untuk jangka waktu tertentu (sebagai penalti) jika tingkat kebisingan tertentu tercapai?

1549

Anak-anak saya (4 dan 5) sering berteriak ketika bermain game di komputer. Saya menemukan obat yang efektif untuk ini. Ketika saya mendengar suara keras, saya ssh ke komputer game dan melakukan:

chvt 3;  sleep 15;  chvt 7 

Ini akan mematikan layar selama 15 detik di Linux. Saya sudah memberi tahu mereka bahwa komputer tidak suka suara keras. Mereka benar-benar percaya ini dan meminta maaf kepada komputer. Mereka menjadi jauh lebih tenang, tetapi tidak pada tingkat yang membuat saya bahagia, jadi saya perlu melanjutkan proses pendidikan ini. Namun, saya tidak selalu ada untuk melakukan ini secara manual.

Apakah mungkin untuk mengotomatisasi ini? Mikrofon terpasang ke kotak. Jika tingkat kenyaringan melewati beberapa ambang batas maka saya ingin menjalankan perintah.

Leonid Volnitsky
sumber
3
Sampai mereka belajar menekan CTRL + ALT + F7
Suici Doga
1
@SuiciDoga Hai; mereka tidak tahu apa yang sedang terjadi!
wizzwizz4
Selamat untuk solusi teknis. Tapi saya pikir, penting untuk selalu mengatakan kebenaran kepada anak-anak.
peterh

Jawaban:

645

Gunakan soxdari SoX untuk menganalisis sampel audio pendek:

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

Dengan -t .wavkami tentukan, kami memproses jenis wav, "|arecord -d 2"menjalankan arecord program selama dua detik, -nmengeluarkan ke file nol dan dengan statkami menentukan kami ingin statistik.

Output dari perintah ini, pada sistem saya dengan beberapa pidato latar belakang, adalah:

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

Amplitudo maksimum kemudian dapat diekstraksi melalui:

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

Kami grepuntuk baris yang kami inginkan, gunakan truntuk memangkas karakter spasi dan kemudian cutoleh :karakter dan mengambil bagian kedua yang memberi kita 0.068383dalam contoh ini. Seperti yang disarankan oleh komentar, RMS adalah ukuran energi yang lebih baik daripada amplitudo maksimum.

Anda akhirnya dapat menggunakan bcpada hasil untuk membandingkan nilai floating-point dari baris perintah:

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

Jika Anda membuat lingkaran (lihat contoh Bash ) yang memanggil sleep selama 1 menit, menguji volume, dan kemudian mengulanginya, Anda bisa membiarkannya tetap berjalan di latar belakang. Langkah terakhir adalah menambahkannya ke skrip init atau file layanan (tergantung pada OS / distro Anda), sehingga Anda bahkan tidak harus menjalankannya secara manual.

tucuxi
sumber
282
Saya akan merekomendasikan mengambil amplitudo maksimum. Ini tidak baik untuk anak-anak ketika layar mereka kosong hanya karena seseorang bertepuk tangan atau yang serupa. Rata-rata sepertinya lebih tepat.
orlp
34
Hanya klarifikasi, dengan "rata-rata" yang Anda maksud RMS Amplitude kan? Amplitudo rata-rata akan mendekati 0 jika kebisingan dari kenyaringan yang konsisten selama 2 detik (bagian positif dan negatif akan membatalkan satu sama lain).
Luke
6
Detektor "energi" sederhana untuk serangkaian sampel adalah dengan menambahkan nilai semua puncak secara bersamaan. Anda tidak perlu meratakannya jika tidak mau. Puncak adalah sembarang titik di mana sample[n]>sample[n-1]&&sample[n]>sample[n+1]saya menggunakan ini sebagai mekanisme yang belum sempurna untuk mengukur energi lagu dan itu bekerja dengan cukup baik. Cukup cari nomor ajaib yang membuat Anda senang dengan level volume.
Kaslai
3
Saya ingin melihat contoh output dari perintah pertama Anda ketika benar-benar datang ke anak-anak berteriak, untuk referensi.
Alvin Wong
3
Untuk penggunaan yang dijelaskan (mulai secara otomatis + jalankan setiap beberapa menit) pekerjaan cron adalah alat yang tepat untuk digunakan. Jauh lebih mudah untuk diatur dan lebih kuat daripada menggunakan skrip init + bash loop + sleep.
m000
131

Inilah cara melakukannya dengan Pure Data :

Pencegahan anak berteriak menggunakan Data Murni

Metro adalah metronom, dan "metro 100" terus menggedor setiap 100 ms.

Audio berasal dari adc ~, volume dihitung oleh env ~. "pd dsp 0" mematikan DSP ketika menggedor, "pd dsp 1" menyalakannya. "shell" mengeksekusi perintah yang lewat di shell, saya menggunakan Linux xrandr API untuk mengatur kecerahan ke X, Anda perlu mengadaptasi ini untuk Wayland.

Seperti yang Anda lihat, masa tenggang dan penguncian memakan lebih banyak ruang daripada kode audio.

Membuat solusi dengan buffer cincin dan / atau rata-rata bergerak harus lebih mudah daripada melakukannya sox. Jadi saya pikir itu bukan ide buruk untuk menggunakan Data Murni untuk ini. Tetapi layar mengosongkan dirinya sendiri dan penguncian tidak sesuai dengan paradigma aliran data.

File PD ada di gist.github.com: ysangkok - kidsyell.pd .

Janus Troelsen
sumber
11
sangat bagus! Anda bisa membuatnya menjadi cukup responsif menggunakan teknik ini: melacak tingkat suara rata-rata lebih dari satu menit, kemudian menggunakannya sebagai garis dasar, sehingga ketika anak-anak pergi lebih dari 20 dB di atas garis dasar, itu memicu. Maka secara otomatis akan menyesuaikan dengan level suara sekitar.
Hans-Christoph Steiner
1
Ya, itu masuk akal @ Hans-ChristophSteiner. Tetapi dengan cara tertentu, bukankah tingkat kebisingan sekitar sebenarnya mengharuskan anak-anak berteriak lebih keras, karena mereka akan membuat proporsi yang lebih kecil dari keseluruhan kebisingan? Itu tentu saja hanya akan berlaku jika kebisingan yang ada berwarna putih atau merah muda atau sebaliknya diabaikan.
Janus Troelsen
4
jika lebih tenang dari biasanya, seperti pagi akhir pekan, maka itu akan membuatnya lebih sensitif, karena itu akan selalu 20 dB di atas tingkat lingkungan
Hans-Christoph Steiner
Ini perpanjangan PD?
nullpotent
@iccthedral: Saya menggunakan pd-extended untuk membuatnya, tapi saya tidak tahu apakah saya menggunakan konstruksi spesifik pd-extended.
Janus Troelsen
103

Centang "Cara mendeteksi keberadaan suara / audio" oleh Thomer M. Gil .

Pada dasarnya ia merekam suara setiap 5 detik, daripada memeriksa amplitudo suara, menggunakan sox, dan memutuskan apakah memicu skrip atau tidak. Saya pikir Anda dapat dengan mudah menyesuaikan rubynaskah untuk anak-anak Anda! Atau Anda dapat memilih untuk meretas skrip Python (menggunakan PyAudio) yang telah ia sediakan juga.

Atropo
sumber
5
Bagaimana dengan ledakan kurang dari 5 detik yang menghindari deteksi?
RhysW
53

Anda dapat memperoleh informasi dari mikrofon dengan melakukan sesuatu seperti:

arecord -d1 /dev/null -vvv

Anda mungkin harus bermain dengan pengaturan sedikit, seperti:

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

Dari sana, keluar, itu masalah sederhana untuk mengurai output.

situs cha0
sumber
44

Ini adalah salah satu pertanyaan yang lebih menyenangkan yang pernah saya lihat. Saya ingin berterima kasih kepada tucuxi untuk jawaban yang begitu bagus; yang telah saya tetapkan sebagai skrip 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
Alexx Roche
sumber
7
Jika Anda mulai menjalankan ini dengan menambahkan baris ke /etc/rc4.d/S99rc.local dan kemudian mengubah input mic dari tidak teramplifikasi menjadi 100%, Anda juga dapat terlempar ke tty3 (Anda dapat melompat kembali sebelum tidur adalah berakhir dengan Ctrl + Alt + F7), dan jika keyboard Anda terlalu keras untuk membuka terminal, untuk menjalankan sudo killall too_loud kemudian Ctrl + Alt + F1 dan login di sana.)
Alexx Roche
41

2 sen saya untuk solusi C atau C ++: mungkin bukan pendekatan yang paling efektif, tetapi di Linux, Anda dapat menggunakan ALSA API (built-in library penanganan audio Linux) dan menggunakan beberapa teknik numerik (misalnya, menghitung suara rata-rata) level setiap detik) untuk mendapatkan level noise.

Kemudian Anda bisa memeriksanya dalam infinite loop, dan jika itu lebih besar dari pra-treshold, Anda dapat menggunakan pustaka X11 untuk mematikan layar selama beberapa detik, atau sebagai alternatif (kurang elegan, tetapi berfungsi) chvtgunakan perintah dengan menggunakan system("chvt 3; sleep 15; chvt 7 ");.

H2CO3
sumber
2
Jika menggunakan perintah saya akan mempertimbangkan sesuatu yang berbeda chvt. ArchWiki memiliki contoh yang bagus.
AD