📄 main.c
字号:
/*****************************************************************
* Fast Fourie Transformation
******************************************************************
This is only an example how to sample sound with windows
(should work with windows98/2000/Me) and how to apply
a Fouriertransformation.
To keep this code simple I have done/not done the following
1) After a Buffer is filled, I take the content of it and
give the device another Buffer worthwile.(pBuffer1,pBuffer2)
In the time the device fills the buffer, all the transformation
has to be done! Usually you should place this in a thread, but
this would have made this code not as easy to understand.
So keep in mind that you need a faster computer, just try.
2) The FFT itself is standard and not very fast. I adapted the
code from a nice book. It is called FFT from
the German "Oldenburg Verlag", but it is available
in english language as I know.
3) Usually the WaveDevice sends its messages to its own
MessageProcedure. I have not done this to keep it easier.
To understand the wavedevicehandling look up
at msdn.microsoft.com or get
Charles Petzolds Book "Programming Windows".
4) In Charles Petzolds Book Chapter 22 WaveFormAudio you find a
sample code of the SoundRecorder1. Here he explains
how to sample sound and get the Buffer. I startet with this
code and kept most of it for my needs. But it also makes it
easies to understand this code, if you have read this chapter
before.
5) For the AudioDeviceHandling winmm.lib has to be included
6) Your AudioDevice must be able to handle 16bit!
******************************************************************/
#include "FFT.h"
#define QUANTIZATION 16
#define WM_FREQ 1234 // user defined Message for Frequ calculation
// the following #defines are needed, because we append the found
// audiodevices to the menu and assign the following ID's
// with this we can append a maximum of 6 Devices
#define WM_DEV 150
#define WM_DEV1 150
#define WM_DEV2 151
#define WM_DEV3 152
#define WM_DEV4 153
#define WM_DEV5 154
#define WM_DEV6 155
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL CALLBACK SettingsDlgProc (HWND, UINT, WPARAM, LPARAM) ;
TCHAR szAppName [] = TEXT ("FFT Frequency Analyser") ;
TCHAR szOpenError[] = TEXT ("Error opening Audio Device!");
TCHAR szMemError [] = TEXT ("Cannot allocate memory!") ;
TCHAR szAbout[] = TEXT ("Code by Tim Buschmann\nContact me:\nt.buschmann@unidui.uni-duisburg.de");
typedef struct
{
int iSamplesPerSecond,
iNumOfSamples,
iInputBufferSize;
} *PFFT_DATA;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ; // we need Scrollbars
wndclass.lpfnWndProc = MainWndProc ; // Window Procedure
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(IDI_FFT)) ; //Load FFT Icon
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; // Get Cursor
wndclass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH) ; // Load black brush from stock
wndclass.lpszMenuName = MAKEINTRESOURCE(IDM_FFT) ; // Menu
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("Could not init Programm"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // Windows Class Name
szAppName, // Window Name
WS_OVERLAPPEDWINDOW |
WS_MINIMIZEBOX |
WS_HSCROLL |
WS_MAXIMIZEBOX |
WS_BORDER,
CW_USEDEFAULT, // X-Position of Window
0, // Y-Position of Window
320, // Window width
240, // Window height
NULL,
NULL, // Menu
hInstance, //
NULL) ; //
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL bRecording, // Device is recording
bEnding, // Ending to record
bTerminating ; // application shutting down
static HWAVEIN hWaveIn ; // WaveIn DeviceHandle
static PWORD pwTemp;
static PBYTE pBuffer1, // Device Buffer 1
pBuffer2, // Device Buffer 2
pTempBuffer; // Recording Buffer
static PWAVEHDR pWaveHdr1, pWaveHdr2 ; // WaveheadrStructure
static WAVEFORMATEX waveform ; //
static int iDevSel, // Menu Device Selection
iViewSel=0, // Menu View Selection
iTmpRange=0, // Last painted Window Range
iStartPos, // Array Pos to Display in Window left side
iRange = 256; // Array range displayed in Window
static PFFT_DATA pFFT;
HDC hdc ; // Device Context
static HINSTANCE hInstance; // HandleInstance
int i, //
iFreq, // Frequency to display
iNumDev; // Number of Devices
static POINT *apt; //FFT Points to paint
static PFLOAT pfRealBuf, // RealBuffer
pfImagBuf, // ImaginaryBuffer
pfResBuf; // ResultBuffer
static RECT rect; // client rect
WAVEINCAPS DevCaps; // DriverCaps
TCHAR buffer[30]; // WindowTextBuffer
switch (message)
{
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDM_HELP:
DialogBox (hInstance,
MAKEINTRESOURCE(IDD_HELP),
hwnd,
AboutDlgProc) ;
return 0;
case IDM_ABOUT:
MessageBox(hwnd,
szAbout,
TEXT("About"),
MB_OK);
return 0;
case IDM_SETTINGS:
DialogBoxParam (hInstance,
MAKEINTRESOURCE(IDD_SETTINGS),
hwnd,
SettingsDlgProc,
(long)pFFT) ;
//after Settings reset to view 100%
SendMessage(hwnd, WM_COMMAND,(WPARAM)IDM100,(LPARAM)NULL);
// and clear old canvas
InvalidateRect(hwnd,&rect,TRUE);
return 0;
case IDM_EXIT:
SendMessage (hwnd, WM_CLOSE, 0, 0) ;
return 0 ;
// The following Command Zoom in a Section of
// the window. For that we need to update the
// Scrollbar Range.
case IDM100: // 100% View
CheckMenuItem(GetMenu(hwnd),iViewSel,MF_UNCHECKED);
CheckMenuItem(GetMenu(hwnd),IDM100,MF_CHECKED);
iViewSel = IDM100;
iRange = pFFT->iNumOfSamples/2;
iStartPos = 0;
SetScrollRange (hwnd, SB_HORZ, 0,iRange, FALSE) ; // SetNewRange, don't update Bar
SetScrollPos (hwnd, SB_HORZ, iRange/2, TRUE) ; // SetNewPos and update Bar
SendMessage(hwnd, WM_FREQ,0,0);
return 0 ;
case IDM200: // 200% View
CheckMenuItem(GetMenu(hwnd),iViewSel,MF_UNCHECKED);
CheckMenuItem(GetMenu(hwnd),IDM200,MF_CHECKED);
iViewSel = IDM200;
iRange = pFFT->iNumOfSamples/8;
iStartPos = pFFT->iNumOfSamples/4-iRange/2;
SetScrollRange (hwnd, SB_HORZ, 0,pFFT->iNumOfSamples/2, FALSE) ;
SetScrollPos (hwnd, SB_HORZ, pFFT->iNumOfSamples/4, TRUE) ;
SendMessage(hwnd, WM_FREQ,0,0);
return 0 ;
case IDM300:
CheckMenuItem(GetMenu(hwnd),iViewSel,MF_UNCHECKED);
CheckMenuItem(GetMenu(hwnd),IDM300,MF_CHECKED);
iViewSel = IDM300;
iRange = pFFT->iNumOfSamples/16;
iStartPos = pFFT->iNumOfSamples/4-iRange/2;
SetScrollRange (hwnd, SB_HORZ, 0,pFFT->iNumOfSamples/2, FALSE) ;
SetScrollPos (hwnd, SB_HORZ, pFFT->iNumOfSamples/4, TRUE) ;
SendMessage(hwnd, WM_FREQ,0,0);
return 0 ;
case IDM400:
CheckMenuItem(GetMenu(hwnd),iViewSel,MF_UNCHECKED);
CheckMenuItem(GetMenu(hwnd),IDM400,MF_CHECKED);
iViewSel = IDM400;
iRange = pFFT->iNumOfSamples/32;
iStartPos = pFFT->iNumOfSamples/4-iRange/2;
SetScrollRange (hwnd, SB_HORZ, 0,pFFT->iNumOfSamples/2, FALSE) ;
SetScrollPos (hwnd, SB_HORZ, pFFT->iNumOfSamples/4, TRUE) ;
SendMessage(hwnd, WM_FREQ,0,0);
return 0 ;
// The following Commands select the appropiate
// audiodevice:
case WM_DEV1:
case WM_DEV2:
case WM_DEV3:
case WM_DEV4:
case WM_DEV5:
case WM_DEV6:
bEnding = TRUE ;
waveInReset (hWaveIn) ; // reset Wave Device
EnableMenuItem(GetMenu(hwnd),IDM_RSTOP,MF_GRAYED); //Gray out Stop button
EnableMenuItem(GetMenu(hwnd),IDM_RSTART,MF_ENABLED); //enable Start button
SetWindowText(hwnd, TEXT("FFT Frequency Analyser")); // Set WindowName to title again
CheckMenuItem(GetMenu(hwnd),iDevSel+WM_DEV,MF_UNCHECKED); // uncheck old device
iDevSel = LOWORD(wParam)-WM_DEV; // get new DeviceID
CheckMenuItem(GetMenu(hwnd),LOWORD(wParam),MF_CHECKED); // and check it
return 0;
// Recording Start
case IDM_RSTART:
// Now do not allow the settings dialog anymore
// that would be fatal
EnableMenuItem(GetMenu(hwnd),IDM_SETTINGS,MF_GRAYED);
//-------------------------------------
// Now allocate Memory for Buffers
//--------------------------------------
//Buffer for FFT Points to Paint
apt = malloc(pFFT->iInputBufferSize*sizeof(POINT));
// Recording Buffer:
pTempBuffer = malloc(pFFT->iInputBufferSize);
// the FFT creates Values in the pos and neg range
// which are symmetrical to the
// horiziontal Y axis
// we actually only paint the left side
// but we need the full buffer for the fft
// Buffer for RealValues of FFT
pfRealBuf= malloc(pFFT->iInputBufferSize*sizeof(float));
// Buffer for Imaginary Values of FFT
pfImagBuf= malloc(pFFT->iInputBufferSize*sizeof(float));
// Absolute Value result Buffer
pfResBuf = malloc(pFFT->iInputBufferSize*sizeof(float));
// allocate 2 Buffers for AudioDevice
pBuffer1 = malloc (pFFT->iInputBufferSize) ;
pBuffer2 = malloc (pFFT->iInputBufferSize) ;
if(!pfRealBuf ||
!pfImagBuf ||
!pfResBuf ||
!apt ||
!pBuffer1 ||
!pBuffer2 )
{ MessageBeep (MB_ICONEXCLAMATION) ;
MessageBox (hwnd, szMemError, szAppName, MB_ICONEXCLAMATION | MB_OK) ;
return 0;
}
// Else: open AudioDevice for the rocording
waveform.wFormatTag = WAVE_FORMAT_PCM ;
waveform.nChannels = 1 ;
waveform.nSamplesPerSec = pFFT->iSamplesPerSecond ;
waveform.nAvgBytesPerSec = pFFT->iSamplesPerSecond*2;//16bit=2Byte*8kHz
waveform.nBlockAlign = QUANTIZATION/8 ; //16bit/8=2Byte
waveform.wBitsPerSample = QUANTIZATION ; //16 bit per Sample
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -