📄 dtmffft.c
字号:
// DTMFFFT.C (c) 2004 Howard Long (G6LVB), Hanlincrest Ltd. All rights reserved.
// 72 Princes Gate
// London SW7 2PA
// United Kingdom
// howard@hanlincrest.com
// Free for educational and non-profit use. For commercial use please contact the author.
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include "resource.h"
#include "fft.h"
#include "about.h"
#include "parameter.h"
#include "registry.h"
#define DF_NUMCHANNELS 1 // Number of audio channels for calc of buffer size - we're mono, so only 1
#define DF_SAMPLESPERSEC 11025
#define DF_BITSPERSAMPLE 16
#define DF_BLOCKALIGN ((DF_NUMCHANNELS * DF_BITSPERSAMPLE)/8)
#define DF_AVGBYTESPERSEC (DF_BLOCKALIGN * DF_SAMPLESPERSEC)
#define DF_FFTLEN 256
#define DF_TIMEBUFFER 1 // Number of seconds to buffer
#define DF_NUMBUFFERS (DF_TIMEBUFFER * DF_SAMPLESPERSEC / DF_FFTLEN) // Choose enough buffers
#define DF_BUFFERSIZE (DF_FFTLEN * DF_BLOCKALIGN)
#define DF_WM_USER_REDRAW (WM_USER)
#define DF_WM_USER_NEWCHAR (WM_USER+1)
// The size of each FFT bin in Hz
#define DF_BINSIZE ((double)DF_SAMPLESPERSEC / DF_FFTLEN)
// DTMF tones in Hz
#define DF_DTMFTONEX0 1209
#define DF_DTMFTONEX1 1336
#define DF_DTMFTONEX2 1477
#define DF_DTMFTONEX3 1633
#define DF_DTMFTONEY0 697
#define DF_DTMFTONEY1 770
#define DF_DTMFTONEY2 852
#define DF_DTMFTONEY3 941
// DTMF FFT Bin indices
#define DF_DTMFBINX0 ((int)((DF_DTMFTONEX0 / DF_BINSIZE) + 0.5))
#define DF_DTMFBINX1 ((int)((DF_DTMFTONEX1 / DF_BINSIZE) + 0.5))
#define DF_DTMFBINX2 ((int)((DF_DTMFTONEX2 / DF_BINSIZE) + 0.5))
#define DF_DTMFBINX3 ((int)((DF_DTMFTONEX3 / DF_BINSIZE) + 0.5))
#define DF_DTMFBINY0 ((int)((DF_DTMFTONEY0 / DF_BINSIZE) + 0.5))
#define DF_DTMFBINY1 ((int)((DF_DTMFTONEY1 / DF_BINSIZE) + 0.5))
#define DF_DTMFBINY2 ((int)((DF_DTMFTONEY2 / DF_BINSIZE) + 0.5))
#define DF_DTMFBINY3 ((int)((DF_DTMFTONEY3 / DF_BINSIZE) + 0.5))
#define DF_DTMFBINMIN DF_DTMFBINY0
#define DF_DTMFBINMAX DF_DTMFBINX3
#define DF_DTMFBINMINX DF_DTMFBINX0
#define DF_DTMFBINMAXX DF_DTMFBINX3
#define DF_DTMFBINMINY DF_DTMFBINY0
#define DF_DTMFBINMAXY DF_DTMFBINY3
#define DF_DLGSTRINGLEN 30
#define DF_DEFAULTNUMDLGPARAMETERS 3 // Default number of dialog box parameters used
#define DF_MAXDLGPARAMETERS 5 // Maximum number of dialog box parameters possible
typedef struct
{
WAVEHDR wh;
DWORD dwTickCount; // Tick time that queue item was set up
BOOL bBufferReady;
BOOL bWHPrepared;
} DFQUEUEWHSTRUCT, *PDFQUEUEWHSTRUCT;
typedef struct
{
CRITICAL_SECTION cs;
DFQUEUEWHSTRUCT adfqwhs[DF_NUMBUFFERS]; // Pool of wave headers
int anIdx[DF_NUMBUFFERS]; // Queue list of indexes of DFQUEUEWHSTRUCTS
int nHead;
int nTail;
} DFQUEUESTRUCT, *PDFQUEUESTRUCT;
typedef struct
{
int nDlgIDName;
int nDlgIDUnits;
int nDlgIDValue;
char szName[DF_DLGSTRINGLEN];
char szUnits[DF_DLGSTRINGLEN];
double dOffset;
double dMultiplier;
} DFDLGPARAMETERSTRUCT;
typedef struct
{
HWAVEIN hwi;
HWND hdlg;
HFONT hf; // Monospaced font
HANDLE ht; // Thread handle
DWORD dwThreadID; // Thread ID
DFQUEUESTRUCT dfqs; // Queue of wave headers
FILE *pf; // File holding output data
FFTSTRUCT fs; // FFT structure
CRITICAL_SECTION cs;
HANDLE hevent; // Used by application thread to signal FFT thread
BOOL bStarting; // Is thread in the process of starting up?
BOOL bStarted; // Has thread started?
BOOL bFinish; // Used to notify thread to end
BOOL bFinished; // Has thread ended?
S32 as32Buffer[DF_FFTLEN/2];
int nThreshold; // Threshold set by user
S32 s32ThresholdAGC; // Threshold ajusted by AGC and user's threshold setting
int nWaveBuffers; // Number of WAV buffers queued up
int nLastToneBitmapX; // Bitmap of last tone X group
int nLastToneBitmapY; // Bitmap of last tone Y group
int nNumDlgParms; // Number of telemtry parameters (up to DF_MAXDLGPARAMETERS)
DFDLGPARAMETERSTRUCT ddps[DF_MAXDLGPARAMETERS];
} DFTHREADSTRUCT, *PDFTHREADSTRUCT;
static HINSTANCE _hinst=NULL;
static void DFQueueTerm(HWAVEIN hwi,PDFQUEUESTRUCT pdfqs)
{
int n;
for (n=0;n<DF_NUMBUFFERS;n++)
{
if (pdfqs->adfqwhs[n].bWHPrepared)
{
waveInUnprepareHeader(hwi,&pdfqs->adfqwhs[n].wh,sizeof(pdfqs->adfqwhs[n].wh));
pdfqs->adfqwhs[n].bWHPrepared=FALSE;
}
if (pdfqs->adfqwhs[n].wh.lpData!=NULL)
{
free(pdfqs->adfqwhs[n].wh.lpData);
pdfqs->adfqwhs[n].wh.lpData=NULL;
}
}
DeleteCriticalSection(&pdfqs->cs);
}
static BOOL DFQueueInit(HWAVEIN hwi,PDFQUEUESTRUCT pdfqs)
{
int n;
InitializeCriticalSection(&pdfqs->cs);
pdfqs->nHead=0;
pdfqs->nTail=0;
for (n=0;n<DF_NUMBUFFERS;n++) // Initialise NULL pointers first in case
{
pdfqs->adfqwhs[n].wh.lpData=NULL;
pdfqs->adfqwhs[n].bWHPrepared=FALSE;
pdfqs->adfqwhs[n].bBufferReady=FALSE;
pdfqs->anIdx[n]=-1;
}
for (n=0;n<DF_NUMBUFFERS;n++)
{
if ((pdfqs->adfqwhs[n].wh.lpData=malloc(DF_BUFFERSIZE))==NULL)
{
DFQueueTerm(hwi,pdfqs);
return FALSE;
}
pdfqs->adfqwhs[n].wh.dwBufferLength=DF_BUFFERSIZE;
pdfqs->adfqwhs[n].wh.dwFlags=0;
pdfqs->adfqwhs[n].wh.dwUser=(DWORD)n; // So that when given a WAVEHDR, the callback can figure out which one it is.
if (waveInPrepareHeader(hwi,&pdfqs->adfqwhs[n].wh,sizeof(pdfqs->adfqwhs[n].wh))!=0)
{
DFQueueTerm(hwi,pdfqs);
return FALSE;
}
pdfqs->adfqwhs[n].bWHPrepared=TRUE;
waveInAddBuffer(hwi,&pdfqs->adfqwhs[n].wh,sizeof(pdfqs->adfqwhs[n].wh));
}
return TRUE;
}
static BOOL DFQueuePut(PDFQUEUESTRUCT pdfqs,LPWAVEHDR lpwh)
{
// Insert a filled buffer into the queue.
EnterCriticalSection(&pdfqs->cs);
{
int nNext=((pdfqs->nHead)+1) % DF_NUMBUFFERS;
int nIdx=(int)lpwh->dwUser; // User data is index of WAVEHDR item
if (nNext==pdfqs->nTail)
{
LeaveCriticalSection(&pdfqs->cs);
return FALSE; // Overrun!
}
pdfqs->anIdx[pdfqs->nHead]=nIdx;
pdfqs->adfqwhs[nIdx].bBufferReady=TRUE; // Flag as data ready - may be used in future, handy for debugging
pdfqs->adfqwhs[nIdx].dwTickCount=GetTickCount(); // Set a timestamp of when this happened
pdfqs->nHead=nNext;
}
LeaveCriticalSection(&pdfqs->cs);
return TRUE;
}
static BOOL DFQueueGet(HWAVEIN hwi,PDFQUEUESTRUCT pdfqs,PWORD pwData,PDWORD pdwTickCount)
{
int nIdx;
// Pull a buffer from the queue
EnterCriticalSection(&pdfqs->cs);
if (pdfqs->nHead==pdfqs->nTail)
{
LeaveCriticalSection(&pdfqs->cs);
return FALSE; // Nothing in queue to get
}
LeaveCriticalSection(&pdfqs->cs);
memcpy(pwData,pdfqs->adfqwhs[pdfqs->nTail].wh.lpData,DF_BUFFERSIZE);
if (pdwTickCount!=NULL)
{
*pdwTickCount=pdfqs->adfqwhs[pdfqs->nTail].dwTickCount;
}
EnterCriticalSection(&pdfqs->cs);
nIdx=pdfqs->nTail;
pdfqs->adfqwhs[nIdx].bBufferReady=FALSE;
pdfqs->nTail=((pdfqs->nTail)+1) % DF_NUMBUFFERS;
LeaveCriticalSection(&pdfqs->cs);
waveInAddBuffer(hwi,&pdfqs->adfqwhs[nIdx].wh,sizeof(pdfqs->adfqwhs[nIdx].wh));
return TRUE;
}
static void DFTSSetThreshold(PDFTHREADSTRUCT pdfts,int n)
{
EnterCriticalSection(&pdfts->cs);
pdfts->nThreshold=n;
LeaveCriticalSection(&pdfts->cs);
}
static int DFTSGetThreshold(PDFTHREADSTRUCT pdfts)
{
int n;
EnterCriticalSection(&pdfts->cs);
n=pdfts->nThreshold;
LeaveCriticalSection(&pdfts->cs);
return n;
}
static void DFTSSetThresholdAGC(PDFTHREADSTRUCT pdfts,S32 s32)
{
EnterCriticalSection(&pdfts->cs);
pdfts->s32ThresholdAGC=s32;
LeaveCriticalSection(&pdfts->cs);
}
static S32 DFTSGetThresholdAGC(PDFTHREADSTRUCT pdfts)
{
S32 s32;
EnterCriticalSection(&pdfts->cs);
s32=pdfts->s32ThresholdAGC;
LeaveCriticalSection(&pdfts->cs);
return s32;
}
static void DFTSSetStarting(PDFTHREADSTRUCT pdfts,BOOL bStarting)
{
EnterCriticalSection(&pdfts->cs);
pdfts->bStarting=bStarting;
LeaveCriticalSection(&pdfts->cs);
}
static BOOL DFTSGetStarting(PDFTHREADSTRUCT pdfts)
{
BOOL b;
EnterCriticalSection(&pdfts->cs);
b=pdfts->bStarting;
LeaveCriticalSection(&pdfts->cs);
return b;
}
static void DFTSSetStarted(PDFTHREADSTRUCT pdfts,BOOL bStarted)
{
EnterCriticalSection(&pdfts->cs);
pdfts->bStarted=bStarted;
LeaveCriticalSection(&pdfts->cs);
}
static BOOL DFTSGetStarted(PDFTHREADSTRUCT pdfts)
{
BOOL b;
EnterCriticalSection(&pdfts->cs);
b=pdfts->bStarted;
LeaveCriticalSection(&pdfts->cs);
return b;
}
static void DFTSSetFinish(PDFTHREADSTRUCT pdfts,BOOL bFinish)
{
EnterCriticalSection(&pdfts->cs);
pdfts->bFinish=bFinish;
LeaveCriticalSection(&pdfts->cs);
}
static BOOL DFTSGetFinish(PDFTHREADSTRUCT pdfts)
{
BOOL b;
EnterCriticalSection(&pdfts->cs);
b=pdfts->bFinish;
LeaveCriticalSection(&pdfts->cs);
return b;
}
static void DFTSSetFinished(PDFTHREADSTRUCT pdfts,BOOL bFinished)
{
EnterCriticalSection(&pdfts->cs);
pdfts->bFinished=bFinished;
LeaveCriticalSection(&pdfts->cs);
}
static BOOL DFTSGetFinished(PDFTHREADSTRUCT pdfts)
{
BOOL b;
EnterCriticalSection(&pdfts->cs);
b=pdfts->bFinished;
LeaveCriticalSection(&pdfts->cs);
return b;
}
static int DFTSIncWaveBuffers(PDFTHREADSTRUCT pdfts)
{
int n;
EnterCriticalSection(&pdfts->cs);
pdfts->nWaveBuffers++;
n=pdfts->nWaveBuffers;
LeaveCriticalSection(&pdfts->cs);
return n;
}
static int DFTSDecWaveBuffers(PDFTHREADSTRUCT pdfts)
{
int n;
EnterCriticalSection(&pdfts->cs);
pdfts->nWaveBuffers--;
n=pdfts->nWaveBuffers;
LeaveCriticalSection(&pdfts->cs);
return n;
}
static int DFTSGetWaveBuffers(PDFTHREADSTRUCT pdfts)
{
int n;
EnterCriticalSection(&pdfts->cs);
n=pdfts->nWaveBuffers;
LeaveCriticalSection(&pdfts->cs);
return n;
}
static void DFTSSetWaveBuffers(PDFTHREADSTRUCT pdfts,int n)
{
EnterCriticalSection(&pdfts->cs);
pdfts->nWaveBuffers=n;
LeaveCriticalSection(&pdfts->cs);
}
void CALLBACK DFWaveInCallback(HWAVEIN hwi,UINT uMsg,PDFTHREADSTRUCT pdfts,DWORD dwParam1,DWORD dwParam2)
{
if(uMsg==MM_WIM_DATA)
{
DFQueuePut(&pdfts->dfqs,(LPWAVEHDR)dwParam1);
DFTSIncWaveBuffers(pdfts); // Tell thread we have more data
SetEvent(pdfts->hevent);
}
}
static void DFWaveInTerm(PDFTHREADSTRUCT pdfts)
{
DFQueueTerm(pdfts->hwi,&pdfts->dfqs);
if (pdfts->hwi!=NULL)
{
waveInClose(pdfts->hwi);
pdfts->hwi=NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -