我怎么能“听”内部主板扬声器上的声音

时间:2014-01-17 17:35:37

标签: python windows

我们正在使用一个非常旧的程序来驱动一些设备测试。这些测试可以运行几天,我想知道测试何时完成。当测试完成时,可执行文件会以每秒约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)

3 个答案:

答案 0 :(得分:2)

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

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

或者,如果您想进入真正的低级编程,请查看查询"Programmable Interval Timer"芯片drives the speakers。请特别注意Read Back Status Byte中的“输出引脚状态”。

您可能必须为python写一个C扩展来访问这些端口:有关访问芯片的一些示例C代码,请参阅here

答案 1 :(得分:2)

好的,这是我尝试使用PyAudio的解决方案,让我知道你的想法。不幸的是,我目前无法进行测试。

这是根据PyAudio页面上的“Record”示例改编的。

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 AND ,至少发现一声蜂鸣声。由于存在一些重叠,所有处理都在线程中完成。

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

最后一点说明:正如我之前所说,我没有能够测试它,所以它可能不会在你的拳头上运行。我提前道歉,但至少,这应该给你一个很好的开端。请告诉我什么休息,以便我可以在这里解决!

<强>参考文献:

  • 录制声音:来自PyAudio页面的“录制”示例
  • FFT和查找频率:This post
祝你好运

答案 2 :(得分:0)

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

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