⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dtmf.cxx

📁 pwlib源码库
💻 CXX
字号:
/* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp * ---------------------------------------------------------------------------- * * Extract DTMF signals from 16 bit PCM audio * * Originally written by Poul-Henning Kamp <phk@freebsd.org> * Made into a C++ class by Roger Hardiman <roger@freebsd.org>, January 2002 * * $Log: dtmf.cxx,v $ * Revision 1.13  2005/01/25 06:35:27  csoutheren * Removed warnings under MSVC * * Revision 1.12  2004/11/17 10:13:14  csoutheren * Fixed compilation with gcc 4.0.0 * * Revision 1.11  2004/09/09 23:50:49  csoutheren * Fixed problem with duplicate definition of sinetab causing problems * * Revision 1.10  2004/09/09 05:23:38  dereksmithies * Add utility function to report on dtmf characters used. * * Revision 1.9  2004/09/09 04:22:46  csoutheren * Added sine table for DTMF encoder * * Revision 1.8  2004/09/09 04:00:01  csoutheren * Added DTMF encoding functions * * Revision 1.7  2003/03/17 07:39:25  robertj * Fixed possible invalid value causing DTMF detector to crash. * * Revision 1.6  2002/02/20 02:59:34  yurik * Added end of line to trace statement * * Revision 1.5  2002/02/12 10:21:56  rogerh * Stop sending '?' when a bad DTMF tone is detected. * * Revision 1.4  2002/01/24 11:14:45  rogerh * Back out robert's change. It did not work (no sign extending) * and replace it with a better solution which should be happy on both big * endian and little endian systems. * * Revision 1.3  2002/01/24 10:40:17  rogerh * Add version log * * */#ifdef __GNUC__#pragma implementation "dtmf.h"#endif#include <ptlib.h>#include <ptclib/dtmf.h>#include <math.h>/* Integer math scaling factor */#define FSC	(1<<12)/* This is the Q of the filter (pole radius) */#define POLRAD .99#define P2 ((int)(POLRAD*POLRAD*FSC))PDTMFDecoder::PDTMFDecoder(){	// Initialise the class	int i,kk;	for (kk = 0; kk < 8; kk++) {		y[kk] = h[kk] = k[kk] = 0;	}	nn = 0;	ia = 0;	so = 0;	for (i = 0; i < 256; i++) {		key[i] = '?';	}	/* We encode the tones in 8 bits, translate those to symbol */	key[0x11] = '1'; key[0x12] = '4'; key[0x14] = '7'; key[0x18] = '*';	key[0x21] = '2'; key[0x22] = '5'; key[0x24] = '8'; key[0x28] = '0';	key[0x41] = '3'; key[0x42] = '6'; key[0x44] = '9'; key[0x48] = '#';	key[0x81] = 'A'; key[0x82] = 'B'; key[0x84] = 'C'; key[0x88] = 'D';	/* The frequencies we're trying to detect */	/* These are precalculated to save processing power */	/* static int dtmf[8] = {697, 770, 852, 941, 1209, 1336, 1477, 1633}; */	/* p1[kk] = (-cos(2 * 3.141592 * dtmf[kk] / 8000.0) * FSC) */	p1[0] = -3497; p1[1] = -3369; p1[2] = -3212; p1[3] = -3027;	p1[4] = -2384; p1[5] = -2040; p1[6] = -1635; p1[7] = -1164;}PString PDTMFDecoder::Decode(const void *buf, PINDEX bytes){	int x;	int s, kk;	int c, d, f, n;	short *buffer = (short *)buf;	PINDEX numSamples = bytes >> 1;	PString keyString;	PINDEX pos;	for (pos = 0; pos < numSamples; pos++) {		/* Read (and scale) the next 16 bit sample */		x = ((int)(*buffer++)) / (32768/FSC);		/* Input amplitude */		if (x > 0)			ia += (x - ia) / 128;		else			ia += (-x - ia) / 128;		/* For each tone */		s = 0;		for(kk = 0; kk < 8; kk++) {			/* Turn the crank */			c = (P2 * (x - k[kk])) / FSC;			d = x + c;			f = (p1[kk] * (d - h[kk])) / FSC;			n = x - k[kk] - c;			k[kk] = h[kk] + f;			h[kk] = f + d;			/* Detect and Average */			if (n > 0)				y[kk] += (n - y[kk]) / 64;			else				y[kk] += (-n - y[kk]) / 64;			/* Threshold */			if (y[kk] > FSC/10 && y[kk] > ia)				s |= 1 << kk;		}		/* Hysteresis and noise supressor */		if (s != so) {			nn = 0;			so = s;		} else if (nn++ == 520 && s < 256 && key[s] != '?') {			PTRACE(3,"DTMF\tDetected '" << key[s] << "' in PCM-16 stream");			keyString += key[s];		}	}	return keyString;}////////////////////////////////////////////////////////////////////////////////////////////////  implement a PCM tone generator////  For reference, the US tones are (as indictated by http://www.elexp.com/t_tele.htm)////   Dial Tone 350 Hz + 440 Hz Continuous //   Ring Back 440 Hz + 480 Hz ON 2.0, OFF 4.0 seconds //   Busy 480 Hz + 620 Hz On 0.5, OFF 0.5 seconds //// this code is based on code copied from http://www-users.cs.york.ac.uk/~fisher/telecom/tones/teletones.C#define   DTMF_LEN  100#ifndef M_PI#define M_PI        3.1415926#endif#define TWOPI	      (2.0 * M_PI)#define MAXSTR	     512#define SAMPLERATE   8000#define SINEBITS     11#define SINELEN	     (1 << SINEBITS)#define TWO32	      4294967296.0	/* 2^32 */static double amptab[2] = { 8191.75, 16383.5 };static inline int ifix(double x) {   return (x >= 0.0) ? (int) (x+0.5) : (int) (x-0.5); }// given frequency f, return corresponding phase increment static inline int phinc(double f){   return ifix(TWO32 * f / (double) SAMPLERATE);}static char dtmfSymbols[16] = {  '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  'A',  'B',  'C',  'D',  '*',  '#'};char PDTMFEncoder::DtmfChar(PINDEX i){  PAssert(i < 16, "Only 16 dtmf symbols. Index too large");  return dtmfSymbols[i];}// DTMF frequencies as per http://www.commlinx.com.au/DTMF_frequencies.htmstatic double dtmfFreqs[16][2] = {  { 941.0, 1336.0 },  // 0  { 697.0, 1209.0 },  // 1  { 697.0, 1336.0 },  // 2  { 697.0, 1477.0 },  // 3  { 770.0, 1209.0 },  // 4  { 770.0, 1336.0 },  // 5  { 770.0, 1477.0 },  // 6  { 852.0, 1209.0 },  // 7  { 852.0, 1336.0 },  // 8  { 852.0, 1477.0 },  // 9  { 697.0, 1633.0 },  // A  { 770.0, 1633.0 },  // B  { 852.0, 1633.0 },  // C  { 941.0, 1633.0 },  // D  { 941.0, 1209.0 },  // *  { 941.0, 1477.0 }   // #};////////////////////////////////////////////////////////////////////////double PDTMFEncoder::sinetab[1 << 11];PMutex & PDTMFEncoder::GetMutex(){  static PMutex mutex;  return mutex;}void PDTMFEncoder::MakeSineTable(){   PWaitAndSignal m(GetMutex());  static BOOL sineTabInit = FALSE;  if (!sineTabInit) {    for (int k = 0; k < SINELEN; k++) {       double th = TWOPI * (double) k / (double) SINELEN;      double v = sin(th);      sinetab[k] = v;    }    sineTabInit = TRUE;  }}void PDTMFEncoder::AddTone(char _digit, unsigned len){  char digit = (char)toupper(_digit);  if ('0' <= digit && digit <= '9')    digit = (char)(digit - '0');  else if ('A' <= digit && digit <= 'D')    digit = (char)(digit + 10 - 'A');  else if (digit == '*')    digit = 14;  else if (digit == '#')    digit = 15;  else    return;  AddTone(dtmfFreqs[(int)digit][0], dtmfFreqs[(int)digit][1], len);}void PDTMFEncoder::AddTone(const PString & str, unsigned len){  PINDEX i;  for (i = 0; i < str.GetLength(); i++)    AddTone(str[i], len);}void PDTMFEncoder::AddTone(double f1, double f2, unsigned ms){  int ak = 0;  MakeSineTable();  PINDEX dataPtr = GetSize();  double amp = amptab[ak];  int phinc1 = phinc(f1), phinc2 = phinc(f2);  int ns = ms * (SAMPLERATE/1000);  unsigned int ptr1 = 0, ptr2 = 0;  for (int n = 0; n < ns; n++) {     double val = amp * (sine(ptr1) + sine(ptr2));    int ival = ifix(val);    if (ival < -32768)      ival = -32768;    else if (val > 32767)       ival = 32767;    if (dataPtr == GetSize())       SetSize(GetSize() + 1024);    (*this)[dataPtr++] = (BYTE)(ival & 0xff);    (*this)[dataPtr++] = (BYTE)(ival >> 8);    ptr1 += phinc1;     ptr2 += phinc2;  }  SetSize(dataPtr);}////////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -