Detect DTMF from Sound Card Device

I have an audio device that plugs into a phone line. I want to create a vb.net app that will continuously monitor one of the ports for DTMF tones. When it detects a DTMF tone, i.e. someone is dialing a number, it performs an action. It doesn't actually have to decode the tones, just detect when one is dialed. Can someone give me code that will do this?

The device is actually a Telephony card but I can't use TAPI because the card itself does not actually pick up the call. The card has WAVE drivers so it can be set as a Default Recording Device in Windows.



Alternatively, if someone can tell me how to detect a dial tone or dtmf tone with a Telephony device that is passively monitoring a phone line (tapping it), that would be good too!

Thanks.
LVL 1
rbichonAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

gregoryyoungCommented:
The goertzel algorithm is the best known algorithm ... you can find more on it including a demo C++ app here http://www.embedded.com/story/OEG20020819S0057

but this sounds rather illegal.

rbichonAuthor Commented:
I am located in Ohio. In Ohio, it is legal to tap/record ones own phone lines. We are not even required by law to notify the caller, even out of state callers, that this is taking place. Look into it if you like.

I am not looking for C++ code. I posted this question in the VB.NET area. I need VB.NET code. Also, I am not looking for just an algorithm. The code must be able to interface with an audio device.
gregoryyoungCommented:
that code can work on standard .wav data the rest is just a matter of getting the data which is a trivial task (reading from a recording source)

"I want to create a vb.net app that will continuously monitor one of the ports for DTMF tones."

As you have stated you want to create something, yet in your reply you basically state that you in fact want me to create it for you. Occasionally people ask questions for something that does not have a readily available implementation which means they may actually have to write code. You may wonder why there is not a readily available solution in this case, well its fairly apparent VB.NET is the WRONG tool to be using for anything resembling real tiime data signal processing.

I am quite sure you can BUY something which does this, but I can assure you that I this is not a free outsourcing center.

Introduction to Web Design

Develop a strong foundation and understanding of web design by learning HTML, CSS, and additional tools to help you develop your own website.

rbichonAuthor Commented:
How can I read from a specific recording source? Since you claim it to be trivial, I assume that you already have some code.
gregoryyoungCommented:
There are numerous free and for money libraries that do this http://www.codeproject.com/cs/media/cswavrec/cswavrec_src.zip is one which can easily be accessed from your VB.NET code and is implemented in C# (includes source) ... just add a reference and use their objects ... There are numerous other components, a quick google on VB.NET record audio will bring back quite a few.

I believe the direct x area also has interfaces for this ...

gregoryyoungCommented:
also since this is the entirety of the algorithm (including the generation of test data) I do not think its a "difficult" port.

/** Tone detect by Goertzel algorithm
*
* This program basically searches for tones (sines) in a sample and reports the different dB it finds for
* different frequencies. Can easily be extended with some thresholding to report true/false on detection.
* I'm far from certain goertzel it implemented 100% correct, but it works :)
*
* Hint, the SAMPLERATE, BUFFERSIZE, FREQUENCY, NOISE and SIGNALVOLUME all affects the outcome of the reported dB. Tweak
* em to find the settings best for your application. Also, seems to be pretty sensitive to noise (whitenoise anyway) which
* is a bit sad. Also I don't know if the goertzel really likes float values for the frequency ... And using 44100 as
* samplerate for detecting 6000 Hz tone is kinda silly I know :)
*
* Written by: Espen Riskedal, espenr@ii.uib.no, july-2002
*/

#include <iostream>
#include <cmath>
#include <cstdlib>

using std::rand;
// math stuff
using std::cos;
using std::abs;
using std::exp;
using std::log10;
// iostream stuff
using std::cout;
using std::endl;

#define PI 3.14159265358979323844
// change the defines if you want to
#define SAMPLERATE 44100
#define BUFFERSIZE 8820
#define FREQUENCY 6000
#define NOISE 0.05
#define SIGNALVOLUME 0.8

/**  The Goertzel algorithm computes the k-th DFT coefficient of the input signal using a second-order filter.
*   http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/www/node3.html.
*   Basiclly it just does a DFT of the frequency we want to check, and none of the others (FFT calculates for all frequencies).
*/
float goertzel(float *x, int N, float frequency, int samplerate) {
    float Skn, Skn1, Skn2;
    Skn = Skn1 = Skn2 = 0;
   
    for (int i=0; i<N; i++) {
    Skn2 = Skn1;
    Skn1 = Skn;
    Skn = 2*cos(2*PI*frequency/samplerate)*Skn1 - Skn2 + x[i];
    }
   
    float WNk = exp(-2*PI*frequency/samplerate); // this one ignores complex stuff
    //float WNk = exp(-2*j*PI*k/N);
    return (Skn - WNk*Skn1);
}

