📄 dtmftesc.c
字号:
/*
* Dual-Tone Multi-Frequency Tone Detect/Generate test harness
* Copyright (C) ARM Limited 1998-1999. All rights reserved.
*/
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mtmfc.h"
#include "dtmftesc.h"
#include "bitutilc.h"
#include "custredc.h"
#include "definesc.h"
#include "fileutlc.h"
#include "optionsc.h"
#define DTMF_OPTIONS 2
/* define the DTMF tones */
static const unsigned int DTMFTones[ 8 ] = {
697, /* 1 2 3 A */
770, /* 4 5 6 B */
852, /* 7 8 9 C */
941, /* * 0 # D */
1209, 1336, 1447, 1633
} ;
/* define the DTMF values */
static const unsigned char DTMFValues[16] = {
'1', '2', '3', 'A',
'4', '5', '6', 'B',
'7', '8', '9', 'C',
'*', '0', '#', 'D'
} ;
/* initialise memory for cosine and sines of DTMF tones */
static int DTMFCosines[ 9 ] ;
static int DTMFSines[ 9 ] ;
#define NOISEFACTOR ( 1 << 11 ) /* maximum noise value used to scale random number to 0..NOISEFACTOR */
#define SAMPLINGRATE 8000 /* the sampling rate in Hertz */
#define SHIFT 15 /* the shift of cosine and sine values */
#define TONEDISTINCTION 1 /* the distinction between valid tones and noise */
#define MINMS 8 /* minimum number of milliseconds duration for tone, frequency or frame */
#define FRAMESIZE ( SAMPLINGRATE/1000 )*MINMS /* the default frame size in ms for sampling rate and min duration */
/* define tone generation structure to passing several pieces of information */
typedef struct DTMFToneGenStruct DTMFToneGenStruct ;
typedef DTMFToneGenStruct *DTMFToneGenStructPtr ;
struct DTMFToneGenStruct {
unsigned int toneperiod ;
unsigned int silenceperiod ;
unsigned int period ;
unsigned int hitonelevel ;
unsigned int lotonelevel ;
unsigned int framesize ;
} ;
/* define a type to identify whether to detect a tone or silence */
typedef enum{ TONE, SILENCE } ToneSilence ;
static Boolean DTMFTableGen( int table[ ], unsigned int samplingRate, unsigned int shift, double( *trig )( double ) ) ;
static Boolean DTMFValid( unsigned char dtmfValues[ ], unsigned int nValues ) ;
static short *GenerateDTMFSamples( unsigned char values[ ], unsigned int nValues, DTMFToneGenStructPtr dtmfToneGenStructPtr, Boolean noise, short samples[ ], unsigned int *nSamples ) ;
static void Menu( unsigned int numberOptions ) ;
static void PrintNumberPad( void ) ;
static ToneState *SetDTMFTones( ToneState toneStates[ ], unsigned char value, unsigned int lotonelevel, unsigned int hitonelevel, Boolean noise ) ;
/**** DetectDTMFTone ****************************************************************
*
* Version & Date
* ------- ----
* 1.0.0, 30/06/1998
*
* Description
* -----------
* detect the next DTMF tone or silence in the given set of samples
*
* Inputs
* ------
* samples
* - the set of samples to detect tone or silence in
* nSamples
* - the number of samples in the set to detect tone or silence in
* toneSilence
* - TONE : detect a DTMF tone 0-9, a-d (or A-D), * and #
* SILENCE : detect silence
* toneDistinction
* - the number of bits to right shift the energies to distinguish a tone from
* background noise
* Return Values
* ------ ------
* if TONE
* unsigned char - the tone detected 0-9, A-D, * or #
* 0 - no tone was detected
* if SILENCE
* 1 - silence detected
* 0 - no silence period detected
*
* History (with dates)
* ------- ---- -----
* 1.0.0, 30/06/1998 first release
*
************************************************************************************/
static unsigned char DetectDTMFTone( short samples[ ], unsigned int nSamples, ToneSilence toneSilence, unsigned int toneDistinction )
{
unsigned int loMax = 0 ;
unsigned int hiMax = 0 ;
int loTone = -1 ;
int hiTone = -1 ;
ToneState toneStates[ 8 ] ;
unsigned int energies[ 8 ] ;
unsigned int i ;
unsigned char tone = 0 ;
if( ( !samples ) || ( nSamples == 0 ) ) {
fprintf( stderr, "[DetectDTMFTone] Error in input arguments, aborting.\n\n" ) ;
return 0 ;
}
ToneDetectSetup( toneStates, ( int * )DTMFCosines, 8 ) ;
ToneDetect( samples, nSamples, toneStates, 8 ) ;
ToneDetectResults( energies, 2, toneStates, 8 ) ;
for( i = 0 ; i < 4 ; i += 1 ) {
if( ( energies[ i ] >> toneDistinction ) > loMax ) { /* tone must be (1<<toneDistinction) greater than any other tone */
loMax = energies[ i ] ;
loTone = i ;
}
else if( ( loMax >> toneDistinction ) < energies[ i ] ) { /* energy is within (1<<toneDistinction), previous max tone is not valid tone */
loTone = -1 ;
if( loMax < energies[ i ] ) {
loMax = energies[ i ] ;
}
}
if( ( energies[ i + 4 ] >> toneDistinction ) > hiMax ) {
hiMax = energies[ i + 4 ] ;
hiTone = i ;
}
else if( ( hiMax >> toneDistinction ) < energies[ i + 4 ] ) {
hiTone = -1 ;
if( hiMax < energies[ i + 4 ] ) {
hiMax = energies[ i + 4 ] ;
}
}
}
/* ensure that both tones are close to each other */
if( ( loMax < ( hiMax >> 1 ) ) || ( hiMax < ( loMax >> 1 ) ) ) {
loTone = hiTone = -1 ;
}
tone = 0 ;
if( ( loTone != -1 ) && ( hiTone != -1 ) ) {
if( toneSilence == TONE ) {
tone = DTMFValues[ hiTone + ( loTone << 2 ) ] ;
}
}
else if( toneSilence == SILENCE ) {
tone = 1 ;
}
return tone ;
}
/**** DetectDTMFTones ***************************************************************
*
* Version & Date
* ------- ----
* 1.0.0, 30/06/1998
*
* Description
* -----------
* detect all the tones and silences in the given set of samples
*
* Inputs
* ------
* samples
* - the set of samples to detect tones and silence in
* nSamples
* - the number of samples in the set to detect tones and silence in
* framesize
* - the size of the frame to detect tones in
* must be of sufficient size to allow energies to be accumulated and
* small enough to allow short duration of tone or silence to be detected
* toneDistinction
* - the number of bits to right shift the energies to distinguish a tone from
* background noise
* fulldetails
* - 1 : give samples where tone detected, silence detected or nothing detected
* 0 : only give tones and silence detected and now by which samples or if nothing detected
* dtmfTones
* - an array to hold the tones detected
* maxTones
* - the maximum number of tones that can be detected before array exhausted
* Outputs
* -------
* dtmfTones
* - the tones detected if non-NULL returned
* maxTones
* - the number of tones detected if non-NULL returned
* Return Values
* ------ ------
* unsigned char * - a pointer to dtmfTones if tones detected
* NULL - some error occurred
*
* History (with dates)
* ------- ---- -----
* 1.0.0, 30/06/1998 first release
*
************************************************************************************/
static unsigned char *DetectDTMFTones( short samples[ ], unsigned int nSamples, unsigned int framesize, unsigned int toneDistinction, unsigned int fulldetails, unsigned char dtmfTones[ ], unsigned int *maxTones )
{
ToneSilence toneSilence = TONE ;
unsigned char tone ;
unsigned int i ;
unsigned int j ;
if( ( !samples ) || ( nSamples == 0 ) || ( framesize == 0 ) || ( !dtmfTones ) || ( !maxTones ) || ( *maxTones == 0 ) ) {
fprintf( stderr, "[DetectDTMFTones] Error in input arguments, aborting.\n\n" ) ;
return NULL ;
}
printf( "Using a %ums framesize, the DTMF values detected are :\n\n", ( framesize*1000 )/SAMPLINGRATE ) ;
j = 0 ;
for( i = 0 ; i < nSamples ; i += framesize ) {
if( ( tone = DetectDTMFTone( samples + i, framesize, toneSilence, toneDistinction ) ) != 0 ) {
printf( "\t" ) ;
if( toneSilence == TONE ) {
printf( "'%c' ", tone ) ;
dtmfTones[ j++ ] = tone ;
if( j == *maxTones ) {
break ;
}
toneSilence = SILENCE ;
}
else {
printf( "silence " ) ;
toneSilence = TONE ;
}
if( fulldetails ) {
printf( "in samples %u to %u.\n", i, i + framesize ) ;
}
else {
printf( "\n" ) ;
}
}
}
printf( "\n" ) ;
*maxTones = j ;
return dtmfTones ;
}
/**** DTMF **************************************************************************
*
* Version & Date
* ------- ----
* 1.0.0, 30/06/1998
*
* Description
* -----------
* perform a DTMF generation or detection
*
* generation:
* get user information for DTMF values to generate waveform for, framesize to use
* duration of tones and silence and peak values, generate discrete waveform samples
* and save to a file given by the user
*
* detection:
* read a file given by the user and using the framesize given by the user try to
* detect DTMF values and silence
*
* Inputs
* ------
* option
* - a value that should be between 1 and 2 and returned from a call to NextTask
* the value corresponds to a menu choice and determines whether generating or detecting
* (respectively)
* Return Values
* ------ ------
* TRUE - the process was successful
* FALSE - some error occurred during process (memory problems?)
*
* History (with dates)
* ------- ---- -----
* 1.0.0, 30/06/1998 first release
*
************************************************************************************/
static Boolean DTMF( unsigned int option )
{
DTMFToneGenStruct dtmfToneGenStruct ;
unsigned char dtmfTones[ LIMIT ] ;
unsigned int nTones = LIMIT ;
short *samples = NULL ;
unsigned int framesize = FRAMESIZE ;
unsigned int nSamples ;
unsigned int is2 ;
Boolean noise ;
unsigned int i ;
printf( "Perform DTMF...\n\n" ) ;
if( option == 666 ) {
printf( "Instigating hidden option: generate & detect DTMF.\n\n" ) ;
}
switch( option ) {
case 1 :
case 666 :
do {
printf( "Please give the DTMF values to generate.\n\n" ) ;
PrintNumberPad( ) ;
printf( "Values (0-9, A-D, *, #) : " ) ;
ReadInString( stdin, ( char * )dtmfTones, LIMIT ) ;
printf( "\n" ) ;
} while( !DTMFValid( dtmfTones, strlen( ( char * )dtmfTones ) ) ) ;
break ;
case 2 :
if( ( samples = ( short * )GetData( HWORDBYTES, "DTMF detection", &nSamples ) ) == NULL ) {
return FALSE ;
}
break ;
default :
return TRUE ;
}
switch( option ) {
case 1 :
case 666 :
/* define an example framesize to show multiple calls to generate the samples */
dtmfToneGenStruct.framesize = FRAMESIZE ;
/* get values as power of 2 to ease complexity in detector */
printf( "Please give the duration of the tones.\n\n" ) ;
do {
printf( "Duration of tones (milliseconds, minimum %ums, power of 2) : ", MINMS ) ;
dtmfToneGenStruct.toneperiod = ( int )ReadDouble( ) ;
ISPOWEROF2( dtmfToneGenStruct.toneperiod, is2 ) ;
if( !is2 ) {
fprintf( stderr, "Value '%u' is not a power of 2.\n\n", dtmfToneGenStruct.toneperiod ) ;
}
else if( dtmfToneGenStruct.toneperiod < MINMS ) {
fprintf( stderr, "Value '%u' is less than %u.\n\n", dtmfToneGenStruct.toneperiod, MINMS ) ;
}
else {
break ;
}
} while( 1 ) ;
dtmfToneGenStruct.toneperiod = ( int )( ( ( double )dtmfToneGenStruct.toneperiod/1000.0 )*( double )SAMPLINGRATE + 0.5 ) ;
printf( "Please give the duration of silence between tones.\n\n" ) ;
do {
printf( "Duration of silence (milliseconds, minimum %ums, power of 2) : ", MINMS ) ;
dtmfToneGenStruct.silenceperiod = ( int )ReadDouble( ) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -