📄 dtmffft.c
字号:
FFTTerm(&pdfts->fs);
}
static BOOL DFWaveInInit(PDFTHREADSTRUCT pdfts,UINT uDeviceID)
{
// Open the wave device...
WAVEFORMATEX wfe=
{
WAVE_FORMAT_PCM, // wFormatTag
DF_NUMCHANNELS, // nChannels
DF_SAMPLESPERSEC, // nSamplesPerSec
DF_AVGBYTESPERSEC, // nAvgBytesPerSec=nBlockAlign*nSamplesPerSec
DF_BLOCKALIGN, //nBlockAlign=(nChannels*wBitsPerSample)/8
DF_BITSPERSAMPLE, // wBitsPerSample
0 //cbSize
};
pdfts->hwi=NULL;
if (!FFTInit(&pdfts->fs,DF_FFTLEN))
{
return FALSE;
}
if (waveInOpen(&pdfts->hwi,uDeviceID,&wfe,(DWORD)DFWaveInCallback,(DWORD)pdfts,CALLBACK_FUNCTION)!=0)
{
DFWaveInTerm(pdfts);
return FALSE;
}
if (!DFQueueInit(pdfts->hwi,&pdfts->dfqs))
{
DFWaveInTerm(pdfts);
return FALSE;
}
waveInStart(pdfts->hwi);
return TRUE;
}
static DWORD WINAPI DFThreadProc(PDFTHREADSTRUCT pdfts)
{
static WORD awBuffer[DF_BUFFERSIZE];
BOOL bFinish=FALSE;
DFTSSetStarted(pdfts,TRUE);
DFTSSetStarting(pdfts,FALSE);
while (!bFinish)
{
DWORD dwTickCount;
BOOL bRedraw=FALSE; // True if we need to post a message to redraw the spectrum.
while (DFQueueGet(pdfts->hwi,&pdfts->dfqs,awBuffer,&dwTickCount)) // Should always be true if we're here
{
// Search the buffer DF_SAMPLESPERSEC / DF_FFTLEN times per sec for a DTMF tone
S32 as32Buffer[DF_FFTLEN/2];
bRedraw=TRUE;
FFTRun(&pdfts->fs,awBuffer,as32Buffer);
EnterCriticalSection(&pdfts->cs);
memcpy(pdfts->as32Buffer,as32Buffer,sizeof(as32Buffer));
LeaveCriticalSection(&pdfts->cs);
// Now figure out if we have any DTMF tones worth talking about...
{
// Array of DTMF bin indices into the FFT table
static const int anDTMFBinX[4]=
{
DF_DTMFBINX0,
DF_DTMFBINX1,
DF_DTMFBINX2,
DF_DTMFBINX3
};
static const int anDTMFBinY[4]=
{
DF_DTMFBINY0,
DF_DTMFBINY1,
DF_DTMFBINY2,
DF_DTMFBINY3
};
int nToneBitmapX=0;
int nToneBitmapY=0;
int nToneX=-1;
int nToneY=-1;
int nCountX=0;
int nCountY=0;
int nBitMap;
int n;
S32 s32AvgX=0;
S32 s32AvgY=0;
S32 s32Avg=0;
S32 s32ThresholdAGC;
int nThreshold=DFTSGetThreshold(pdfts);
static char cLast='\0'; // Last decoded
static char cLastSent='\0'; // Last decoded sent
// Get the average without the first few bins...
for (n=DF_DTMFBINMIN-1;n<=DF_DTMFBINMAX+1;n++)
{
s32Avg+=as32Buffer[n];
}
// Remove the bins for our freqs of interest and for grins
// get the average of the X and Y bins
for (n=0;n<4;n++)
{
s32Avg-=as32Buffer[anDTMFBinX[n]];
s32Avg-=as32Buffer[anDTMFBinY[n]];
s32AvgX+=as32Buffer[anDTMFBinX[n]];
s32AvgY+=as32Buffer[anDTMFBinY[n]];
}
s32Avg=(s32Avg)/(DF_DTMFBINMAX-DF_DTMFBINMIN+3-8);
s32ThresholdAGC=s32Avg*nThreshold/2;
DFTSSetThresholdAGC(pdfts,s32ThresholdAGC);
s32AvgX=s32AvgX*3/4; // We'd like the tones to be significantly over the average
s32AvgY=s32AvgY*3/4;
for (n=0,nBitMap=1;n<4;n++,nBitMap<<=1)
{
if (as32Buffer[anDTMFBinX[n]]>s32ThresholdAGC)
{
nToneBitmapX |= nBitMap;
nToneX=n;
nCountX++;
}
if (as32Buffer[anDTMFBinY[n]]>s32ThresholdAGC)
{
nToneBitmapY |= nBitMap;
nToneY=n;
nCountY++;
}
}
// Pessimistic algorithm - need two successive correct tone decodes the same
if (nCountX==1 && nCountY==1) // Only one tone in each group please
{
static const char aacToneDecode[4][4]=
{
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
char c=aacToneDecode[nToneY][nToneX];
if (pdfts->nLastToneBitmapX==nToneBitmapX && pdfts->nLastToneBitmapY==nToneBitmapY)
{
if (c==cLast)
{
if (cLastSent!=c)
{
PostMessage(pdfts->hdlg,DF_WM_USER_NEWCHAR,(WPARAM)c,(LPARAM)dwTickCount);
cLastSent=c;
}
}
}
cLast=c;
}
else
{
cLast='\0';
cLastSent='\0';
}
/* Optimistic algorithm
if (nCountX==1 && nCountY==1) // Only one tone in each group please
{
if (pdfts->nLastToneBitmapX!=nToneBitmapX || pdfts->nLastToneBitmapY!=nToneBitmapY) // If changed from last time
{
static const char aacToneDecode[4][4]=
{
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
char c=aacToneDecode[nToneY][nToneX];
PostMessage(pdfts->hdlg,DF_WM_USER_NEWCHAR,(WPARAM)c,0);
}
}
*/
pdfts->nLastToneBitmapX=nToneBitmapX;
pdfts->nLastToneBitmapY=nToneBitmapY;
}
DFTSDecWaveBuffers(pdfts);
}
if (bRedraw)
{
PostMessage(pdfts->hdlg,DF_WM_USER_REDRAW,0,0);
}
switch(WaitForSingleObject(pdfts->hevent,100))
{
case WAIT_OBJECT_0:
break;
case WAIT_TIMEOUT:
break;
}
bFinish=DFTSGetFinish(pdfts);
}
DFTSSetStarted(pdfts,FALSE);
DFTSSetFinished(pdfts,TRUE);
pdfts->dwThreadID=0;
pdfts->ht=NULL;
ExitThread(0);
return 0;
}
static void DFThreadTerm(PDFTHREADSTRUCT pdfts)
{
if (DFTSGetStarting(pdfts) || DFTSGetStarted(pdfts))
{
DFTSSetFinished(pdfts,FALSE);
DFTSSetFinish(pdfts,TRUE);
SetEvent(pdfts->hevent);
while (!DFTSGetFinished(pdfts))
{
Sleep(100);
}
}
}
static BOOL DFThreadInit(PDFTHREADSTRUCT pdfts,LONG lDeviceID)
{
BOOL brc=FALSE; // pessimistic return code
if (!DFTSGetStarting(pdfts) && !DFTSGetStarted(pdfts))
{
pdfts->ht=NULL;
pdfts->dwThreadID=0;
pdfts->nLastToneBitmapX=0;
pdfts->nLastToneBitmapY=0;
// Open the wave device...
DFTSSetWaveBuffers(pdfts,0);
if (!DFWaveInInit(pdfts,(UINT)lDeviceID))
{
DFThreadTerm(pdfts);
MessageBox(pdfts->hdlg,"Could not open wave device","DTMF FFT",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// Start the thread...
DFTSSetStarting(pdfts,TRUE);
DFTSSetStarted(pdfts,FALSE);
DFTSSetFinish(pdfts,FALSE);
DFTSSetFinished(pdfts,TRUE);
if ((pdfts->ht=CreateThread(NULL,0,DFThreadProc,(LPVOID)pdfts,0,&pdfts->dwThreadID))==NULL)
{
DFThreadTerm(pdfts);
MessageBox(pdfts->hdlg,"Could not start thread","DTMF FFT",MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
brc=TRUE;
}
return brc;
}
static void DFTerm(PDFTHREADSTRUCT pdfts)
{
// Close thread down...
DFThreadTerm(pdfts);
// Close down WAV handle...
DFWaveInTerm(pdfts);
// Close down event...
CloseHandle(pdfts->hevent);
pdfts->hevent=NULL;
// Close down critical section...
DeleteCriticalSection(&pdfts->cs);
// Delete any font I've created
if (pdfts->hf!=NULL)
{
DeleteObject(pdfts->hf);
pdfts->hf=NULL;
}
// Close the log file
if (pdfts->pf!=NULL)
{
SYSTEMTIME st;
GetSystemTime(&st);
fprintf(pdfts->pf,"DTMFFFT,%04d%02d%02d %02d:%02d:%02d.%03d,UTC,Close \n",st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
fclose(pdfts->pf);
pdfts->pf=NULL;
}
}
static void DFInitSetParameterFields(PDFTHREADSTRUCT pdfts)
{ // Try to get the registry values and fudge factors, and set dialog field texts
int n;
char szKey[30]="NumParameters";
char szVal[30];
// First try to get the number of parameters...
if (!RegGetString(szKey,szVal,sizeof(szVal)))
{
sprintf(szVal,"%d",DF_DEFAULTNUMDLGPARAMETERS);
RegSetString(szKey,szVal);
}
pdfts->nNumDlgParms=atoi(szVal);
for (n=0;n<DF_MAXDLGPARAMETERS;n++)
{
static const int anDlgIDName[DF_MAXDLGPARAMETERS]=
{
IDC_DF_PARAMETER_NAME1,
IDC_DF_PARAMETER_NAME2,
IDC_DF_PARAMETER_NAME3,
IDC_DF_PARAMETER_NAME4,
IDC_DF_PARAMETER_NAME5
};
static const int anDlgIDValue[DF_MAXDLGPARAMETERS]=
{
IDC_DF_PARAMETER_VALUE1,
IDC_DF_PARAMETER_VALUE2,
IDC_DF_PARAMETER_VALUE3,
IDC_DF_PARAMETER_VALUE4,
IDC_DF_PARAMETER_VALUE5
};
static const int anDlgIDUnits[DF_MAXDLGPARAMETERS]=
{
IDC_DF_PARAMETER_UNITS1,
IDC_DF_PARAMETER_UNITS2,
IDC_DF_PARAMETER_UNITS3,
IDC_DF_PARAMETER_UNITS4,
IDC_DF_PARAMETER_UNITS5
};
static const char *aszNameDefault[DF_MAXDLGPARAMETERS]=
{
"Parameter 1",
"Parameter 2",
"Parameter 3",
"Parameter 4",
"Parameter 5"
};
static const char *aszUnitsDefault[DF_MAXDLGPARAMETERS]=
{
"Units 1",
"Units 2",
"Units 3",
"Units 4",
"Units 5"
};
static const double adOffsetDefault[DF_MAXDLGPARAMETERS]=
{
0.0,
0.0,
0.0,
0.0,
0.0
};
static const double adMultiplierDefault[DF_MAXDLGPARAMETERS]=
{
1.0,
1.0,
1.0,
1.0,
1.0
};
pdfts->ddps[n].nDlgIDName=anDlgIDName[n];
pdfts->ddps[n].nDlgIDValue=anDlgIDValue[n];
pdfts->ddps[n].nDlgIDUnits=anDlgIDUnits[n];
strcpy(pdfts->ddps[n].szName,aszNameDefault[n]);
sprintf(szKey,"ParameterName%d",n+1);
if (!RegGetString(szKey,pdfts->ddps[n].szName,DF_DLGSTRINGLEN))
{
RegSetString(szKey,pdfts->ddps[n].szName);
}
SetDlgItemText(pdfts->hdlg,pdfts->ddps[n].nDlgIDName,pdfts->ddps[n].szName);
sprintf(szKey,"ParameterOffset%d",n+1);
if (RegGetString(szKey,szVal,sizeof(szVal)))
{
pdfts->ddps[n].dOffset=atof(szVal);
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -