ich versuche gerade von einer am Raspberry angeschlossenen Soundkarte DTMF Töne zu erkennen, sowie einen bestimmten Ton zu erkennen.
Ich habe folgendes heute durch googeln etc. gefunden, bzw. umgebaut:
Code: Alles auswählen
#!/usr/bin/env python
import pyaudio
from numpy import zeros,linspace,short,fromstring,hstack,transpose,log
from scipy 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 frequencies (Hz) to detect (Use audacity to record a wave and then do Analyze->Plot Spectrum)
TONE = 1750
#Bandwidth for detection (i.e., detect frequencies within this margin of error of the TONE)
BANDWIDTH = 10
# Show the most intense frequency detected (useful for configuration)
beeplength=6
frequencyoutput=False
#Set up audio sampler -
NUM_SAMPLES = 2048
SAMPLING_RATE = 48000
pa = pyaudio.PyAudio()
_stream = pa.open(format=pyaudio.paInt16,
channels=1, rate=SAMPLING_RATE,
input=True,
frames_per_buffer=NUM_SAMPLES)
print("1750hz detector working. Press CTRL-C to quit.")
blipcount=0
while True:
while _stream.get_read_available()< NUM_SAMPLES: sleep(0.01)
audio_data = fromstring(_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=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
print "freq=",thefreq
if max(intensity[(frequencies < TONE+BANDWIDTH) & (frequencies > TONE-BANDWIDTH )]) > max(intensity[(frequencies < TONE-1000) & (frequencies > TONE-2000)]) + SENSITIVITY:
if blipcount <= beeplength:
blipcount+=1
if blipcount == beeplength:
print "1750hz"
else:
blipcount=0
sleep(0.01)
Das funktioniert soweit... Sobald die 1750hz erkannt werden, wird der Text "1750hz" ausgegeben.
Nun bin ich am überlegen, das so zu erweitern, dass ich auch DTMF auswerten kann...
Ich weiß, dass DTMF aus zwei Tönen bestehen (1209.0,1336.0,1477.0,1633.0,697.0,770.0,852.0,941.0) und ich habe auch diesen Code gefunden:
Code: Alles auswählen
'''
A python implementation of the Goertzel algorithm to decode DTMF tones.
The wave file is split into bins and each bin is analyzed
for all the DTMF frequencies. The method run() will return a numeric
representation of the DTMF tone.
'''
import wave
import struct
import math
class pygoertzel_dtmf:
def __init__(self, samplerate):
self.samplerate = samplerate
self.goertzel_freq = [1209.0,1336.0,1477.0,1633.0,697.0,770.0,852.0,941.0]
self.s_prev = {}
self.s_prev2 = {}
self.totalpower = {}
self.N = {}
self.coeff = {}
# create goertzel parameters for each frequency so that
# all the frequencies are analyzed in parallel
for k in self.goertzel_freq:
self.s_prev[k] = 0.0
self.s_prev2[k] = 0.0
self.totalpower[k] = 0.0
self.N[k] = 0.0
normalizedfreq = k / self.samplerate
self.coeff[k] = 2.0*math.cos(2.0 * math.pi * normalizedfreq)
def __get_number(self, freqs):
hi = [1209.0,1336.0,1477.0,1633.0]
lo = [697.0,770.0,852.0,941.0]
# get hi freq
hifreq = 0.0
hifreq_v = 0.0
for f in hi:
if freqs[f]>hifreq_v:
hifreq_v = freqs[f]
hifreq = f
# get lo freq
lofreq = 0.0
lofreq_v = 0.0
for f in lo:
if freqs[f]>lofreq_v:
lofreq_v = freqs[f]
lofreq = f
if lofreq==697.0:
if hifreq==1209.0:
return "1"
elif hifreq==1336.0:
return "2"
elif hifreq==1477.0:
return "3"
elif hifreq==1633.0:
return "A"
elif lofreq==770.0:
if hifreq==1209.0:
return "4"
elif hifreq==1336.0:
return "5"
elif hifreq==1477.0:
return "6"
elif hifreq==1633.0:
return "B"
elif lofreq==852.0:
if hifreq==1209.0:
return "7"
elif hifreq==1336.0:
return "8"
elif hifreq==1477.0:
return "9"
elif hifreq==1633.0:
return "C"
elif lofreq==941.0:
if hifreq==1209.0:
return "*"
elif hifreq==1336.0:
return "0"
elif hifreq==1477.0:
return "#"
elif hifreq==1633.0:
return "D"
def run(self, sample):
freqs = {}
for freq in self.goertzel_freq:
s = sample + (self.coeff[freq] * self.s_prev[freq]) - self.s_prev2[freq]
self.s_prev2[freq] = self.s_prev[freq]
self.s_prev[freq] = s
self.N[freq]+=1
power = (self.s_prev2[freq]*self.s_prev2[freq]) + (self.s_prev[freq]*self.s_prev[freq]) - (self.coeff[freq]*self.s_prev[freq]*self.s_prev2[freq])
self.totalpower[freq]+=sample*sample
if (self.totalpower[freq] == 0):
self.totalpower[freq] = 1
freqs[freq] = power / self.totalpower[freq] / self.N[freq]
return self.__get_number(freqs)
if __name__ == '__main__':
# load wav file
wav = wave.open('/home/michael/Downloads/dtmf.wav', 'r')
(nchannels, sampwidth, framerate, nframes, comptype, compname) = wav.getparams()
frames = wav.readframes(nframes * nchannels)
# convert wave file to array of integers
frames = struct.unpack_from("%dH" % nframes * nchannels, frames)
# if stereo get left/right
if nchannels == 2:
left = [frames[i] for i in range(0,len(frames),2)]
right = [frames[i] for i in range(1,len(frames),2)]
else:
left = frames
right = left
binsize = 400
# Split the bin in 4 to average out errors due to noise
binsize_split = 4
prevvalue = ""
prevcounter = 0
for i in range(0,len(left)-binsize,binsize/binsize_split):
goertzel = pygoertzel_dtmf(framerate)
for j in left[i:i+binsize]:
value = goertzel.run(j)
if value==prevvalue:
prevcounter+=1
if prevcounter==10:
print value
else:
prevcounter=0
prevvalue=value
Wie bekomme ich das so umgebaut, dass es DTMF von der Soundkarte erkennt?
Gruß Tommi