-
Notifications
You must be signed in to change notification settings - Fork 22
/
alarmBeepDetect.py
101 lines (94 loc) · 4.04 KB
/
alarmBeepDetect.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#!/usr/bin/env python
# This program is for educational purposes only and should never be used in any production or safety system
# Benjamin Chodroff benjamin.chodroff@gmail.com
# Updated on 2024/06/16 for Python3
import pyaudio
from numpy import zeros,linspace,short,hstack,transpose,log,frombuffer
from numpy.fft import fft
from time import sleep
#Volume Sensitivity, 0.05: Extremely Sensitive, may give false alarms
# 0.1: Probably Ideal volume
# 1: Poorly sensitive, will only go off for relatively loud
SENSITIVITY= 1
# Alarm frequency (Hz) to detect (Set frequencyoutput to True if you need to detect what frequency to use)
TONE = 3500
#Bandwidth for detection (i.e., detect frequencies +- within this margin of error of the TONE)
BANDWIDTH = 30
# Each blip is 1/SAMPLE_RATE * NUM_SAMPLES which is approximately 46ms for 44100 Hz with 2048 samples
#How many 46ms blips before we declare a beep? (Set frequencyoutput to True if you need to determine how many blips are found, then subtract some)
beeplength=8
# How many beeps before we declare an alarm? (Avoids false alarms)
alarmlength=5
# How many false 46ms blips before we declare there are no more beeps? (May need to be increased if there are expected long pauses between beeps)
resetlength=10
# How many reset counts until we clear an active alarm? (Keep the alarm active even if we don't hear this many beeps)
clearlength=30
# Enable blip, beep, and reset debug output (useful for understanding when blips, beeps, and resets are being found)
debug=False
# Show the most intense frequency detected (useful for configuration of the frequency and beep lengths)
frequencyoutput=False
# Audio Sampler
NUM_SAMPLES = 2048
SAMPLING_RATE = 44100
pa = pyaudio.PyAudio()
_stream = pa.open(format=pyaudio.paInt16,
channels=1, rate=SAMPLING_RATE,
input=True,
frames_per_buffer=NUM_SAMPLES)
print("Alarm detector working. Press CTRL-C to quit.")
blipcount=0
beepcount=0
resetcount=0
clearcount=0
alarm=False
while True:
while _stream.get_read_available()< NUM_SAMPLES: sleep(0.01)
audio_data = frombuffer(_stream.read(
_stream.get_read_available()), dtype=short)[-NUM_SAMPLES:]
# Each data point is a signed 16 bit number, so we can normalize by dividing 32*1024
normalized_data = audio_data / 32768.0
intensity = abs(fft(normalized_data))[:NUM_SAMPLES//2]
frequencies = linspace(0.0, float(SAMPLING_RATE)/2, num=int(NUM_SAMPLES/2))
if frequencyoutput:
which = intensity[1:].argmax()+1
# use quadratic interpolation around the max
if which != len(intensity)-1:
y0,y1,y2 = log(intensity[which-1:which+2:])
x1 = (y2 - y0) * .5 / (2 * y1 - y2 - y0)
# find the frequency and output it
thefreq = (which+x1)*SAMPLING_RATE/NUM_SAMPLES
else:
thefreq = which*SAMPLING_RATE/NUM_SAMPLES
if max(intensity[(frequencies < TONE+BANDWIDTH) & (frequencies > TONE-BANDWIDTH )]) > max(intensity[(frequencies < TONE-1000) & (frequencies > TONE-2000)]) + SENSITIVITY:
if frequencyoutput:
print("\t\t\t\tfreq=",thefreq)
blipcount+=1
resetcount=0
if debug: print("\t\tBlip",blipcount)
if (blipcount>=beeplength):
blipcount=0
resetcount=0
beepcount+=1
if debug: print("\tBeep",beepcount)
if (beepcount>=alarmlength and not alarm):
clearcount=0
alarm=True
print("Alarm!")
beepcount=0
else:
if frequencyoutput:
print("\t\t\t\tfreq=",thefreq)
blipcount=0
resetcount+=1
if debug: print("\t\t\treset",resetcount)
if (resetcount>=resetlength):
resetcount=0
beepcount=0
if alarm:
clearcount+=1
if debug: print("\t\tclear",clearcount)
if clearcount>=clearlength:
clearcount=0
print("Cleared alarm!")
alarm=False
sleep(0.01)