/** Generates a tone of the specified frequency
*  Gotten from: http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=3c641e%243jn%40uicsl.csl.uiuc.edu
*/
float *makeTone(int samplerate, float frequency, int length, float gain=1.0) {
    //y(n) = 2 * cos(A) * y(n-1) - y(n-2)
    //A= (frequency of interest) * 2 * PI / (sampling frequency)
    //A is in radians.
    // frequency of interest MUST be <= 1/2 the sampling frequency.
    float *tone = new float[length];
    float A = frequency*2*PI/samplerate;
   
    for (int i=0; i<length; i++) {
    if (i > 1) tone[i]= 2*cos(A)*tone[i-1] - tone[i-2];
    else if (i > 0) tone[i] = 2*cos(A)*tone[i-1] - (cos(A));
    else tone[i] = 2*cos(A)*cos(A) - cos(2*A);
    }

    for (int i=0; i<length; i++) tone[i] = tone[i]*gain;
   
    return tone;
}

/** adds whitenoise to a sample */
void *addNoise(float *sample, int length, float gain=1.0) {
    for (int i=0; i<length; i++) sample[i] += (2*(rand()/(float)RAND_MAX)-1)*gain;
}

/** returns the signal power/dB */
float power(float value) {
    return 20*log10(abs(value));
}

int main(int argc, const char* argv) {
    cout << "Samplerate: " << SAMPLERATE << "Hz\n";
    cout << "Buffersize: " << BUFFERSIZE << " samples\n";
    cout << "Correct frequency is: " << FREQUENCY << "Hz\n";
    cout << " - signal volume: " << SIGNALVOLUME*100 << "%\n";
    cout << " - white noise: " << NOISE*100 << "%\n";
   
    float *tone = makeTone(SAMPLERATE, FREQUENCY, BUFFERSIZE, SIGNALVOLUME);
    addNoise(tone, BUFFERSIZE,NOISE);

    int stepsize = FREQUENCY/5;

    for (int i=0; i<10; i++) {
    int freq = stepsize*i;
    cout << "Trying freq: " << freq << "Hz  ->  dB: " << power(goertzel(tone, BUFFERSIZE, freq, SAMPLERATE)) << endl;
    }
    delete tone;
   
    return 0;
}

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
gregoryyoungCommented:
I would also double check your legal source in ohio ... this seems fairly clear cut.

http://www.units.osu.edu/local_phone/harassing.php


Unlawful Use of Telephone Services
Fraudulent use of the telephone system will not be tolerated by Ohio State, or UNITS. This includes:

Unlawful wiretapping

It is a Federal crime to intercept a phone call unless permission is obtained from both parties participating.
Unlawful recording

It is a Federal crime to record a phone conversation without the other party's consent.

Unlawful calling

It is a crime under both Ohio and Federal laws for anyone to make obscene, harassing, or threatening phone calls.

Wire tampering

It is prohibited by University regulations for anyone to tamper with telephone wiring.
rbichonAuthor Commented:
Since this has become a legal debate, go to http://www.nolo.com/article.cfm/objectID/751CFB9F-5A4B-48FB-A85BC08E2D9862E5/111/259/137/ART/ and read the section "The Law of Monitoring". I should mention that this is a business monitoring work related calls.

If you are really interested in Ohio's wiretapping laws, do a search on "Wiretapping and Electronic Surveillance, ORC 2933.51-2933.66".

The resource you gave me is from the Ohio State University, which is not a private business. Different laws probably apply to them.
gregoryyoungCommented:
"I should mention that this is a business monitoring work related calls."

yes you should it makes a world of difference as the expectation of privacy is different.

I was just trying to warn you of possible legal implications of what you are trying to do, as for the rest. I _MAY_ have time this weekend ... If I do; this is intresting enough to make an article out of so I may be inclined to write the code to do this, but if I do it will be in C# (not VB.NET) as its my language of choice and because I have a feeling that the use of unsafe code in the algorithm will make a huge difference in its speed.

It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.