如果达到一定的噪音水平,如何在一段时间内使机器“黑屏”(作为惩罚)?


1548

我的孩子(4岁和5岁)在计算机上玩游戏时大喊大叫。我找到了有效的解决方法。当我听到很大的声音时,我便进入游戏计算机并执行以下操作:

chvt 3;  sleep 15;  chvt 7 

在Linux上,这将关闭屏幕15秒钟。我告诉他们,计算机不喜欢吵闹的声音。他们完全相信这一点,并请求计算机原谅。他们变得安静了许多,但没有达到我满意的程度,因此我需要继续进行这一教育过程。但是,我并不总是手动执行此操作。

可以自动化吗?麦克风已连接到盒子。如果响度级别超过某个阈值,那么我要运行命令。


2
直到他们学会按下CTRL + ALT + F7
Suici Doga '18

1
@SuiciDoga嘿;他们不知道发生了什么!
wizzwizz4 18-10-24

恭喜您获得了技术解决方案。但我认为,务必要对孩子们说实话。
彼得

Answers:


645

使用soxSOX分析很短的音频采样:

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

通过-t .wav指定,我们处理wav类型,"|arecord -d 2"执行arecord 程序两秒钟,-n输出到空文件,并stat指定我们想要的统计信息。

该命令在我的系统上带有一些背景说明的输出为:

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

然后可以通过以下方式提取最大幅度:

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

我们grep针对所需的行,tr先剪掉空格字符,然后cut按字符剪掉,然后:取第二部分,0.068383在本示例中为我们提供。正如评论所建议的那样,RMS是比最大幅度更好的能量度量。

您最终可以bc在结果上使用命令行来比较浮点值:

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

如果您构建一个循环(请参阅Bash示例),该循环调用sleep 1分钟,测试音量,然后重复播放,则可以使其在后台运行。最后一步是将其添加到初始化脚本或服务文件中(取决于您的OS /发行版),这样您甚至不必手动启动它。


280
我不建议采用最大振幅。当孩子们的屏幕变黑只是因为有人鼓掌或类似的东西时,这对孩子来说并不好。平均似乎更合适。
orlp

34
只是澄清一下,用“平均”表示RMS幅度正确吗?如果噪声在2秒钟内保持一致的响度,则平均振幅将接近0(正负两半将相互抵消)。
路加福音

6
一个用于一系列样本的简单“能量”检测器就是将所有峰的值加在一起。如果您不想,则不必平均。峰值只是sample[n]>sample[n-1]&&sample[n]>sample[n+1]我将其用作测量歌曲能量的基本机制的任何点,并且效果很好。只需搜索一个令您满意的音量数字即可。
卡斯莱

3
我想看到您第一个命令的输出示例,它确实涉及到孩子大喊大叫,以供参考。
艾文·黄

3
对于所描述的用法(自动启动+每隔几分钟运行),cron作业是使用的正确工具。与使用初始化脚本+ bash循环+睡眠相比,它更易于设置且更可靠。
m000 2013年

130

这是使用Pure Data可以完成的方法:

使用纯数据预防孩子大喊大叫

Metro是一个节拍器,“ Metro 100”每100 ms不断跳动。

音频来自adc〜,音量由env〜计算。撞击时,“ pd dsp 0”将关闭DSP,“ pd dsp 1”将其打开。“ shell”在shell中执行传递的命令,我使用Linux xrandr API将亮度设置为X,您需要对此进行调整以适应Wayland。

如您所见,宽限期和锁定比音频代码占用更多的空间。

使用环形缓冲区和/或移动平均线来进行求解应该比使用来容易sox。因此,我认为为此使用Pure Data并不是一个坏主意。但是屏幕本身会消隐并且锁定不符合数据流范式。

该PD文件位于gist.github.com:ysangkok-kidsyell.pd


11
非常好!您可以使用此技术使其响应迅速:跟踪一分钟的平均声音水平,然后将其用作基线,以便当孩子超过基线20 dB以上时触发。然后,它将自动调整为环境声音级别。
汉斯·克里斯托夫·斯坦纳

1
是的,@ Hans-ChristophSteiner很有意义。但是从某种意义上说,环境噪声水平是否真的不会要求孩子大声喊叫,因为他们将占总噪声的较小部分?当然,这仅在现有噪声为白色或粉红色或以其他方式忽略时适用。
Janus Troelsen

4
如果它比通常的安静(例如周末早晨)安静,那么它将使其更加敏感,因为它总是比环境水平高20 dB
Hans-Christoph Steiner

这是扩展的PD吗?
nullpotent 2013年

@iccthedral:我使用pd-extended来制作它,但是我不知道是否使用任何pd-extended的特定结构。
Janus Troelsen

102

选中Thomer M. Gil的“如何检测声音/音频的存在”

基本上,它每5秒钟记录一次声音,然后使用来检查声音的幅度sox,并确定是否触发脚本。我认为您可以轻松地ruby为孩子们改编剧本!或者,您也可以选择破解他提供的Python脚本(使用PyAudio)。


5
那些不到5秒就能避免被发现的爆发怎么办?
RhysW

53

您可以通过执行以下操作从麦克风获取信息:

arecord -d1 /dev/null -vvv

您可能需要稍微进行一些设置,例如:

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

从那里开始,只需解析输出即可。


43

这是我所看到的更有趣的问题之一。我要感谢tucuxi 这么好的回答;我已经设置为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
如果通过在/etc/rc4.d/S99rc.local中添加一行来开始此运行,然后将输入麦克风从未放大更改为100%,那么您最终也可能会被扔到tty3(可以在睡眠之前跳回) (Ctrl + Alt + F7),如果您的键盘太大而无法打开终端,请运行sudo killall too_loud,然后按Ctrl + Alt + F1并在那里登录。)
Alexx Roche

41

我花2美分购买C或C ++解决方案:也许不是最有效的方法,但是在Linux上,您可以使用ALSA API(Linux的内置音频处理库)并使用某种数值技术(例如,计算平均声音)每秒水平)以获得噪声水平。

然后,您可以无限循环检查它,如果它大于预设的阈值,则可以使用X11库关闭屏幕几秒钟,或者使用(虽然不那么优雅,但可以chvt使用)调用命令system("chvt 3; sleep 15; chvt 7 ");


2
如果使用命令,我会考虑不同的东西chvtArchWiki有很好的例子。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.