From 59934436c41da5c999a065638d2e951a34110b03 Mon Sep 17 00:00:00 2001 From: Harvie Date: Wed, 1 Aug 2012 00:47:42 +0200 Subject: [PATCH] Improved Goertzel + DTMF decoder example --- c/goertzel/dtmf.sh | 71 +++++++++++++++++++++++++++ c/goertzel/goertzel.c | 109 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 176 insertions(+), 4 deletions(-) create mode 100755 c/goertzel/dtmf.sh diff --git a/c/goertzel/dtmf.sh b/c/goertzel/dtmf.sh new file mode 100755 index 0000000..6c7798e --- /dev/null +++ b/c/goertzel/dtmf.sh @@ -0,0 +1,71 @@ +#!/bin/bash +#This is sample implementation of DTMF decoder using my C implementation of Goertzel Algorithm +#This is not very efficient or precise, it's just proof of concept +#Usage example: arecord 2>/dev/null | ./dtmf.sh + +tresh=3 +last=''; +./goertzel -i -q -r 8000 -s 400 -t $tresh -f 697 -f 770 -f 852 -f 941 -f 1209 -f 1336 -f 1477 -f 1633 | while read line; do + #echo "$line"; + + #Get time + pos="$(echo "$line" | cut -f 1)"; + + #Get values for each tone + a="$(echo "$line" | cut -f 2)"; + b="$(echo "$line" | cut -f 3)"; + c="$(echo "$line" | cut -f 4)"; + d="$(echo "$line" | cut -f 5)"; + e="$(echo "$line" | cut -f 6)"; + f="$(echo "$line" | cut -f 7)"; + g="$(echo "$line" | cut -f 8)"; + h="$(echo "$line" | cut -f 9)"; + + #Compare values to treshold + test $a -gt $tresh && a=true || a=false + test $b -gt $tresh && b=true || b=false + test $c -gt $tresh && c=true || c=false + test $d -gt $tresh && d=true || d=false + test $e -gt $tresh && e=true || e=false + test $f -gt $tresh && f=true || f=false + test $g -gt $tresh && g=true || g=false + test $h -gt $tresh && h=true || h=false + + #echo "$pos: $a $b $c $d $e $f $g $h"; + state="$a$b$c$d$e$f$g$h"; + + #Test if tones changed since last time + #echo test "$state" != "$last" + test "$state" != "$last" && { + + #DTMF Table + $a && { + $e && echo -n '1' + $f && echo -n '2' + $g && echo -n '3' + $h && echo -n 'A' + } + $b && { + $e && echo -n '4' + $f && echo -n '5' + $g && echo -n '6' + $h && echo -n 'B' + } + $c && { + $e && echo -n '7' + $f && echo -n '8' + $g && echo -n '9' + $h && echo -n 'C' + } + $d && { + $e && echo -n '*' + $f && echo -n '0' + $g && echo '#' + $h && echo -n 'D' + } + + } + + last="$state" + +done diff --git a/c/goertzel/goertzel.c b/c/goertzel/goertzel.c index bcf7a91..f5250a0 100644 --- a/c/goertzel/goertzel.c +++ b/c/goertzel/goertzel.c @@ -1,10 +1,15 @@ #include #include +#include + /* Usage examples arecord | ./goertzel sox input.mp3 -b 8 -c 1 -r 8000 -t wav - | ./goertzel + + Arguments for DTMF decoding: + -f 697 -f 770 -f 852 -f 941 -f 1209 -f 1336 -f 1477 -f 1633 -t 10 */ float goertzel_mag(int numSamples,int TARGET_FREQUENCY,int SAMPLING_RATE, float* data) @@ -48,7 +53,18 @@ float goertzel_mag(int numSamples,int TARGET_FREQUENCY,int SAMPLING_RATE, float* return magnitude; } -int main() { +void print_help(char ** argv) { + printf("help me %s\n", argv[0]); +} + +void addfreq(int *freqs, int freq) { + int i = 0; + while(freqs[i]!=-1) i++; + freqs[i]=freq; + freqs[i+1]=-1; +} + +int main(int argc, char ** argv) { /* int samples[] = {0,1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2,1}; int samplecount = 18; @@ -58,19 +74,104 @@ int main() { int samplerate = 8000; int samplecount = 4000; + int treshold = -1; + char noreturn = 0; + char integers=0; + char verbose=1; + int freqs[argc+1]; freqs[0]=-1; + + int opt; + while ((opt = getopt(argc, argv, "?r:s:f:t:iqn")) != -1) { + switch (opt) { + case 'r': + samplerate = atoi(optarg); + break; + case 's': + samplecount = atoi(optarg); + break; + case 'f': + addfreq(freqs, atoi(optarg)); + break; + case 't': + treshold = atoi(optarg); + break; + case 'i': + integers = 1; + break; + case 'n': + noreturn = 1; + break; + case 'q': + verbose = 0; + break; + case '?': + print_help(argv); + return 0; + break; + } + } + + if(freqs[0]==-1) addfreq(freqs, 440); float samples[samplecount]; float position = 0; - fprintf(stderr,"Position (Secs)\tMagnitude\n"); + + if(verbose) { + fprintf(stderr, + "#Detected tone: %d Hz\n" + "#Samplerate: %d Hz\n" + "#Frame lenght: %d samples\n" + "#Treshold: %d\n" + "#\n" + ,freqs[0],samplerate,samplecount,treshold); + fflush(stderr); + + printf("#Position"); + int i; for(i=0;freqs[i]!=-1;i++) { + printf("\t%2dHz",freqs[i]); + } + puts(""); + } + + char print=0, printnow=0, printlast = 0; while(!feof(stdin)) { int i; + + //Sample data for(i=0;i treshold; + print = print || printnow || (printlast && !noreturn); + } + printlast = printnow; + fflush(stdout); + + //Print data + if(print) { + printf("%8.2f", position); + for(i=0;freqs[i]!=-1;i++) { + printf("\t"); + if(integers) + printf("%d",(int)power[i]); + else + printf("%.4f",power[i]); + } + puts(""); + fflush(stdout); + } + + //Increase time position += ((float)samplecount/(float)samplerate); - float power = goertzel_mag(samplecount, 440, samplerate, samples); - printf("%f\t%f\n", position, power); } } -- 2.30.2