如何"listen"内置主板扬声器上的声音



我们正在使用一个非常旧的程序来驱动一些设备测试。这些测试可以运行几天,我想知道测试何时完成。测试完成后,可执行程序会以每秒约1次的蜂鸣声持续提示主板扬声器,直到操作员介入。

有没有一种方法可以让我"听"这个哔哔声,并在MB开始哔哔时发出通知?我希望有一个sysos库可以用来指示这一点。

我们在Windows XP x86上运行。我还没有在机器上安装Python。

伪码:

already_beeping = True
while True:
speaker_beeping = check_speaker() # returns True or False
if speaker_beeping == True:
if already_beeping == False:
send_notification()
already_beeping = True
else:
pass
else:
already_beeping = False
time.sleep(10)

好的,这是我尝试使用PyAudio的解决方案,让我知道你的想法。不幸的是,我目前没有测试手段。

这是根据PyAudio页面上的"录制"示例改编的。

import threading
import PyAudio
import wave
import struct
import numpy as np
import os
import datetime
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 5
SEARCHTIME = 5
LOWERBOUND = 0.9
UPPERBOUND = 1.1
class RecorderThread(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
self.stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
self.start()
def run(self):
p = pyaudio.PyAudio()
print("* recording")
frames = []
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = self.stream.read(CHUNK)
frames.append(data)
print("* done recording")
self.stream.stop_stream()
self.stream.close()
p.terminate()
wf = wave.open(self.name, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
frate = RATE
wav_file = wave.open(self.name,'r')
data = wav_file.readframes(wav_file.getnframes())
wav_file.close()
os.remove(self.file)
data =s truct.unpack('{n}h'.format(n=data_size), data)
data = np.array(data)
w = np.fft.fft(data)
freqs = np.fft.fftfreq(len(w))
idx=np.argmax(np.abs(w)**2)
freq=freqs[idx]
freq_in_hertz=abs(freq*frate)
if freq_in_herts > LOWERBOUND and freq_in_herts < UPPERBOUND:
curName = "found0.txt"
while os.path.exists(curName):
num = int(curName.split('.')[0][6:])
curName = "found{}.txt".format(str(num+1))
f = open(curName, 'r')
f.write("Found it at {}".format(datetime.datetime.now()))
f.close()
def main():
recordingThreads = []
totalTime = 0
while totalTime < SEARCHTIME*(24*3600) and not os.path.exists("found.txt"):
start = datetime.datetime(year=2012, month=2, day=25, hour=9)
curName = "record0.wav"
while os.path.exists(curName):
num = int(curName.split('.')[0][6:])
curName = "record{}.wav".format(str(num+1))
recorder = RecorderThread(curName)
time.sleep(4.5)
end = datetime.datetime(year=2012, month=2, day=25, hour=18)
totalTime += end - start
if __name__ == "__main__": main()

好吧,结果比我预想的要大一点。这将在SEARCHTIME指定的天数内运行。每4.5秒,它将录制5秒(以确保我们不会错过任何内容)。此录制将使用动态名称保存(以防止覆盖)。然后,我们对该.wav文件执行FFT,并查看频率是否在LOWERBOUNDUPPERBOUND之间。如果频率在这两个界限之间,就会创建一个文件,说明何时发生这种情况。此代码一直持续到达到SEARCHTIME并且至少发现一声蜂鸣音为止。由于有一点重叠,所有的处理都是在线程中完成的。

请注意,这可能会产生误报,这就是为什么它在第一次发现后不会终止的原因。另外,如果它永远找不到什么东西,它就会继续运行。永远

最后一点:正如我之前所说,我还没能测试它,所以它很可能不会在你的拳头上运行。我提前道歉,但至少,这会给你一个很好的开端。请让我知道什么坏了,这样我就可以在这里修理了!

参考文献:

  • 录制声音:PyAudio页面中的"录制"示例
  • FFT和查找频率:本帖

祝好运

扬声器是否通过2针插头连接到主板?

如果是这样的话,拦截它并监视信号应该是微不足道的。从示波器开始验证信号,然后连接某种USB数字I/O监视器——你应该能够计数脉冲并确定频率。(有现成的解决方案,或者一个简单的Arduino程序就可以了)。

或者,如果你想进入真正的低级别编程,可以查询驱动扬声器的"可编程间隔定时器"芯片。具体查看回读状态字节中的"输出引脚状态"。

您可能需要为python编写一个C扩展来访问这些端口:请参阅这里的一些访问芯片的C代码示例。

我不熟悉在Windows上编程,所以这个答案有很多猜测。

据推测,该程序调用了一些Windows API函数来提示扬声器,这可能是由某些DLL提供的。在POSIX平台上,我会使用LD_PRELOAD加载一个共享库,用我自己的版本覆盖API函数,这样就可以通知我。在Windows上可能也有类似的技术;也许DLL注入有帮助。

最新更新