�������� Linux Tags
22. ����������
WINDOWS�Ͷ�ý��
��
��ij����������˵����ý�����͸����װ���޹صĺ�ʽ��������öԸ���Ӳ��Ĵ�ȡ�����������ȿ�һ��Ӳ�壬Ȼ���ٿ���Windows��ý��API�Ľṹ��
��ý��Ӳ��
��
������õĶ�ý��Ӳ����Dz��������豸��Ҳ����ƽ����˵����Ч�������������豸����˷�������������������ת��Ϊ��λȡ���������䴢�浽��������ߴ��浽��.WAVΪ�������Ĵŵ������С����������豸��������ת��������������Ա�ͨ��PC�����������š�
��Ч��ͨ��������MIDI�豸��MIDI�Ƿ��Ϲ�ҵ��׼��������λ�����棨Musical Instrument Digital Interface��������Ӳ�岥�������Ի�Ӧ�̵Ķ���λ����ѶϢ��MIDIӲ��ͨ��������ͨ���������ᵽ�����ּ��̵ȵ�MIDI�����豸�ϡ�ͨ�����ⲿ��MIDI�ϳ���Ҳ�ܹ����ӵ���Ч���ϡ�
���ڣ������PC�ϵ�CD-ROM���������߱�������ͨ����CD�������������ƽ����˵�ġ�CD�����������Բ��������豸��MIDI�豸�Լ�CD�����豸�������һ����ʹ���ߵĿ������á��������ơ���ʽ�����һ��
���⼸���ձ�Ķ�ý�塸�豸������Ҫ�����Ӳ�塣Windows��Ѷ�豸��Ҳ����AVI��Ѷ�豸�����Ÿ�����Ϊ.AVI��audio-video interleave��������Ƶ��ñ£©µÄµï¿½Ó°ï¿½ò¶¯»ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ActiveMovie��������Բ���������̬�ĵ�Ӱ������QuickTime��MPEG��PC�ϵ���ʾ����Ҫ�ض���Ӳ����Ð��������Щ��Ӱ��
���и���PCʹ����ʹ��ij��Pioneer����Ӱ��������Sony VISCAϵ��¼��Ӱ������Щ�豸�������в����棬��˿���PC���������ơ�ijЩ��ʾ������һ�ֳ�Ϊ���Ӵ�Ӱ��video in a window�����Ĺ��ܣ��˹�������һ���ⲿ����Ѷ�ź�������Ӧ�ó�ʽһ�������Windows��өĻ�ϡ���Ҳ����Ϊ��һ�ֶ�ý���豸��
API����
��
��Windows�У�API֧Ԯ�Ķ�ý�幦����Ҫ�ֳ��������ϡ�����ͨ����Ϊ���ͽס��͡��߽ס����档
�ͽ׽�����һϵ�к�ʽ����Щ��ʽ�Լ�̵�˵�������׿�ͷ��������/Platform SDK/Graphics and Multimedia Services/Multimedia Reference/Multimedia Functions����߽׺�ʽһ�����г���
�ͽ׵IJ����������������ʽ��������waveIn��waveOut�����ǽ��ڱ��¿�����Щ��ʽ�����⣬���»�������midiOut��ʽ������MIDI����豸����ЩAPI������midiIn��midiStream��ʽ��
���»�ʹ������Ϊtime�ĺ�ʽ����Щ��ʽ�����趨һ���߽����ȵļ�ʱ����ʽ�����ʱ����ʱ������������ܹ���1���롣�˳�ʽ��Ҫ��춲���MIDI���֡��������麯ʽ��������ѹ������Ѷѹ���Լ���������Ѷ���У���ϧ���DZ��²�������Щ��ʽ��
������ע�⵽��ý�庯ʽ�б����߸���������mci�ĺ�ʽ������������ȡý����ƽ��棨MCI��Media Control Interface��������һ���߽׵Ŀ��Ž��棬��춿��ƶ�ý��PC�����еĶ�ý��Ӳ�塣MCI�������ж�ý��Ӳ�嶼���е����������Ϊ��ý������෽�涼�ԴŴ���¼�������豸����/��¼��ʽΪģ�͡���Ϊ�������������򿪡�һ̨�豸���������ԡ�¼������������룩���ߡ����š����������������ҽ�������ԡ��رա��豸��
MCI������Ϊ������ʽ��һ����ʽ�£�������MCI����ѶϢ���������WindowsѶϢ����ЩѶϢ����λԪ�����Ǻ�C���Ͻṹ����һ����ʽ�£�������MCI���������ִ��������ʽ��Ҫ��������������ԣ������Ծ��������ִ�������ʽ����֧Ԯ����Windows API�ĺ�ʽ���ࡣ�ִ�������MCI������춽����о���ѧϰMCI���������Ͼ;�һ�����ӡ�MCI�е��豸���ư���CD������cdaudio�����������죨waveaudio����MIDI��������sequencer����Ӱ������videodisc����vcr��overlay���Ӵ��е������Ƶ����dat��digital audio tape����λʽ¼Ƶ�Ŵ����Լ���λ��Ƶ��digitalvideo����MCI�豸��Ϊ�����͡��͡�����͡��������豸����CD��������ʹ�õ�����������豸���粨�����죩��ʹ�õ�����ʹ�ò�������ʱ����Щ�����ĸ�������.WAV��
��ȡ��ý��Ӳ�����һ�ַ�������DirectX API���������˱���ķ�Χ��
���������߽׶�ý�庯ʽҲֵ��һ�᣺MessageBeep��PlaySound�������ڵ�������ʾ����MessageBeep���š�����̨���ġ���������ָ����������PlaySound�ɲ��Ŵŵ��ϡ��������л�����Ϊ��Դ�����.WAV���������µ����滹���õ�PlaySound��ʽ��
��TESTMCI�о�MCI
��
��Windows��ý������ڣ����忪���׼�����һ����ΪMCITEST��C��ʽ����������ʽд���߽�̸ʽ����MCI���ѧϰ��Щ����Ĺ�����ʽ�������ʽ��������C���԰棬��Ȼ�Ѿ���ʧ�ˡ���ˣ��������½�������������ʽ22-1��ʾ��TESTMCI��ʽ����Ȼ�Ҳ���ΪĿǰ��ʽ����ɵij�ʽ����ʲô���𣬵����ڵ�ʹ���߽��滹��������ǰ��MCITEST��ʽ������û��ʹ�����ڵij�ʽ�롣
��ʽ22-1 TESTMCI TESTMCI.C /*--------------------------------------------------------------------------- TESTMCI.C -- MCI Command String Tester (c) Charles Petzold, 1998 ----------------------------------------------------------------------------*/ #include <windows.h> #include "resource.h" #define ID_TIMER 1 BOOL CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM) ; TCHAR szAppName [] = TEXT ("TestMci") ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { if (-1 == DialogBox (hInstance, szAppName, NULL, DlgProc)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; } return 0 ; } BOOL CALLBACK DlgProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hwndEdit ; int iCharBeg, iCharEnd, iLineBeg, iLineEnd, iChar, iLine, iLength ; MCIERROR error ; RECT rect ; TCHAR szCommand [1024], szReturn [1024], szError [1024], szBuffer [32] ; switch (message) { case WM_INITDIALOG: // Center the window on screen GetWindowRect (hwnd, &rect) ; SetWindowPos (hwnd, NULL, (GetSystemMetrics (SM_CXSCREEN) - rect.right + rect.left) / 2, (GetSystemMetrics (SM_CYSCREEN) - rect.bottom + rect.top) / 2, 0, 0, SWP_NOZORDER | SWP_NOSIZE) ; hwndEdit = GetDlgItem (hwnd, IDC_MAIN_EDIT) ; SetFocus (hwndEdit) ; return FALSE ; case WM_COMMAND: switch (LOWORD (wParam)) { case IDOK: // Find the line numbers corresponding to the selection SendMessage (hwndEdit, EM_GETSEL, (WPARAM) &iCharBeg, (LPARAM) &iCharEnd) ; iLineBeg = SendMessage (hwndEdit, EM_LINEFROMCHAR, iCharBeg, 0) ; iLineEnd = SendMessage (hwndEdit, EM_LINEFROMCHAR, iCharEnd, 0) ; // Loop through all the lines for (iLine = iLineBeg ; iLine <= iLineEnd ; iLine++) { // Get the line and terminate it; ignore if blank * (WORD *) szCommand = sizeof (szCommand) / sizeof (TCHAR) ; iLength = SendMessage (hwndEdit, EM_GETLINE, iLine, (LPARAM) szCommand) ; szCommand [iLength] = '\0' ; if (iLength == 0) continue ; // Send the MCI command error = mciSendString (szCommand, szReturn, sizeof (szReturn) / sizeof (TCHAR), hwnd) ; // Set the Return String field SetDlgItemText (hwnd, IDC_RETURN_STRING, szReturn) ; // Set the Error String field (even if no error) mciGetErrorString (error, szError, sizeof (szError) / sizeof (TCHAR)) ; SetDlgItemText (hwnd, IDC_ERROR_STRING, szError) ; } // Send the caret to the end of the last selected line iChar = SendMessage (hwndEdit, EM_LINEINDEX, iLineEnd, 0) ; iChar += SendMessage (hwndEdit, EM_LINELENGTH, iCharEnd, 0) ; SendMessage (hwndEdit, EM_SETSEL, iChar, iChar) ; // Insert a carriage return/line feed combination SendMessage (hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) TEXT ("\r\n")) ; SetFocus (hwndEdit) ; return TRUE ; case IDCANCEL: EndDialog (hwnd, 0) ; return TRUE ; case IDC_MAIN_EDIT: if (HIWORD (wParam) == EN_ERRSPACE) { MessageBox (hwnd, TEXT ("Error control out of space."), szAppName, MB_OK | MB_ICONINFORMATION) ; return TRUE ; } break ; } break ; case MM_MCINOTIFY: EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_MESSAGE), TRUE) ; wsprintf (szBuffer, TEXT ("Device ID = %i"), lParam) ; SetDlgItemText (hwnd, IDC_NOTIFY_ID, szBuffer) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_ID), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_SUCCESSFUL), wParam & MCI_NOTIFY_SUCCESSFUL) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_SUPERSEDED), wParam & MCI_NOTIFY_SUPERSEDED) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_ABORTED), wParam & MCI_NOTIFY_ABORTED) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_FAILURE), wParam & MCI_NOTIFY_FAILURE) ; SetTimer (hwnd, ID_TIMER, 5000, NULL) ; return TRUE ; case WM_TIMER: KillTimer (hwnd, ID_TIMER) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_MESSAGE), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_ID), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_SUCCESSFUL), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_SUPERSEDED), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_ABORTED), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_FAILURE), FALSE) ; return TRUE ; case WM_SYSCOMMAND: switch (LOWORD (wParam)) { case SC_CLOSE: EndDialog (hwnd, 0) ; return TRUE ; } break ; } return FALSE ; }
TESTMCI.RC ��ժ¼�� //Microsoft Developer Studio generated resource script. #include "resource.h" #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// // Dialog TESTMCI DIALOG DISCARDABLE 0, 0, 270, 276 STYLE WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "MCI Tester" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_MAIN_EDIT,8,8,254,100,ES_MULTILINE | ES_AUTOHSCROLL | WS_VSCROLL LTEXT "Return String:",IDC_STATIC,8,114,60,8 EDITTEXT IDC_RETURN_STRING,8,126,120,50,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_GROUP | NOT WS_TABSTOP LTEXT "Error String:",IDC_STATIC,142,114,60,8 EDITTEXT IDC_ERROR_STRING,142,126,120,50,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | NOT WS_TABSTOP GROUPBOX "MM_MCINOTIFY Message",IDC_STATIC,9,186,254,58 LTEXT "",IDC_NOTIFY_ID,26,198,100,8 LTEXT "MCI_NOTIFY_SUCCESSFUL",IDC_NOTIFY_SUCCESSFUL,26,212,100, 8,WS_DISABLED LTEXT "MCI_NOTIFY_SUPERSEDED",IDC_NOTIFY_SUPERSEDED,26,226,100, 8,WS_DISABLED LTEXT "MCI_NOTIFY_ABORTED",IDC_NOTIFY_ABORTED,144,212,100,8, WS_DISABLED LTEXT "MCI_NOTIFY_FAILURE",IDC_NOTIFY_FAILURE,144,226,100,8, WS_DISABLED DEFPUSHBUTTON "OK",IDOK,57,255,50,14 PUSHBUTTON "Close",IDCANCEL,162,255,50,14 END
RESOURCE.H ��ժ¼�� // Microsoft Developer Studio generated include file. // Used by TestMci.rc #define IDC_MAIN_EDIT 1000 #define IDC_NOTIFY_MESSAGE 1005 #define IDC_NOTIFY_ID 1006 #define IDC_NOTIFY_SUCCESSFUL 1007 #define IDC_NOTIFY_SUPERSEDED 1008 #define IDC_NOTIFY_ABORTED 1009 #define IDC_NOTIFY_FAILURE 1010 #define IDC_SIGNAL_MESSAGE 1011 #define IDC_SIGNAL_ID 1012 #define IDC_SIGNAL_PARAM 1013 #define IDC_RETURN_STRING 1014 #define IDC_ERROR_STRING 1015 #define IDC_DEVICES 1016 #define IDC_STATIC -1
�뱾�µĴ������ʽһ����TESTMCIʹ�÷�ģ̬�Ի�������Ϊ�������Ӵ����뱾�����еij�ʽһ����TESTMCIҪ��WINMM.LIB���ó�ʽ����Microsoft Visual C++��Projects Settings���Ի�����ġ�Links��ҳ�г���
�˳�ʽ�õ�����������Ҫ�Ķ�ý�庯ʽ��mciSendString��mciGetErrorText����TESTMCI�����à¼ï¿½Ó´ï¿½ï¿½ï¿½ï¿½ï¿½Ò»Ð©ï¿½ï¿½ï¿½ï¿½È»ï¿½á°´ï¿½ï¿½Enter������OK����ť���ᣬ��ʽ��������ִ���Ϊ��һ���������ݸ�mciSendString���
error = mciSendString (szCommand, szReturn, sizeof (szReturn) / sizeof (TCHAR), hwnd) ;
����ڱà¼ï¿½Ó´ï¿½Ñ¡ï¿½ï¿½ï¿½Ë²ï¿½Ö¹Ò»ï¿½Ð£ï¿½ï¿½ï¿½ï¿½Ê½ï¿½ï¿½ï¿½ï¿½Ë³ï¿½ï¿½ï¿½ï¿½ï¿½Ç·ï¿½ï¿½Í¸ï¿½mciSendString��ʽ���ڶ����������ִ�λַ�����ִ�ȡ�ôӺ�ʽ���ص���Ѷ����ʽ������Ѷ��ʾ���Ӵ��ġ�Return String�����ò¡£´ï¿½mciSendString���صĴ�����봫�ݸ�mciGetErrorString��ʽ���Ի�����ִ���˵������˵����ʾ��TESTMCI�Ӵ��ġ�Error String������
MCITEXT��CD����
��
ͨ������CD-ROM�������Ͳ�������CD�������MCI�����ִ����ºܺõ�ӡ����Ϊ��Щ�����ִ�һ�㶼�dz��򵥣����Ҹ���Ҫ��������������һЩ���֣��������Ǻõ���㡣��������/Platform SDK/Graphics and Multimedia Services/Multimedia Reference/Multimedia Command Strings�л��MCI�����ִ��IJο����Է��㱾��ϰ��
��ȷ��CD-ROM��������������������ᵽ�������������Ȼ�����һ������CD����Bruce Springsteen�ġ�Born to Run����Windows 98�У���CD���ų�ʽ������������ʼ���Ŵ˳�Ƭ������������Ļ�����ֹ��CD���ų�ʽ����Ȼ����Խг�TESTMCI���Ҽ������
open cdaudio
Ȼ�ᰴEnter��������open��MCI���cdaudio��MCI�϶���CD-ROM���������豸���ƣ��ٶ�����ϵͳ��ֻ��һ��CD-ROM��������Ҫ��ö��CD-ROM������������ʹ��sysinfo�����
TESTMCI�еġ�Return String��������ʾmciSendString��ʽ��ϵͳ���ظ���ʽ���ִ������ִ����open������ֵ��1��TESTMCI�ڡ�Error String����������ʾmciGetErrorString����mciSendString����ֵ�����ص���Ѷ�����mciSendStringû�д��ش�����룬��Error String��������ʾ����"The specified command was carried out"��
�ٶ�ִ����open������ھͿ������룺
play cdaudio
CD����ʼ���ų�Ƭ�ϵĵ�һ��������Thunder Road����������������������ͣ���ţ�
pause cdaudio
����
stop cdaudio
���CD�����豸��˵����Щ�����Ĺ�����ͬ��������������������²��ţ�
play cdaudio
����Ϊֹ������ʹ�õ�ȫ���ִ�����������豸������ɡ�������Щ�������ѡ����磬���룺
status cdaudio position
��������ʱ��ij��̣���Return String��������ʾ���������һЩ��Ԫ��
01:15:25
����Щʲô������Ȼ����Сʱ�����Ӻ��룬��ΪCDû����ô����Ҫ�ҳ�ʱ���ʽ������룺
status cdaudio time format
���ڡ�Return String��������ʾ������ִ���
msf
���������-��-�񡹡�CD�����У�ÿ����75��ʱ���ʽ��Ѷ�񲿷ֿ���0��74֮��ķ�Χ�ڱ仯��
״̬������һ������ѡ�ʹ����������������ȷ��msf��ʽ��CDȫ�����ȣ�
status cdaudio length
��춡�Born to Run������Return String��������ʾ��
39:28:19
��ָ����39��28��19��
������һ��
status cdaudio number of tracks
��Return String��������ʾ��
8
���Ǵ�CD������֪����Born to Run��CD�ϵ�������������������MCI�����е�������1��ʼ��š�Ҫ��֪��������Born to Run���ij��ȣ����Լ�����������
status cdaudio length track 5
��Return String��������ʾ��
04:30:22
���ǻ���ȷ�������������ϵ��ĸ�λ�ÿ�ʼ��
status cdaudio position track 5
��Return String��������ʾ��
17:36:35
����������Ѷ�����ǿ���ֱ�������������⣺
play cdaudio from 17:36:35 to 22:06:57
������ֻ����һ��������Ȼ��ֹͣ�������ֵ����4:30:22���������ȣ���17:36:35�õ��ġ����ߣ�Ҳ���������������ȷ����
status cdaudio position track 6
���ߣ�Ҳ���Խ�ʱ���ʽ�趨Ϊ����-��-��-��
set cdaudio time format tmsf
Ȼ��
play cdaudio from 5:0:0:0 to 6:0:0:0
���ߣ����򵥵�
play cdaudio from 5 to 6
���ʱ���β����0����ô����ȥ�����ǡ��������ú����趨ʱ���ʽ��
ÿ��MCI�����ִ����������ִ����������ѡ��wait��notify��������ͬʱʹ�ã������磬������ֻ�벥�š�Born to Run����ǰ10�룬���Ҳ����ᣬ�������ó�ʽ����������������ɰ�����ķ������У��ٶ����Ѿ���ʱ���ʽ�趨Ϊtmsf����
play cdaudio from 5:0:0 to 5:0:10 wait
��������£�ֱ����ʽִ�н�����Ҳ����˵��ֱ�������꡸Born to Run����ǰ10�룬mciSendString��ʽ�Ŵ��ء�
���ں����ԣ�һ����˵���ڵ�ִ������Ӧ�ó�ʽ���ⲻ��һ�����¡������С�ļ��룺
play cdaudio wait
ֱ��������Ƭ���������ᣬmciSendString��ʽ�Ž�����Ȩ���ظ���ʽ���������ʹ��waitѡ���ֻҪִ��MCI�����������������������ʱ����ô���ܷ��㣬���ҽ�չʾ��һ����������ʹ��break�����������趨һ��������룬���뽫�ж�mciSendString���������Ȩ���ظ���ʽ�����磬Ҫ�趨Escape����ʵ����Ŀ�ģ����ã�
break cdaudio on 27
���27��ʮ��λ��VK_ESCAPEֵ��
��waitѡ����õ���notifyѡ�
play cdaudio from 5:0:0 to 5:0:10 notify
��������£�mciSendString��ʽ�������أ�������ò�����MCI�����β�����壬��mciSendString��ʽ������һ��������ָ�����ŵ��Ӵ����յ�MM_MCINOTIFYѶϢ��TESTMCI��ʽ��MM_MCINOTIFY������ʾ��ѶϢ�Ľ����Ϊ�������������ܼ�������������TESTMCI��ʽ��5����ֹͣ��ʾMM_MCINOTIFYѶϢ�Ľ����
������ͬʱʹ��wait��notify�ؼ��֣���û��������ô������ʹ���������ؼ��֣��ڶ��IJ����ͼȲ���wait��Ҳ������ͨ����ϣ����notify��
����Щ�����������ʱ���ɼ��������������ֹͣCD��
stop cdaudio
����ڹر�֮ǰû��ֹͣCD-ROM�豸����ô�����ڹر��豸֮�ỹ���������CD��
���⣬����������������Ӳ���������߲�������һЩ���
eject cdaudio
���ᰴ����ķ����ر��豸��
close cdaudio
��ȻTESTMCI�Լ����ܴ�����������ֵ������������ڱà¼ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½Í¼ï¿½ï¿½ï¿½ï¿½ï¿½Ö®ï¿½ä¸´ï¿½ï¿½ï¿½ï¿½ï¿½Ö£ï¿½ï¿½È´ï¿½TESTMCIѡ��һЩ���ݣ����临�Ƶ�����������Ctrl-C�����ٽ���Щ���ִӼ��������Ƶ������±�����Ȼ�ᴢ�档�෴�IJ��������Խ�һϵ�е�MCI�������뵽TESTMCI�����ѡ����һϵ������Ȼ�ᰴ�¡�OK����ť������Enter��������TESTMCI��ÿ��ִ��һ����������������дMCI�ġ���������������MCI����ļ��б���
���磬����������������Jungleland������Ƭ�е�����һ�ף�����Thunder Road���͡�Born to Run������Ҫ����˳���������Ա�д���µ��������
open cdaudio set cdaudio time format tmsf break cdaudio on 27 play cdaudio from 8 wait play cdaudio from 1 to 2 wait play cdaudio from 5 to 6 wait stop cdaudio eject cdaudio close cdaudio
����wait�ؼ��֣��Ͳ���������������ΪmciSendString������������أ�Ȼ��ִ����һ�����
��ʱ����α�дģ��CD���ų�ʽ�ļ�Ӧ�ó�ʽ����Ӧ���൱����ˡ���ʽ����ȷ������������ÿ�������ij��Ȳ�����ʾ����ʹ���ߴ�����λ�ÿ�ʼ���ţ����������ס��mciSendString���Ǵ��������ִ���Ѷ���������Ҫ��д����������ʽ������Щ�ִ�ת�������֣������Կ϶��������ij�ʽ��Ҫʹ��Windows��ʱ�����Բ�����Լ1���ʱ��������WM_TIMERѶϢ�����ڼ䣬��ʽ�����У�
status cdaudio mode
���鿴CD����ͣ�����ڲ��š�
status cdaudio position
����������ʽ������ʾ�Ը�ʹ������ʾĿǰ��λ�á������ܻ����ڸ����˸���Ȥ���£������ʽ֪�������������ֵĽ���λ�ã���ô�Ϳ���ʹөĻ�ϵ�ͼ����CDͬ������������ָ����߽����Լ���ͼ��������Ѷ��ʽ��Ϊ���á�
��������
��
������������õ�Windows��ý�����ԡ����������豸����ͨ����˷粶׽������������ת��Ϊ��ֵ��Ȼ������Ǵ��浽��������ߴŵ��ϵIJ��ε����У����ε����ĸ�������.WAV�������������Ϳ��Բ����ˡ�
�����벨��
��
�ڽӴ���������API֮ǰ���߱�һЩԤ��֪ʶ����Ҫ����Щ֪ʶ��������ѧ�������Լ������������Եij���
���������񶯡��������ı��˹�Ĥ�Ͽ�����ѹ��ʱ�����Ǿ͸о�������������˷���Ը�Ӧ��Щ�񶯣����ҽ�����ת��Ϊ������ͬ���������پ����Ŵ����������������ֱ������������ͳ�ϣ���������ȷ�ʽ���棨����¼���Ŵ��ͳ�Ƭ������Щ�񶯴����ڴ�������������������С�������ת��Ϊ����ʱ���Ϳ�������ʱ���񶯵IJ�������ʾ��������Ȼ����ʽ���������Ҳ���ʾ������һ��������ͼ5-5��ʾ��
���Ҳ������������������Ҳ����һ�������е�����������Ƶ�ʡ�������֪�������������Ƶ�ʾ���������һ����˵�˶��ɸ��ܵ����Ҳ��ķ�Χ�Ǵ�20Hz��ÿ�����ڣ��ĵ�Ƶ������20,000Hz�ĸ�Ƶ����������������������Ը�Ƶ�����ĸ��������������˻���
�˸���Ƶ�ʵ�������Ƶ���Ƕ�����ϵ���������Թ�ϵ��Ҳ����˵�����Ǹ���20Hz��40Hz��Ƶ�ʱ仯�����40Hz��80Hz��Ƶ�ʱ仯��һ���ġ��������У����ּӱ���Ƶ�ʶ���Ϊ�˶����ס���ˣ��˶��ɸо�����Լ10���˶����׵����������ٵķ�Χ�Ǵ�27.5 Hz��4186 Hz֮�䣬��С�7���˶����ס�
��Ȼ���Ҳ��������񶯵Ĵ������Ȼ��ʽ���������Ҳ���������ʵ�����е������֣����ң������Ҳ�����������������������ܸ��ӡ�
�κ����ڵIJ��Σ�����һ����Ȧ���Σ����Էֽ�ɶ�����Ҳ�����Щ���Ҳ���Ƶ�ʶ������������������ν��Fourier���������Է�����ѧ�Һ�����ѧ��Jean Baptiste Joseph Fourier��1768-1830�����������������ڵ�Ƶ���ǻ������������������Ҳ���Ƶ���ǻ���Ƶ�ʵ�2����3����4�����ȵȣ�����ЩƵ�ʵ�������Ϊ����������Ƶ��Ҳ����һ��г������һ�����Ƕ���г�����Դ����ơ�
���Ҳ�г�������ǿ�ȸ�ÿ�����ڵIJ���Ψһ������������ǡ����ʡ�����ʹ�����ȴ��������������ٵ�����������
����һ����Ϊ���Ӻϳ�����������Ҫ�������ֽ��г�������������Ҳ����鼴�ɡ���������ʵ֤����ʵ�����е�������������ô�򵥡�������ʵ�����������IJ��ζ�û���ϸ�����ڡ�����֮��г�������ǿ���Dz�ͬ�ģ�����г��Ҳ����ÿ������������ʱ��ı䡣�ر����������������Ŀ�ʼλ�ã����dz������ࣨattack�����൱���ӣ������λ���ֶ����Ǹ�������������Ҫ��
��춽�������λ������������ߣ����ǿ��Խ�����ֱ������λ��ʽ��������ø��ӵ����顣
���������ƣ�Pulse Code Modulation��
��
���Դ���������ֵ�����Ҫʹ����������ԣ��ͱ������һ���ܽ���������λ�ź��໥ת���Ļ��ơ�
��ѹ�����Ͼ���ɴ˹��ܵ���÷������������������ơ���PCM��pulse code modulation����PCM�����ڹ������λʽ¼���Ŵ��Լ�Windows�С�������������ʵֻ��һ�ָ����Ϻܼ򵥵Ĵ����������ִ����ʶ��ѡ�
�������������ƣ����ο��԰��̶�������Ƶ��ȡ������Ƶ��ͨ����ÿ�뼸��Ρ����ÿ�������������䲨�ε��������ɽ����ת������λ�źŹ�����Ӳ���������λת������ADC��analog-to-digital converter�������Ƶأ�ͨ����λ���ת������DAC��digital-to-analog converter���ɽ���λ�ź�ת���ز��ε����źš�������ת���õ��IJ���������IJ�����ȫ��ͬ���ϳɵIJ��ξ����ɸ�Ƶ��ɵļ����Ե����ˣ�����Ӳ��ͨ������λ���ת�����ỹ����һ����ͨ�˲��������˲����˵���Ƶ����ʹ�ϳ���IJ��θ�ƽ����������ˣ���ͨ�˲���λ�ADCǰ�档
����������������������ȡ��Ƶ�ʣ���ÿ���ڲ�����������Ĵ�����������С������춴����������λԪ�������������һ����ȡ��Ƶ��Խ�ߣ�������СԽ��Ôʼ�����ĸ���Ʒ�Ÿ��á�����������һ�����ȡ��Ƶ�ʺ�������С�ļ��㣬�����������Ҳ�ͳ���������ֱ������ļ��ޡ����⣬���ȡ��Ƶ�ʺ�������С���ͣ������²��ܾ�ȷ�ظ��������Լ�����������
ȡ��Ƶ��
��
ȡ��Ƶ�ʾ��������ɱ���λ���ʹ�������Ƶ�ʡ������ǣ�ȡ��Ƶ�ʱ����������������Ƶ�ʵ�����������ǡ�NyquistƵ�ʣ�Nyquist Frequency��������30����о�ȡ������Ĺ���ʦHarry Nyquist������������
�Թ��͵�ȡ��Ƶ�ʶ����Ҳ�ȡ��ʱ���ϳɵIJ��α�����IJ���Ƶ�ʸ��͡��������˵��ʧ���źš�Ϊ����ʧ���źŵķ������������ʹ�õ�ͨ�˲�������ֹƵ�ʴ�춰��ȡ��Ƶ�ʵ����в��Ρ�������ˣ���λ���ת���������ĴֲڵIJ��α�Եʵ��������Ƶ�ʴ�춰��ȡ��Ƶ�ʵIJ�����ɵķ�������ˣ�λ�����˵ĵ�ͨ�˲���Ҳ��ֹƵ�ʴ�춰��ȡ��Ƶ�ʵ����в��Ρ�
����CD��ʹ�õ�ȡ��Ƶ����ÿ��44,100�����������߳�Ϊ44.1kHz��������е���ֵ�����������ģ�
�˶����������20kHz�����������Ҫ������������������������Χ������Ҫ40kHz��ȡ��Ƶ�ʡ�Ȼ������춵�ͨ�˲�������Ƶ���»�ЧӦ������ȡ��Ƶ��Ӧ���ٸ߳���Լ�ٷ�֮ʮ���С����ڣ�ȡ��Ƶ�ʾʹﵽ��44kHz����ʱ������Ҫ����Ѷͬʱ��¼��λ���������ȡ��Ƶ�ʾ�Ӧ����������ŷ�޵�����ʾ�����ʵ�����������������Ѷ�����ʷֱ���30Hz��25Hz�����ʹȡ��Ƶ�����ߵ���44.1kHz��
ȡ��Ƶ��Ϊ44.1kHz�Ĺ����������������ϣ�����һЩӦ�ó�ʽ��˵ʵ����̫���ˣ�������¼������������¼������ʱ������������ȡ��Ƶ�ʼ��뵽22.05 kHz������һ��10 kHz�ķ������򻯸����������ϰ벿�֡��ٽ�����뵽11.025 kHz���������ṩ��5 kHzƵ�ʷ�Χ��44.1 kHz��22.05 kHz��11.025 kHz��ȡ��Ƶ�ʣ��Լ�8 kHz���Dz��������豸�ձ�֧Ԯ�ı�׼��
��Ϊ���ٵ����Ƶ��Ϊ4186 Hz�����������ܻ���Ϊ������¼��ʱ��11.025 kHz��ȡ��Ƶ�ʾ��㹻�ˡ���4186 Hzֻ�Ǹ�����ߵĻ���Ƶ�ʶ��ѣ��˵����5000Hz���������Ҳ������ٿɱ����Ƶķ����������������ܾ�ȷ�ز�׽�͸��Ƹ��ٵ�������
������С
��
���������Ƶĵڶ��������ǰ�λԪ�����������С��������С�����˿ɹ�¼�ƺͲ��ŵ�������������֮������������ͨ����˵�Ķ�̬��Χ��
����ǿ���Dz��������ƽ������ÿ�����Ҳ�һ���������������ĺϳɣ�����Ƶ��һ�����˶�����ǿ�ȵĸ���Ҳ�ʶ����仯��
����������ǿ���ϵ��������Ա������Ե绰������Alexander Graham Bell�������������ͷֱ���dB��Ϊ��λ���в����ġ�1����������ǿ���ϳ�10�����ӡ�1dB��������ͬ�ij˷������Ϊ1������ʮ��֮һ���ɴˣ�1dB����������ǿ�ȵ�1.26����10��10�η��������������Ӳ��������1.12����10��20�η�������1�ֱ��Ƕ���ɸо�������ǿ����С�仯���ӿ�ʼ���������������޵����˸е���ʹ����������֮�����ǿ���Լ��100 dB��
��������Ĺ�ʽ����������������Ķ�̬��Χ����λ�Ƿֱ���
��
����A1��A2�������������������Ϊֻ������һ�����������������С��1λԪ����̬��Χ��0��
���������С��8λԪ��������������С���֮��ı�������256����������̬��Χ���ǣ�
��
����48�ֱ���48�Ķ�̬��Χ��Լ�൱춷dz������ķ�����綯��ݻ�֮��IJ�𡣽�������С�ӱ���16λԪ�����Ķ�̬��Χ�ǣ�
��
����96�ֱ�����dz��ӽ��������޺���ʹ���ޣ�����������Ϊ����Ǹ������ֵ�����ֵ��
Windowsͬʱ֧Ԯ8λԪ��16λԪ��������С������8λԪ������ʱ����������������λԪ�鴦��������������Ϊһ��ֵΪ0x80���ִ���16λԪ�������Դ�������������������ʱ����������Ϊһ��ֵΪ0���ִ���
Ҫ����δѹ����������Ĵ���ռ䣬��������Ϊ��λ����������ʱ�����ȡ��Ƶ�ʡ������16λԪ����������8λԪ����������ӱ��������¼�����������ټӱ������磬1Сʱ��CD��������������ÿ������������ռ2λԪ�顢ÿ��44 ,100���������ٶ��½���3 600�룩��Ҫ635MB�����Ҫ�ӽ�һ��CD-ROM�Ĵ������ˡ�
�������в������Ҳ�
��
��춵�һ����춲�����������ϰ�����Dz����㽫�������浽�����л򲥷�¼�Ƶ����������ǽ�ʹ�õͽ׵IJ�������API������������waveOut�ĺ�ʽ��������һ������SINEWAVE���������Ҳ����������˳�ʽ��1 Hz�����������ɴ�20Hz���˿ɸо������ֵ����5,000Hz�����˸о������ֵ��������˶����ף������Ҳ���
����֪������׼Cִ��ʱ�ڳ�ʽ�������һ��sin��ʽ���ú�ʽ����һ�����Ƚǵ�����ֵ��2�л��ȵ��360�ȣ���sin��ʽ����ֵ�ķ�Χ�Ǵ�-1��1�����ڵ����£����Ǿ���SINEWAVE��ʽ��ʹ�ù������ʽ������ˣ�Ӧ�ú�����ʹ��sin��ʽ�����������������Ӳ������Ҳ����ϡ����������ô������Σ���ʱ�����Ҳ�������������仺�����������˻��������ݸ�API�������ǰ����������΢��Щ���ӣ����ҽ���ϸ���ܣ�����������Ӳ�岥���껺�����е������ᣬӦ���ڶ����������е����ϴ��ݸ����������Դ����ơ�
��һ�ο���������⣨���Ҷ�PCMҲһ����֪��ʱ������Ż���Ϊ��һ�����ڵ����Ҳ��ֳ����ɹ̶�����������������360�����ź��������20 Hz�����Ҳ���ÿ�����7,200�����������200 Hz�����Ҳ���ÿ����Ҫ���72,000�����������п���ʵ������ʵ����ȴ������ô�������5,000 Hz�����Ҳ�������Ҫÿ�����1,800,000�����������ȷ������DAC�ĸ���������Ҫ���ǣ���춸��ߵ�Ƶ�ʣ������������ʵ����Ҫ�ľ�ȷ�Ȼ��ߡ�
�����������ƶ��ԣ�ȡ��Ƶ���Ǹ��������ٶ�ȡ��Ƶ����SINEWAVE��ʽ��ʹ�õ�11,025Hz�����Ҫ����һ��2,756.25Hz��ȷ�е�˵���ķ�֮һ��ȡ��Ƶ�ʣ������Ҳ��������Ҳ���ÿ�����ھ���4�����������25Hz�����Ҳ���ÿ�����ھ���441��������ͨ����ÿ���ڵ����������ȡ��Ƶ�ʳ���Ҫ�õ������Ҳ�Ƶ�ʡ�һ��֪����ÿ���ڵ�����������2�л��ȳ��Դ�����Ȼ����sin��ʽ�����ÿ���ڵ�������Ȼ���ٷ�����һ�����ڽ���ȡ�����Ӷ�����һ�������IJ��Ρ�
������ÿ���ڵ����������ܴ���С���������ʹ��ʱ���ַ��������Ǻܺá�ÿ�����ڵ�β�������м�ϡ�
ʹ�����������Ĺؼ��DZ���һ����̬�ġ���λ�ǡ��������˽dz�ʼ��Ϊ0����һ��������0�����ҡ����ᣬ��λ������һ��ֵ����ֵ���2�г���Ƶ���ٳ���ȡ��Ƶ�ʡ��ô���λ����Ϊ�ڶ������������Ұ��˷���������һ����λ�dz���2�л��ȣ����ȥ2�л��ȣ�����Ҫ����λ���ٳ�ʼ��Ϊ0��
���磬�ٶ�Ҫ��11,025Hz��ȡ��Ƶ��������1,000Hz�����Ҳ�����ÿ�����д�Լ11��������Ϊ������⣬�˴���λ�ǰ�������������Լǰһ�������ڵ���λ���ǣ�0��32.65��65.31��97.96��130.61��163.27��195.92��228.57��261.22��293.88��326.53��359.18��31.84��64.49��97.14��129.80��162.45��195.10���Դ����ơ����뻺�����IJ�����������Щ�Ƕȵ�����ֵ���������ŵ�ÿ������λԪ����Ϊ�����Ļ�������������ʱ���ɼ��������������λ�ǣ�����Ҫ������ʼ��Ϊ0��
���ʽ22-2��ʾ��FillBuffer��ʽ������������SINEWAVE��ʽ�����ಿ��һ����ɡ�
��ʽ22-2 SINEWAVE SINEWAVE.C /*------------------------------------------------------------------------- SINEWAVE.C -- Multimedia Windows Sine Wave Generator (c) Charles Petzold, 1998 --------------------------------------------------------------------------*/ #include <windows.h> #include <math.h> #include "resource.h" #define SAMPLE_RATE 11025 #define FREQ_MIN 20 #define FREQ_MAX 5000 #define FREQ_INIT 440 #define OUT_BUFFER_SIZE 4096 #define PI 3.14159 BOOL CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM) ; TCHAR szAppName [] = TEXT ("SineWave") ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { if (-1 == DialogBox (hInstance, szAppName, NULL, DlgProc)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; } return 0 ; } VOID FillBuffer (PBYTE pBuffer, int iFreq) { static double fAngle ; int i ; for (i = 0 ; i < OUT_BUFFER_SIZE ; i++) { pBuffer [i] = (BYTE) (127 + 127 * sin (fAngle)) ; fAngle += 2 * PI * iFreq / SAMPLE_RATE ; if ( fAngle > 2 * PI) fAngle -= 2 * PI ; } } BOOL CALLBACK DlgProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bShutOff, bClosing ; static HWAVEOUT hWaveOut ; static HWND hwndScroll ; static int iFreq = FREQ_INIT ; static PBYTE pBuffer1, pBuffer2 ; static PWAVEHDR pWaveHdr1, pWaveHdr2 ; static WAVEFORMATEX waveformat ; int iDummy ; switch (message) { case WM_INITDIALOG: hwndScroll = GetDlgItem (hwnd, IDC_SCROLL) ; SetScrollRange (hwndScroll, SB_CTL, FREQ_MIN, FREQ_MAX, FALSE) ; SetScrollPos (hwndScroll, SB_CTL, FREQ_INIT, TRUE) ; SetDlgItemInt (hwnd, IDC_TEXT, FREQ_INIT, FALSE) ; return TRUE ; case WM_HSCROLL: switch (LOWORD (wParam)) { case SB_LINELEFT: iFreq -= 1 ; break ; case SB_LINERIGHT: iFreq += 1 ; break ; case SB_PAGELEFT: iFreq /= 2 ; break ; case SB_PAGERIGHT: iFreq *= 2 ; break ; case SB_THUMBTRACK: iFreq = HIWORD (wParam) ; break ; case SB_TOP: GetScrollRange (hwndScroll, SB_CTL, &iFreq, &iDummy) ; break ; case SB_BOTTOM: GetScrollRange (hwndScroll, SB_CTL, &iDummy, &iFreq) ; break ; } iFreq = max (FREQ_MIN, min (FREQ_MAX, iFreq)) ; SetScrollPos (hwndScroll, SB_CTL, iFreq, TRUE) ; SetDlgItemInt (hwnd, IDC_TEXT, iFreq, FALSE) ; return TRUE ; case WM_COMMAND: switch (LOWORD (wParam)) { case IDC_ONOFF: // If turning on waveform, hWaveOut is NULL if (hWaveOut == NULL) { // Allocate memory for 2 headers and 2 buffers pWaveHdr1 = malloc (sizeof (WAVEHDR)) ; pWaveHdr2 = malloc (sizeof (WAVEHDR)) ; pBuffer1 = malloc (OUT_BUFFER_SIZE) ; pBuffer2 = malloc (OUT_BUFFER_SIZE) ; if (!pWaveHdr1 || !pWaveHdr2 || !pBuffer1 || !pBuffer2) { if (!pWaveHdr1) free (pWaveHdr1) ; if (!pWaveHdr2) free (pWaveHdr2) ; if (!pBuffer1) free (pBuffer1) ; if (!pBuffer2) free (pBuffer2) ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, TEXT ("Error allocating memory!"), szAppName, MB_ICONEXCLAMATION | MB_OK) ; return TRUE ; } // Variable to indicate Off button pressed bShutOff = FALSE ; // Open waveform audio for output waveformat.wFormatTag = WAVE_FORMAT_PCM ; waveformat.nChannels = 1 ; waveformat.nSamplesPerSec = SAMPLE_RATE ; waveformat.nAvgBytesPerSec = SAMPLE_RATE ; waveformat.nBlockAlign = 1 ; waveformat.wBitsPerSample = 8 ; waveformat.cbSize = 0 ; if (waveOutOpen (&hWaveOut, WAVE_MAPPER, &waveformat, DWORD) hwnd, 0, CALLBACK_WINDOW)!= MMSYSERR_NOERROR) { free (pWaveHdr1) ; free (pWaveHdr2) ; free (pBuffer1) ; free (pBuffer2) ; hWaveOut = NULL ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, TEXT ("Error opening waveform audio device!"), szAppName, MB_ICONEXCLAMATION | MB_OK) ; return TRUE ; } // Set up headers and prepare them pWaveHdr1->lpData = pBuffer1 ; pWaveHdr1->dwBufferLength = OUT_BUFFER_SIZE ; pWaveHdr1->dwBytesRecorded = 0 ; pWaveHdr1->dwUser = 0 ; pWaveHdr1->dwFlags = 0 ; pWaveHdr1->dwLoops = 1 ; pWaveHdr1->lpNext = NULL ; pWaveHdr1->reserved = 0 ; waveOutPrepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ; pWaveHdr2->lpData = pBuffer2 ; pWaveHdr2->dwBufferLength = OUT_BUFFER_SIZE ; pWaveHdr2->dwBytesRecorded = 0 ; pWaveHdr2->dwUser = 0 ; pWaveHdr2->dwFlags = 0 ; pWaveHdr2->dwLoops = 1 ; pWaveHdr2->lpNext = NULL ; pWaveHdr2->reserved = 0 ; waveOutPrepareHeader (hWaveOut, pWaveHdr2, sizeof (WAVEHDR)) ; } // If turning off waveform, reset waveform audio else { bShutOff = TRUE ; waveOutReset (hWaveOut) ; } return TRUE ; } break ; // Message generated from waveOutOpen call case MM_WOM_OPEN: SetDlgItemText (hwnd, IDC_ONOFF, TEXT ("Turn Off")) ; // Send two buffers to waveform output device FillBuffer (pBuffer1, iFreq) ; waveOutWrite (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ; FillBuffer (pBuffer2, iFreq) ; waveOutWrite (hWaveOut, pWaveHdr2, sizeof (WAVEHDR)) ; return TRUE ; // Message generated when a buffer is finished case MM_WOM_DONE: if (bShutOff) { waveOutClose (hWaveOut) ; return TRUE ; } // Fill and send out a new buffer FillBuffer (((PWAVEHDR) lParam)->lpData, iFreq) ; waveOutWrite (hWaveOut, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ; return TRUE ; case MM_WOM_CLOSE: waveOutUnprepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ; waveOutUnprepareHeader (hWaveOut, pWaveHdr2, sizeof (WAVEHDR)) ; free (pWaveHdr1) ; free (pWaveHdr2) ; free (pBuffer1) ; free (pBuffer2) ; hWaveOut = NULL ; SetDlgItemText (hwnd, IDC_ONOFF, TEXT ("Turn On")) ; if (bClosing) EndDialog (hwnd, 0) ; return TRUE ; case WM_SYSCOMMAND: switch (wParam) { case SC_CLOSE: if (hWaveOut != NULL) { bShutOff = TRUE ; bClosing = TRUE ; waveOutReset (hWaveOut) ; } else EndDialog (hwnd, 0) ; return TRUE ; } break ; } return FALSE ; }
SINEWAVE.RC ��ժ¼�� //Microsoft Developer Studio generated resource script. #include "resource.h" #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// // Dialog SINEWAVE DIALOG DISCARDABLE 100, 100, 200, 50 STYLE WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Sine Wave Generator" FONT 8, "MS Sans Serif" BEGIN SCROLLBAR IDC_SCROLL,8,8,150,12 RTEXT "440",IDC_TEXT,160,10,20,8 LTEXT "Hz",IDC_STATIC,182,10,12,8 PUSHBUTTON "Turn On",IDC_ONOFF,80,28,40,14 END
RESOURCE.H ��ժ¼�� // Microsoft Developer Studio generated include file. // Used by SineWave.rc #define IDC_STATIC -1 #define IDC_SCROLL 1000 #define IDC_TEXT 1001 #define IDC_ONOFF 1002
ע�⣬FillBuffer��ʽ���õ���OUT_BUFFER_SIZE��SAMPLE_RATE��PIʶ�����ڳ�ʽ�Ķ������塣FillBuffer��iFreq��������Ҫ��Ƶ�ʣ���λ��Hz����Ҫע�⣬sin��ʽ�Ľ����������0��254�ķ�Χ֮�䡣���ÿ��������sin��ʽ��fAngle����������һ��ֵ����ֵ�Ĵ�С��2�л��ȳ�����Ҫ��Ƶ���ٳ���ȡ��Ƶ�ʡ�
SINEWAVE���Ӵ��������������һ�����ѡ��Ƶ�ʵ�ˮƽ�����У�һ�������ʾĿǰ��ѡƵ�ʵľ�̬���������Լ�һ�����Ϊ��Turn On���İ�ť�����´˰�ť�ᣬ������������Ч�������������������Ҳ���������ͬʱ��ť�ϵ����ֽ���ɡ�Turn Off�����ü��̻��߻����ƶ������п��Ըı�Ƶ�ʡ�Ҫ�ر������������ٴΰ��°�ť��
SINEWAVE��ʽ���ʼ�������У��Ա�Ƶ����WM_INITDIALOGѶϢ�����ڼ������20Hz�������5000Hz����ʼ��ʱ���������趨Ϊ440 Hz��������������˵�������������A�����ڹ����ֶ�����ʱ����������DlgProc�ڽ���WM_HSCROLLѶϢ�����ڼ�ı侲̬����iFreq��ע�⣬Page Left��Page Right������DlgProc���ӻ��߼���һ���˶����ס�
��DlgProc�Ӱ�ť�յ�һ��WM_COMMANDѶϢʱ������������4��������é£2�����WAVEHDR�ṹ�������������ۡ���������춻��������沨�����ϣ����ǽ���������������ΪpBuffer1��pBuffer2��
ͨ������waveOutOpen��ʽ��SINEWAVE�򿪲��������豸�Ա������waveOutOpen��ʽʹ������IJ�����
waveOutOpen (&hWaveOut, wDeviceID, &waveformat, dwCallBack, dwCallBackData, dwFlags) ;
����һ�������趨Ϊָ��HWAVEOUT��handle to waveform audio output����������������ţ���̬�ı������Ӻ�ʽ����ʱ���˱������趨Ϊһ�����ţ�����IJ�����������н�ʹ�øô��š�
waveOutOpen�ĵڶ����������豸ID����������ʽ�����ڰ�װ�����Ч���Ļ�����ʹ�á������ķ�Χ��0��ϵͳ����װ�IJ�������豸��֮�䡣����waveOutGetNumDevs���Ի�ò�������豸����������waveOutGetDevCaps�����ҳ�ÿ����������豸������������豸�ʺţ���ô�������ó���WAVE_MAPPER������Ϊ-1����ѡ���豸�����豸�ڡ�����̨���ġ���ý�塹�С���Ч��ҳ���ǩ��ġ�ϲ��ʹ�õ�װ�á���ָ�������⣬�����ѡ�豸��������������Ҫ���������豸���ԣ���ôϵͳ��ѡ�������豸��
������������ָ��WAVEFORMATEX�ṹ��ָ�꣨���潫��ϸ���ܣ������ĸ��������Ӵ����Ż�ָ��̬�����ʽ����callback��ʽ��ָ�꣬������ʾ���ղ������ѶϢ���Ӵ�����callback��ʽ��ʹ��callback��ʽʱ�����ڵ����������ָ����ʽ��������ϡ�dwFlags��������ΪCALLBACK_WINDOW��CALLBACK_FUNCTION���Ա�ʾ���ĸ���������̬����Ҳ����WAVE_FORMAT_QUERY���������ܷ���豸��ʵ���ϲ�������������������������ǿ��á�
waveOutOpen�ĵ�������������Ϊָ��WAVEFORMATEX��̬�ṹ��ָ�꣬�˽ṹ��MMSYSTEM.H�ж������£�
typedef struct waveformat_tag { WORD wFormatTag ; // waveform format = WAVE_FORMAT_PCM WORD nChannels ; // number of channels = 1 or 2 DWORD nSamplesPerSec ; // sample rate DWORD nAvgBytesPerSec ; // bytes per second WORD nBlockAlign ; // block alignment WORD wBitsPerSample ; // bits per samples = 8 or 16 WORD cbSize ; // 0 for PCM } WAVEFORMATEX, * PWAVEFORMATEX ;
�����ô˽ṹָ��ȡ��Ƶ�ʣ�nSamplesPerSec����ȡ����ȷ�ȣ�nBitsPerSample�����Լ�ѡ����������������nChannels�����ṹ����Щ��Ѷ�������Ƕ���ģ����ýṹҲ����춷�PCM��ȡ����ʽ���ڷ�PCMȡ����ʽ�£��˽ṹ������һ����λ�趨Ϊ��0ֵ��������������Ѷ��
���PCMȡ����ʽ��nBlockAlign��λ�趨ΪnChannels����wBitsPerSample�ٳ���8���õ�����ֵ������ʾÿ��ȡ������λԪ������nAvgBytesPerSec��λ�趨ΪnSamplesPerSec��nBlockAlign�ij˻���
SINEWAVE��ʼ��WAVEFORMATEX�ṹ����λ��������waveOutOpen��ʽ��
waveOutOpen ( &hWaveOut, WAVE_MAPPER, &waveformat, (DWORD) hwnd, 0, CALLBACK_WINDOW)
������гɹ�����waveOutOpen��ʽ����MMSYSERR_NOERROR������Ϊ0�������򴫻ط�0�Ĵ�����롣���waveOutOpen�Ĵ���ֵ��0����SINEWAVE����Ӵ�������ʾһ����ʶ�����ѶϢ���顣
�����豸���ˣ�SINEWAVE������ʼ������WAVEHDR�ṹ����λ���������ṹ�����API�д��ݻ��塣WAVEHDR�������£�
typedef struct wavehdr_tag { LPSTR lpData; // pointer to data buffer DWORD dwBufferLength; // length of data buffer DWORD dwBytesRecorded; // used for recorded DWORD dwUser; // for program use DWORD dwFlags; // flags DWORD dwLoops; // number of repetitions struct wavehdr_tag FAR *lpNext; // reserved DWORD reserved; // reserved } WAVEHDR, *PWAVEHDR ;
SINEWAVE��lpData��λ�趨Ϊ�������ϵĻ�����λַ��dwBufferLength��λ�趨Ϊ�˻������Ĵ�С��dwLoops��λ�趨Ϊ1��������λ���趨Ϊ0��NULL�����Ҫ�ظ���Ȧ�������������趨dwFlags��dwLoops��λ��
SINEWAVE��һ��Ϊ������Ѷ��ͷ����waveOutPrepareHeader��ʽ���Է�ֹ�ṹ�ͻ�������ŵ��������Ͻ�����
����Ϊֹ�����е���Щ׼�����ǻ�Ӧ�������������İ�ť�����ڳ�ʽ��ѶϢ�������Ѿ���һ��ѶϢ�ڵȴ���Ӧ����Ϊ�����Ѿ��ں�ʽwaveOutOpen��ָ��Ҫ��һ���Ӵ�ѶϢ������ʽ�����ղ������ѶϢ������waveOutOpen��ʽ���ʽ��ѶϢ���з�����MM_WOM_OPENѶϢ��wParamѶϢ�����趨Ϊ����������š�Ҫ����MM_WOM_OPENѶϢ��SINEWAVE����FillBuffer��ʽ���Σ��������Ҳ����������pBuffer��������Ȼ��SINEWAVE������WAVEHDR�ṹ���͸�waveOutWrite���˺�ʽ�����ϴ��͵��������Ӳ�壬��������ʼ����������
������Ӳ�岥����waveOutWrite��ʽ�������������ᣬ�����Ӵ�����MM_WOM_DONEѶϢ������wParam�����Dz���������ţ�lParam��ָ��WAVEHDR�ṹ��ָ�ꡣSINEWAVE�ڴ�����ѶϢʱ�������㻺�����������ϣ�������waveOutWrite�������ύ��������
��дSINEWAVE��ʽʱҲ����ֻ��һ��WAVEHDR�ṹ��һ���������������������ڲ����������Ὣ���кܶ��ݵ�ͣ�٣��Եȴ���ʽ����MM_WOM_DONEѶϢ���ύ�µĻ�������SINEWAVEʹ�õġ�˫���塹���������������IJ�������
��ʹ���ߵ�����Turn Off����ť�ر�����ʱ��DlgProc���յ���һ��WM_COMMANDѶϢ���Դ�ѶϢ��DlgProc��bShutOff�����趨ΪTRUE��������waveOutReset��ʽ���˺�ʽֹͣ��������������һ��MM_WOM_DONEѶϢ��bShutOffΪTRUEʱ��SINEWAVE͸������waveOutClose������MM_WOM_DONE���Ӷ�����һ��MM_WOM_CLOSEѶϢ������MM_WOM_CLOSEͨ�������������SINEWAVEΪ����WAVEHDR�ṹ������waveOutUnprepareHeader���ͷ����еļ�����鲢�Ѱ�ť�ϵ����ָĻء�Turn On����
���Ӳ��������Ż��������������ϣ���ô���Լ�����waveOutClose��û�����á��������Ⱥ���waveOutReset��ֹͣ���Ų�����MM_WOM_DONEѶϢ����wParam��SC_CLOSEʱ��DlgProcҲ����WM_SYSCOMMANDѶϢ��������Ϊʹ���ߴ�ϵͳ���ܱ���ѡ���ˡ�Close����������������������ţ�DlgProc�����waveOutReset��������Σ�������Ҫ����EndDialog��������ʽ��
��λ¼����
��
Windows�ṩ��һ����Ϊ��¼����ʽ����¼�ƺͲ�����λ��������ʽ22-3��ʾ�ij�ʽ��RECORD1�����硸¼����ʽ�����ƣ���Ϊ���������κε���I/O��Ҳ�����������à¼ï¿½ï¿½È»ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½Ê½ï¿½ï¿½Ê¾ï¿½ï¿½Ê¹ï¿½ÃµÍ½×²ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½API��¼�ƺ��ز������Ļ���������
��ʽ22-3 RECORD1 RECORD1.C /*--------------------------------------------------------------------------- RECORD1.C -- Waveform Audio Recorder (c) Charles Petzold, 1998 ----------------------------------------------------------------------------*/ #include <windows.h> #include "resource.h" #define INP_BUFFER_SIZE 16384 BOOL CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM) ; TCHAR szAppName [] = TEXT ("Record1") ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { if (-1 == DialogBox (hInstance, TEXT ("Record"), NULL, DlgProc)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; } return 0 ; } void ReverseMemory (BYTE * pBuffer, int iLength) { BYTE b ; int i ; for (i = 0 ; i < iLength / 2 ; i++) { b = pBuffer [i] ; pBuffer [i] = pBuffer [iLength - i - 1] ; pBuffer [iLength - i - 1] = b ; } } BOOL CALLBACK DlgProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bRecording, bPlaying, bReverse, bPaused, bEnding, bTerminating ; static DWORD dwDataLength, dwRepetitions = 1 ; static HWAVEIN hWaveIn ; static HWAVEOUT hWaveOut ; static PBYTE pBuffer1, pBuffer2, pSaveBuffer, pNewBuffer ; static PWAVEHDR pWaveHdr1, pWaveHdr2 ; static TCHAR szOpenError[] = TEXT ("Error opening waveform audio!"); static TCHAR szMemError [] = TEXT ("Error allocating memory!") ; static WAVEFORMATEX waveform ; switch (message) { case WM_INITDIALOG: // Allocate memory for wave header pWaveHdr1 = malloc (sizeof (WAVEHDR)) ; pWaveHdr2 = malloc (sizeof (WAVEHDR)) ; // Allocate memory for save buffer pSaveBuffer = malloc (1) ; return TRUE ; case WM_COMMAND: switch (LOWORD (wParam)) { case IDC_RECORD_BEG: // Allocate buffer memory pBuffer1 = malloc (INP_BUFFER_SIZE) ; pBuffer2 = malloc (INP_BUFFER_SIZE) ; if (!pBuffer1 || !pBuffer2) { if (pBuffer1) free (pBuffer1) ; if (pBuffer2) free (pBuffer2) ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szMemError, szAppName, MB_ICONEXCLAMATION | MB_OK) ; return TRUE ; } // Open waveform audio for input waveform.wFormatTag = WAVE_FORMAT_PCM ; waveform.nChannels = 1 ; waveform.nSamplesPerSec = 11025 ; waveform.nAvgBytesPerSec = 11025 ; waveform.nBlockAlign = 1 ; waveform.wBitsPerSample = 8 ; waveform.cbSize = 0 ; if (waveInOpen (&hWaveIn, WAVE_MAPPER, &waveform, (DWORD) hwnd, 0, CALLBACK_WINDOW)) { free (pBuffer1) ; free (pBuffer2) ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION | MB_OK) ; } // Set up headers and prepare them pWaveHdr1->lpData = pBuffer1 ; pWaveHdr1->dwBufferLength = INP_BUFFER_SIZE ; pWaveHdr1->dwBytesRecorded = 0 ; pWaveHdr1->dwUser = 0 ; pWaveHdr1->dwFlags = 0 ; pWaveHdr1->dwLoops = 1 ; pWaveHdr1->lpNext = NULL ; pWaveHdr1->reserved = 0 ; waveInPrepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ; pWaveHdr2->lpData = pBuffer2 ; pWaveHdr2->dwBufferLength = INP_BUFFER_SIZE ; pWaveHdr2->dwBytesRecorded = 0 ; pWaveHdr2->dwUser = 0 ; pWaveHdr2->dwFlags = 0 ; pWaveHdr2->dwLoops = 1 ; pWaveHdr2->lpNext = NULL ; pWaveHdr2->reserved = 0 ; waveInPrepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ; return TRUE ; case IDC_RECORD_END: // Reset input to return last buffer bEnding = TRUE ; waveInReset (hWaveIn) ; return TRUE ; case IDC_PLAY_BEG: // Open waveform audio for output waveform.wFormatTag = WAVE_FORMAT_PCM ; waveform.nChannels = 1 ; waveform.nSamplesPerSec = 11025 ; waveform.nAvgBytesPerSec = 11025 ; waveform.nBlockAlign = 1 ; waveform.wBitsPerSample = 8 ; waveform.cbSize = 0 ; if (waveOutOpen (&hWaveOut, WAVE_MAPPER, &waveform, (DWORD) hwnd, 0, CALLBACK_WINDOW)) { MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION | MB_OK) ; } return TRUE ; case IDC_PLAY_PAUSE: // Pause or restart output if (!bPaused) { waveOutPause (hWaveOut) ; SetDlgItemText (hwnd, IDC_PLAY_PAUSE, TEXT ("Resume")) ; bPaused = TRUE ; } else { waveOutRestart (hWaveOut) ; SetDlgItemText (hwnd, IDC_PLAY_PAUSE, TEXT ("Pause")) ; bPaused = FALSE ; } return TRUE ; case IDC_PLAY_END: // Reset output for close preparation bEnding = TRUE ; waveOutReset (hWaveOut) ; return TRUE ; case IDC_PLAY_REV: // Reverse save buffer and play bReverse = TRUE ; ReverseMemory (pSaveBuffer, dwDataLength) ; SendMessage (hwnd, WM_COMMAND, IDC_PLAY_BEG, 0) ; return TRUE ; case IDC_PLAY_REP: // Set infinite repetitions and play dwRepetitions = -1 ; SendMessage (hwnd, WM_COMMAND, IDC_PLAY_BEG, 0) ; return TRUE ; case IDC_PLAY_SPEED: // Open waveform audio for fast output waveform.wFormatTag = WAVE_FORMAT_PCM ; waveform.nChannels = 1 ; waveform.nSamplesPerSec =22050 ; waveform.nAvgBytesPerSec= 22050 ; waveform.nBlockAlign = 1 ; waveform.wBitsPerSample = 8 ; waveform.cbSize = 0 ; if (waveOutOpen (&hWaveOut, 0, &waveform, (DWORD) hwnd, 0, CALLBACK_WINDOW)) { essageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION | MB_OK) ; } return TRUE ; } break ; case MM_WIM_OPEN: // Shrink down the save buffer pSaveBuffer = realloc (pSaveBuffer, 1) ; // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), FALSE) ; SetFocus (GetDlgItem (hwnd, IDC_RECORD_END)) ; // Add the buffers waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ; waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ; // Begin sampling bRecording = TRUE ; bEnding = FALSE ; dwDataLength = 0 ; waveInStart (hWaveIn) ; return TRUE ; case MM_WIM_DATA: // Reallocate save buffer memory pNewBuffer = realloc ( pSaveBuffer, dwDataLength + ((PWAVEHDR) lParam)->dwBytesRecorded) ; if (pNewBuffer == NULL) { waveInClose (hWaveIn) ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szMemError, szAppName, MB_ICONEXCLAMATION | MB_OK) ; return TRUE ; } pSaveBuffer = pNewBuffer ; CopyMemory (pSaveBuffer + dwDataLength, ((PWAVEHDR) lParam)->lpData, ((PWAVEHDR) lParam)->dwBytesRecorded) ; dwDataLength += ((PWAVEHDR) lParam)->dwBytesRecorded ; if (bEnding) { waveInClose (hWaveIn) ; return TRUE ; } // Send out a new buffer waveInAddBuffer (hWaveIn, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ; return TRUE ; case MM_WIM_CLOSE: // Free the buffer memory waveInUnprepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ; waveInUnprepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ; free (pBuffer1) ; free (pBuffer2) ; // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE) ; SetFocus (GetDlgItem (hwnd, IDC_RECORD_BEG)) ; if (dwDataLength > 0) { EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), TRUE) ; SetFocus (GetDlgItem (hwnd, IDC_PLAY_BEG)) ; } bRecording = FALSE ; if (bTerminating) SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ; return TRUE ; case MM_WOM_OPEN: // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), TRUE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), TRUE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), FALSE) ; SetFocus (GetDlgItem (hwnd, IDC_PLAY_END)) ; // Set up header pWaveHdr1->lpData = pSaveBuffer ; pWaveHdr1->dwBufferLength = dwDataLength ; pWaveHdr1->dwBytesRecorded = 0 ; pWaveHdr1->dwUser = 0 ; pWaveHdr1->dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP ; pWaveHdr1->dwLoops = dwRepetitions ; pWaveHdr1->lpNext = NULL ; pWaveHdr1->reserved = 0 ; // Prepare and write waveOutPrepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ; waveOutWrite (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ; bEnding = FALSE ; bPlaying = TRUE ; return TRUE ; case MM_WOM_DONE: waveOutUnprepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ; waveOutClose (hWaveOut) ; return TRUE ; case MM_WOM_CLOSE: // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), TRUE) ; SetFocus (GetDlgItem (hwnd, IDC_PLAY_BEG)) ; SetDlgItemText (hwnd, IDC_PLAY_PAUSE, TEXT ("Pause")) ; bPaused = FALSE ; dwRepetitions = 1 ; bPlaying = FALSE ; if (bReverse) { ReverseMemory (pSaveBuffer, dwDataLength) ; bReverse = FALSE ; } if (bTerminating) SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ; return TRUE ; case WM_SYSCOMMAND: switch (LOWORD (wParam)) { case SC_CLOSE: if (bRecording) { bTerminating = TRUE ; bEnding = TRUE ; waveInReset (hWaveIn) ; return TRUE ; } if (bPlaying) { bTerminating = TRUE ; bEnding = TRUE ; waveOutReset (hWaveOut) ; return TRUE ; } free (pWaveHdr1) ; free (pWaveHdr2) ; free (pSaveBuffer) ; EndDialog (hwnd, 0) ; return TRUE ; } break ; } return FALSE ; }
RECORD.RC ��ժ¼�� //Microsoft Developer Studio generated resource script. #include "resource.h" #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// // Dialog RECORD DIALOG DISCARDABLE 100, 100, 152, 74 STYLE WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Waveform Audio Recorder" FONT 8, "MS Sans Serif" BEGIN PUSHBUTTON "Record",IDC_RECORD_BEG,28,8,40,14 PUSHBUTTON "End",IDC_RECORD_END,76,8,40,14,WS_DISABLED PUSHBUTTON "Play",IDC_PLAY_BEG,8,30,40,14,WS_DISABLED PUSHBUTTON "Pause",IDC_PLAY_PAUSE,56,30,40,14,WS_DISABLED PUSHBUTTON "End",IDC_PLAY_END,104,30,40,14,WS_DISABLED PUSHBUTTON "Reverse",IDC_PLAY_REV,8,52,40,14,WS_DISABLED PUSHBUTTON "Repeat",IDC_PLAY_REP,56,52,40,14,WS_DISABLED PUSHBUTTON "Speedup",IDC_PLAY_SPEED,104,52,40,14,WS_DISABLED END
RESOURCE.H ��ժ¼�� // Microsoft Developer Studio generated include file. // Used by Record.rc #define IDC_RECORD_BEG 1000 #define IDC_RECORD_END 1001 #define IDC_PLAY_BEG 1002 #define IDC_PLAY_PAUSE 1003 #define IDC_PLAY_END 1004 #define IDC_PLAY_REV 1005 #define IDC_PLAY_REP 1006 #define IDC_PLAY_SPEED 1007
RECORD.RC��RESOURCE.H����Ҳ��RECORD2��RECORD3��ʽ��ʹ�á�
RECORD1�Ӵ���8����ť����һ��ִ��RECORD1ʱ��ֻ�С�Record����ť��Ч�����¡�Record���ᣬ�Ϳ�ʼ¼������ʱ��Record����ť��Ч������End����ť��Ч�����¡�End����ֹͣ¼������ʱ����Play������ Reverse������ Repeat���͡�Speedup��Ҳ����Ч��ѡ����һ����ť�����ط���������Play����ʾ�������ţ���Reverse����ʾ���򲥷ţ���Repeat����ʾ���޵��ظ����ţ������Ȧ¼����������Speedup���������ٶȵ����������š�Ҫֹͣ���ţ�������ѡ��End����ť�������¡�Pause����ť��ֹͣ���š������ᣬ��Pause����ť����Ϊ��Resume����ť����춼����������������Ҫ¼����һ����������¼�Ƶ��������滻�����������е�������
�κ�ʱ����Ч��ť���ǿ���ִ����Ч�����İ�ť������Ҫ��RECORD1Ôʼ���а�����EnableWindow�Ķ�κ��У����dz�ʽ����������İ�ť�����Ƿ���Ч����Ȼ����ʹ�ó�ʽ������Ϊֱ�ۡ�
RECORD1���������ݷ�ʽ���򻯳�ʽ�롣���ȣ������װ�˶����������Ӳ���豸����RECORD1ֻʹ���ڶ��豸����Σ���ʽ����׼��11.025 kHz��ȡ��Ƶ�ʺ�8λԪ��ȡ����ȷ����¼���ͷ������������豸�ܷ��ṩ���ߵ�ȡ��Ƶ�ʺ�ȡ����ȷ�ȡ�Ψһ�������Ǽ��ٹ��ܣ�����ʱRECORD1��22.050kHz��ȡ��Ƶ�ʲ����������������������ٶ������һ��������Ƶ��Ҳ�����һ�����ס�
¼�������Ȱ���Ϊ������򿪲�������Ӳ�壬�����������������ݸ�API���Ա�����������ϡ�
RECORD1���м���������顣����������С�������ڳ�ʼ��ʱ��С��������DlgProc��WM_INITDIALOGѶϢ�����ڼ�������á���ʽ��������WAVEHDR�ṹ���ֱ���ָ��pWaveHdr1��pWaveHdr2ָ���������ṹ��춽����������ݸ�����API��pSaveBufferָ��ָ�򴢴�����¼���Ļ��������������ʱֻ��һ��λԪ�顣Ȼ�ᣬ����¼���Ľ��У��û�����������������Ӧ���е��������ϣ����¼��ʱ���������RECORD1�ܹ���¼�Ƴ����м�ʱ���ּ�������������������طųɹ����������������������������������ѻ����������ϣ������ҽ����Ϊ�����滺������save buffer������ָ��pBuffer1��pBuffer2ָ�����������������飬��С��16K�������ڼ�¼���յ���������ʱ���á�¼���������ͷ���Щ������顣
8����ť�е�ÿһ������REPORT1�Ӵ��ĶԻ�����DlgProc����WM_COMMANDѶϢ�����ֻ�С�Record����ť��Ч�����´˰�ť������WM_COMMANDѶϢ������wParam�������IDC_RECORD_BEG��Ϊ�������ѶϢ��RECORD1��������16K�Ļ������������������ϣ���ʼ��WAVEFORMATEX�ṹ����λ�������˽ṹ���ݸ�waveInOpen��ʽ��Ȼ���趨����WAVEHDR�ṹ��
waveInOpen��ʽ����һ��MM_WIM_OPENѶϢ���ڴ�ѶϢ�����ڼ䣬RECORD1�Ѵ��滺�����Ĵ�С������1��λԪ�飬��׼���������ϣ���Ȼ����һ��¼��ʱ�����滺�����Ĵ�С����1��λԪ�飬������¼��ʱ���Ϳ��ܴ���ˣ�����MM_WIM_OPENѶϢ�����ڼ䣬RECORD1Ҳ���ʵ��İ�ť�趨Ϊ��Ч����Ч��Ȼ�ᣬ��ʽ��waveInAddBuffer������WAVEHDR�ṹ�ͻ��������͸�API����ʱ���趨ijЩ��ǣ�Ȼ�����waveInStart��ʼ¼����
����11.025kHz��ȡ��Ƶ�ʺ�8λԪ��ȡ����ȷ��ʱ��16K�Ļ������ɴ����Լ1.5�����������ʱ��RECORD1����MM_WIM_DATAѶϢ���ڻ�Ӧ��ѶϢ�����ڼ䣬��ʽ�����ݱ���dwDataLength��WAVEHDR�ṹ�е���λdwBytesRecorded�Ի������������á��������ʧ�ܣ�RECORD1����waveInClose��ֹͣ¼����
����������óɹ�����RECORD1��16K������������ϸ��Ƶ����滺������Ȼ���ٴκ���waveInAddBuffer���˳��򽫳�����RECORD1���괢�滺�����ļ����壬��ʹ���߰��¡�End����ťΪֹ��
��End����ť����WM_COMMANDѶϢ������wParam���IDC_RECORD_END���������ѶϢ�ܼ򵥣�RECORD1��bEnding����趨ΪTRUE������waveInReset��waveInReset��ʽʹ¼��ֹͣ��������MM_WIM_DATAѶϢ����ѶϢ���в������Ļ����������˺���waveInClose���رղ��������豸�⣬RECORD1�����ѶϢ������Ӧ��
waveInClose����MM_WIM_CLOSEѶϢ��RECORD1��Ӧ��ѶϢʱ���ͷ�16K���뻺��������ʹ��Ӧ�İ�ť��Ч����Ч�������ǣ������滺������������ϣ����ǵ�һ�����þ�ʧ�ܣ�����һ�㶼�������ϣ�ʱ�����Ű�ť����Ч��
¼�����ᣬ���滺�����ォ������Щ�������ϡ���ʹ����ѡ��Play����ťʱ��DlgProc�ͽ���һ��WM_COMMANDѶϢ������wParam���IDC_PLAY_BEG����Ӧʱ����ʽ����ʼ��WAVEFORMATEX�ṹ����λ��������waveOutOpen��
waveOutOpen�����ٴβ���MM_WOM_OPENѶϢ���ڴ�ѶϢ�����ڼ䣬RECORD1����Ӧ�İ�ť��Ϊ��Ч����Ч��ֻ����ʹ�á�Pause���͡�End�������ô��滺��������ʼ��WAVEHDR�ṹ����λ������waveOutPrepareHeader��׼��Ҫ���ŵ�������Ȼ�����waveOutWrite��ʼ���š�
һ������£�ֱ�������괢�滺��������������ϲ�ֹͣ����ʱ����MM_WOM_DONE ѶϢ��������л�����Ҫ���ţ����ʽ������ʱ�����Ǵ��ݸ�API�����RECORD1ֻ����һ���󻺳�������˳�ʽ���ټ򵥵�׼�����⣬���Ǻ���waveOutClose��waveOutClose��ʽ����MM_WOM_CLOSEѶϢ���ڴ�ѶϢ�����ڼ䣬RECORD1ʹ��Ӧ�İ�ť��Ч����Ч�������������ٴβ��Ż���¼����������
��ʽ�л���һ����End����ť�����ô˰�ť��ʹ���߿����ڲ����괢�滺����֮ǰ���κ�ʱ��ֹͣ���š���End����ť����һ��WM_COMMANDѶϢ������wParam���IDC_PLAY_END����Ӧʱ����ʽ����waveOutReset���˺�ʽ����һ������������MM_WOM_DONEѶϢ��
RECORD1���Ӵ��л�����һ����Pause����ť�������˰�ť�ܼ򵥣���һ�ΰ�ʱ�£�RECORD1����waveOutPause����ͣ���ţ�������ť�ϵ����ָ�Ϊ��Resume�������¡�Resume����ťʱ��ͨ������waveOutRestart���������š�
Ϊ��ʹ��ʽ����Ȥ���Ӵ��л���������������ť����Reverse������Repeat���͡�Speedup������Щ��ť������WM_COMMANDѶϢ������wParam��ֵ�ֱ���IDC_PLAY_REV��IDC_PLAY_REP��IDC_PLAY_SPEED��
�����������ǰѴ��滺����������ϰ�λԪ��˳����Ȼ�����������š�RECORD1����һ����ΪReverseMemory��С��ʽʹλԪ�鷴����WM_COMMANDѶϢ�����ڼ䣬��ʽ�ڲ��ſ�֮ǰ���д˺�ʽ������MM_WOM_CLOSEѶϢ�������ٴκ��д˺�ʽ���Ա㽫��ָ�������״̬��
��Repeat����ť��������ͣ�ز������������API֧Ԯ�ظ����������������Ⲣ�����ӡ�ֻҪ��WAVEHDR�ṹ��dwLoops��λ��Ϊ�ظ���������dwFlags��λ��ΪWHDR_BEGINLOOP��WHDR_ENDLOOP���ֱ��ʾ��Ȧʱ�������Ŀ�ʼ���ֺͽ������֡���ΪRECORD1ֻʹ��һ�����������������������������������ϵ���dwFlags��λ��
Ҫʵ�������ٲ���Ҳ�����ס���׼��Ϊ������򿪲��������ڼ䣬��ʼ��WAVEFORMATEX�ṹ����λʱ��ֻ�轫nSamplesPerSec��nAvgBytesPerSec��λ�趨Ϊ22050��������11025��
��һ��MCI����
��
�������Ѿ����֣�RECORD1�ܸ��ӡ��ر����ڴ�������������ʽ���к����Dz�����ѶϢ��Ľ���ʱ�������ӡ��������ܳ��ֵļ����岻������Ҳ����ˡ�����Ҳ����������Ϊ�ͽ׽����Ô�����ڱ��µ�ǰ���ᵽ����WindowsҲ�ṩ�߽�ý����ƽ��棨Media Control Interface����
�Բ���������˵���ͽ׽�����MCI֮�����Ҫ�������MCI�ò��ε�����¼�������ϣ���ͨ����ȡ��������������������ڲ�������֮ǰҪ��ȡ��������������Ȼ����д�뵵����������RECODE1��ʵ��������Ч���������ѡ����ǵ��͵�����ѡ�����⣺������ȫ����ʹ�÷��㣿�ͽ׽��������MCI�����еĴ󲿷֣������㡣
MCI�����ֲ�ͬ������ص�ʵ����ʽ��һ����ʽ��ѶϢ�����Ͻṹ������͸���ý���豸��Ȼ���ٴ����������Ѷ����һ����ʽʹ��ASCII�����ִ���������������Ľ��������Ϊ���ö�ý���豸���ܼ򵥵������������ԵĿ��ơ�����Ҳ�ṩ�dz����׵Ľ�̸ʽ���ƣ���μ�����ǰ�棬TESTMCI��ʽ��չʾ��
RECORD2��ʽ�����ʽ22-4��ʾ��ʹ��MCI��ʽ��ѶϢ�����Ͻṹ��ʵ����һ����λ����¼�����Ͳ���������Ȼ��ʹ�õĶԻ�����ģ����RECORD1һ��������û��ʵ����������Ч���İ�ť��
��ʽ22-4 RECORD2 RECORD2.C /*--------------------------------------------------------------------------- RECORD2.C -- Waveform Audio Recorder (c) Charles Petzold, 1998 ------------------------------------------------------------------------*/ #include <windows.h> #include "..\\record1\\resource.h" BOOL CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM) ; TCHAR szAppName [] = TEXT ("Record2") ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { if (-1 == DialogBox (hInstance, TEXT ("Record"), NULL, DlgProc)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; } return 0 ; } void ShowError (HWND hwnd, DWORD dwError) { TCHAR szErrorStr [1024] ; mciGetErrorString (dwError, szErrorStr, sizeof (szErrorStr) / sizeof (TCHAR)) ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szErrorStr, szAppName, MB_OK | MB_ICONEXCLAMATION) ; } BOOL CALLBACK DlgProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bRecording, bPlaying, bPaused ; static TCHAR szFileName[] = TEXT ("record2.wav") ; static WORD wDeviceID ; DWORD dwError ; MCI_GENERIC_PARMS mciGeneric ; MCI_OPEN_PARMS mciOpen ; MCI_PLAY_PARMS mciPlay ; MCI_RECORD_PARMS mciRecord ; MCI_SAVE_PARMS mciSave ; switch (message) { case WM_COMMAND: switch (wParam) { case IDC_RECORD_BEG: // Delete existing waveform file DeleteFile (szFileName) ; // Open waveform audio mciOpen.dwCallback = 0 ; mciOpen.wDeviceID = 0 ; mciOpen.lpstrDeviceType = TEXT ("waveaudio") ; mciOpen.lpstrElementName = TEXT ("") ; mciOpen.lpstrAlias = NULL ; dwError = mciSendCommand (0, MCI_OPEN, MCI_WAIT | MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD) (LPMCI_OPEN_PARMS) &mciOpen) ; if (dwError != 0) { ShowError (hwnd, dwError) ; return TRUE ; } // Save the Device ID wDeviceID = mciOpen.wDeviceID ; // Begin recording mciRecord.dwCallback = (DWORD) hwnd ; mciRecord.dwFrom = 0 ; mciRecord.dwTo = 0 ; mciSendCommand (wDeviceID, MCI_RECORD, MCI_NOTIFY, (DWORD) (LPMCI_RECORD_PARMS) &mciRecord) ; // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE); SetFocus (GetDlgItem (hwnd, IDC_RECORD_END)) ; bRecording = TRUE ; return TRUE ; case IDC_RECORD_END: // Stop recording mciGeneric.dwCallback = 0 ; mciSendCommand (wDeviceID, MCI_STOP, MCI_WAIT, (DWORD) (LPMCI_GENERIC_PARMS) &mciGeneric) ; // Save the file mciSave.dwCallback = 0 ; mciSave.lpfilename = szFileName ; mciSendCommand (wDeviceID, MCI_SAVE, MCI_WAIT | MCI_SAVE_FILE, (DWORD) (LPMCI_SAVE_PARMS) &mciSave) ; // Close the waveform device mciSendCommand (wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD) (LPMCI_GENERIC_PARMS) &mciGeneric) ; // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), TRUE); EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), TRUE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE); SetFocus (GetDlgItem (hwnd, IDC_PLAY_BEG)) ; bRecording = FALSE ; return TRUE ; case IDC_PLAY_BEG: // Open waveform audio mciOpen.dwCallback = 0 ; mciOpen.wDeviceID = 0 ; mciOpen.lpstrDeviceType = NULL ; mciOpen.lpstrElementName = szFileName ; mciOpen.lpstrAlias = NULL ; dwError = mciSendCommand ( 0, MCI_OPEN, MCI_WAIT | MCI_OPEN_ELEMENT, (DWORD) (LPMCI_OPEN_PARMS) &mciOpen) ; if (dwError != 0) { ShowError (hwnd, dwError) ; return TRUE ; } // Save the Device ID wDeviceID = mciOpen.wDeviceID ; // Begin playing mciPlay.dwCallback = (DWORD) hwnd ; mciPlay.dwFrom = 0 ; mciPlay.dwTo = 0 ; mciSendCommand (wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD) (LPMCI_PLAY_PARMS) &mciPlay) ; // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), TRUE) ; SetFocus (GetDlgItem (hwnd, IDC_PLAY_END)) ; bPlaying = TRUE ; return TRUE ; case IDC_PLAY_PAUSE: if (!bPaused) // Pause the play { mciGeneric.dwCallback = 0 ; mciSendCommand (wDeviceID, MCI_PAUSE, MCI_WAIT, (DWORD) (LPMCI_GENERIC_PARMS) & mciGeneric); SetDlgItemText (hwnd, IDC_PLAY_PAUSE, TEXT ("Resume")) ; Paused = TRUE ; } else // Begin playing again { mciPlay.dwCallback = (DWORD) hwnd ; mciPlay.dwFrom = 0 ; mciPlay.dwTo = 0 ; mciSendCommand (wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD) (LPMCI_PLAY_PARMS) &mciPlay) ; SetDlgItemText (hwnd, IDC_PLAY_PAUSE, TEXT ("Pause")) ; bPaused = FALSE ; } return TRUE ; case IDC_PLAY_END: // Stop and close mciGeneric.dwCallback = 0 ; mciSendCommand (wDeviceID, MCI_STOP, MCI_WAIT, (DWORD) (LPMCI_GENERIC_PARMS) &mciGeneric) ; mciSendCommand (wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD) (LPMCI_GENERIC_PARMS) &mciGeneric) ; // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE); SetFocus (GetDlgItem (hwnd, IDC_PLAY_BEG)) ; bPlaying = FALSE ; bPaused = FALSE ; return TRUE ; } break ; case MM_MCINOTIFY: switch (wParam) { case MCI_NOTIFY_SUCCESSFUL: if (bPlaying) SendMessage (hwnd, WM_COMMAND, IDC_PLAY_END, 0) ; if (bRecording) SendMessage (hwnd, WM_COMMAND, IDC_RECORD_END, 0); return TRUE ; } break ; case WM_SYSCOMMAND: switch (wParam) { case SC_CLOSE: if (bRecording) SendMessage (hwnd, WM_COMMAND, IDC_RECORD_END, 0L) ; if (bPlaying) SendMessage (hwnd, WM_COMMAND, IDC_PLAY_END, 0L) ; EndDialog (hwnd, 0) ; return TRUE ; } break ; } return FALSE ; }
RECORD2ֻʹ������MCI��ʽ���У���������Ҫ�ĺ���������ʾ��
error = mciSendCommand (wDeviceID, message, dwFlags, dwParam)
��һ���������豸��ʶ�����֣�ID���������԰�������ʹ��ID�����豸ʱ�Ϳ��Ի��ID�����������mciSendCommand������ʹ�á��ڶ�������������ΪMCI�ij�������Щ��ΪMCI����ѶϢ��RECORD2չʾ�����е��߸���MCI_OPEN��MCI_RECORD��MCI_STOP��MCI_SAVE��MCI_PLAY��MCI_PAUSE��MCI_CLOSE��
dwFlags����ͨ����0���߶��λԪ��곣������C��λԪOR�����Ӻϳɣ���ɡ���Щͨ��������ʾ��ͬ��ѡ�һЩѡ����ij������ѶϢ�����еģ�����һЩ�����е�ѶϢ����ͨ�õġ�dwParam����ͨ����ָ��һ�����Ͻṹ�ij�ָ�꣬�ýṹ��ʾѡ���Լ����豸��õ���Ѷ������MCIѶϢ�������Ͻṹ�йأ�������Щ���Ͻṹ���ѶϢ��˵����Ψһ�ġ�
���mciSendCommand��ʽ���гɹ����򴫻�0ֵ�����򴫻ش�����롣Ҫ��ʹ���߱���˴��󣬿�������ĺ�ʽ�����������������ִ���
mciGetErrorString (error, szBuffer, dwLength)
�˺�ʽ�ڳ�ʽTESTMCI��Ҳ�õ�����
���¡�Record����ť�ᣬRECORD2���Ӵ�ѶϢ������ʽ���յ�һ��WM_COMMANDѶϢ������wParam���IDC_RECORD_BEG��RECORD2�Ӵ��豸��ʼ�������趨MCI_OPEN_PARMS�ṹ����λ������MCI_OPEN����ѶϢ����mciSendCommand��¼��ʱ��lpstrDeviceType��λ�趨Ϊ�ִ���waveaudio����˵���豸��̬��lpstrElementName��λ�趨Ϊ����Ϊ0���ִ���MCI������ʽʹ���ڶ���ȡ��Ƶ�ʺ�ȡ����ȷ�ȣ�������������MCI_SET��������޸ġ�¼�������У����������ȴ�����Ӳ���ϵ��ݴ浵���У�������ת���ɱ�׼�IJ��ε��������µ����潫���ܲ��ε����ĸ�ʽ������¼�Ƶ�����ʱ��MCIʹ�ò��ε����ж����ȡ��Ƶ�ʺ�ȡ����ȷ�ȡ�
���RECORD2���ܴ��豸������mciGetErrorString��MessageBox��ʾ������Ѷ�������mciSendCommand���д��أ�MCI_OPEN_PARMS�ṹ��wDeviceID��λ�������豸ID���Թ�����ĺ���ʹ�á�
Ҫ��ʼ¼����RECORD2�ͺ���mciSendCommand����MCI_RECORD����ѶϢ��MCI_WAVE_RECORD_PARMS���ϽṹΪ��������Ȼ����Ҳ���Խ��˽ṹ����ʹ�ñ�ʾ��Щ��λ���趨��λԪ��꣩��dwFromz��dwTo��λ�����趨���Ա㽫�����������еIJ��ε������䵵������MCI_OPEN_PARMS�ṹ��lpstrElementName��λָ�����ڶ�״̬�£��κ��µ����������������е����Ŀ�ʼλ�á�
RECORD2��MCI_WAVE_RECORD_PARMS�ṹ��dwCallback��λ�趨Ϊ��ʽ���Ӵ����ţ�����mciSendCommand�����а���MCI_NOTIFY��ǡ��⵼��¼�����������Ӵ�ѶϢ������ʽ����һ��֪ͨѶϢ���ҽ���Ҫ����һ������֪ͨѶϢ��
¼�������ᣬ����ǰһ����End����ť��ֹͣ¼������ʱ����һ��WM_COMMANDѶϢ������wParam���IDC_RECORD_END����Ӧʱ���Ӵ�ѶϢ������ʽ������mciSendCommand���Σ�MCI_STOP����ѶϢ���ֹͣ¼����MCI_SAVE����ѶϢ��춰��ݴ浵���е��������ϴ��ݵ�MCI_SAVE_PARMS�ṹ��ָ���ĵ�������record2.wav������MCI_CLOSE����ѶϢ���ɾ�����е��ݴ浵�����ͷ��Ѿ������ļ�����鲢�ر��豸��
����ʱ��MCI_OPEN_PARMS�ṹ��lpstrElementName��λ�趨Ϊ��������record2.wav���� mciSendCommand��������������������MCI_OPEN_ELEMENT��DZ�ʾlpstrElementName��λ��һ����Ч�ĵ�������ͨ�������ĸ�������.WAV��MCI֪��ʹ����Ҫ��һ�����������豸��������ڶ������Ӳ�壬��򿪵�һ�����趨MCI_OPEN_PARMS�ṹ��lpstrDeviceType��λ��Ҳ���Դ����������豸����
���Ž���������MCI_PLAY����ѶϢ��MCI_PLAY_PARMS�ṹ��mciSendCommand���С���Ȼ���ε��������ⲿ�ֶ����Բ��ţ���RECORD2ֻ��������������
RECORD2������һ����Pause����ť����ͣ������Ч�����������ť����һ��WM_COMMANDѶϢ������wParam���IDC_PLAY_PAUSE����Ӧʱ����ʽ������mciSendCommand������MCI_PAUSE����ѶϢ��MCI_GENERIC_PARMS�ṹ��Ϊ������MCI_GENERIC_PARMS�ṹ�������һЩѶϢ�����dz�����Ҫ���֪ͨ�Ŀ�ѡ�Ӵ������⣬����Ҫ�κ���Ѷ����������Ѿ���ͣ����ͨ���ٴ�ʹ��MCI_PLAY����ѶϢ����mciSendCommand�������š�
���µڶ�����End����ťҲ����ֹͣ���š���ʱ����wParam���IDC_PLAY_END��WM_COMMANDѶϢ����Ӧʱ���Ӵ�ѶϢ������ʽ������mciSendCommand���Σ���һ��ʹ��MCI_STOP����ѶϢ���ڶ���ʹ��MCI_CLOSE����ѶϢ��
������һ�����⣺��Ȼ����ͨ�����¡�End����ť���ֹ���ֹ���ţ�����������Ҫ����������������ʽ���֪�������������ʱ���أ�����MCI֪ͨѶϢ������
������MCI_RECORD��MCI_PLAYѶϢ������mciSendCommandʱ��RECORD2������MCI_NOTIFY��ǣ��������Ͻṹ��dwCallback��λ�趨Ϊ��ʽ�Ӵ����š������Ͳ���һ��֪ͨѶϢ����ΪMM_MCINOTIFY������ijЩ�����´��ݸ��Ӵ�ѶϢ������ʽ��ѶϢ����wParam��һ��״̬���룬��lParam���豸ID��
����MCI_STOP����MCI_PAUSE����ѶϢ������mciSendCommandʱ���������յ�һ��MM_MCINOTIFYѶϢ������wParam���MCI_NOTIFY_ABORTED���������¡�Pause����ť����������End����ť�е�һ��ʱ���ͻ���������������춶���Щ��ť�ѽ��й��ʵ��Ĵ���������RECORD2���Ժ����������������ʱ����������Ч������������յ�MM_MCINOTIFYѶϢ������wParam���MCI_NOTIFY_SUCCESSFUL����������£��Ӵ�ѶϢ������ʽ���Լ�����һ��WM_COMMANDѶϢ������wParam���IDC_PLAY_END����ģ��ʹ���߰��¡�End����ť��Ȼ���Ӵ�ѶϢ������ʽ����������Ӧ��ֹͣ���ţ��ر��豸��
¼��ʱ�������춴����ݴ浵����Ӳ���ռ䲻�������ͻ����һ��MM_MCINOTIFYѶϢ������wParam���MCI_NOTIFY_SUCCESSFUL����Ȼ���ڻ�����˵�������������书���Ѿ�����ȫ�ˣ�����Ӧʱ���Ӵ�ѶϢ������ʽ���Լ�����һ��WM_COMMANDѶϢ������wParam���IDC_RECORD_END��Ȼ�������������һ����ֹͣ¼�������浵�����ر��豸��
MCI�����ִ��ķ���
��
Windows�Ķ�ý���������������ʽmciExecute�����﷨���£�
bSuccess = mciExecute (szCommand) ;
����Ψһ�IJ�����MCI�����ִ�����ʽ���ز���ֵ��������гɹ����򴫻ط�0ֵ�����򴫻�0���ڹ����ϣ�mciExecute��ʽ��ͬ춺�������������ΪNULL��0��mciSendString��TESTMCI��ʹ�õ������ִ���MCI��ʽ����Ȼ���ڷ�������ʱ����mciGetErrorString��MessageBox��
��ȻmciExecute������API��һ���֣����һ�����RECORD3�����λ¼������ʹ���������ʽ����RECORD2һ����RECORD3��ʽҲʹ��RECORD1�е���Դ������RECORD.RC��RESOURCE.H�����ʽ22-5��ʾ��
��ʽ22-5 RECORD3 RECORD3.C /*--------------------------------------------------------------------------- RECORD3.C -- Waveform Audio Recorder (c) Charles Petzold, 1998 ----------------------------------------------------------------------------*/ #include <windows.h> #include "..\\record1\\resource.h" BOOL CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM) ; TCHAR szAppName [] = TEXT ("Record3") ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { if (-1 == DialogBox (hInstance, TEXT ("Record"), NULL, DlgProc)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; } return 0 ; } BOOL mciExecute (LPCTSTR szCommand) { MCIERROR error ; TCHAR szErrorStr [1024] ; if (error = mciSendString (szCommand, NULL, 0, NULL)) { mciGetErrorString (error, szErrorStr, sizeof (szErrorStr) / sizeof (TCHAR)) ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox ( NULL, szErrorStr, TEXT ("MCI Error"), MB_OK | MB_ICONEXCLAMATION) ; } return error == 0 ; } BOOL CALLBACK DlgProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bRecording, bPlaying, bPaused ; switch (message) { case WM_COMMAND: switch (wParam) { case IDC_RECORD_BEG: // Delete existing waveform file DeleteFile (TEXT ("record3.wav")) ; // Open waveform audio and record if (!mciExecute (TEXT ("open new type waveaudio alias mysound"))) return TRUE ; mciExecute (TEXT ("record mysound")) ; // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE); SetFocus (GetDlgItem (hwnd, IDC_RECORD_END)) ; bRecording = TRUE ; return TRUE ; case IDC_RECORD_END: // Stop, save, and close recording mciExecute (TEXT ("stop mysound")) ; mciExecute (TEXT ("save mysound record3.wav")) ; mciExecute (TEXT ("close mysound")) ; // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE); SetFocus (GetDlgItem (hwnd, IDC_PLAY_BEG)) ; bRecording = FALSE ; return TRUE ; case IDC_PLAY_BEG: // Open waveform audio and play if (!mciExecute (TEXT ("open record3.wav alias mysound"))) return TRUE ; mciExecute (TEXT ("play mysound")) ; // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), TRUE) ; SetFocus (GetDlgItem (hwnd, IDC_PLAY_END)) ; bPlaying = TRUE ; return TRUE ; case IDC_PLAY_PAUSE: if (!bPaused) // Pause the play { mciExecute (TEXT ("pause mysound")) ; SetDlgItemText (hwnd, IDC_PLAY_PAUSE, TEXT ("Resume")) ; bPaused = TRUE ; } else // Begin playing again { mciExecute (TEXT ("play mysound")) ; SetDlgItemText (hwnd, IDC_PLAY_PAUSE, TEXT ("Pause")) ; bPaused = FALSE ; } return TRUE ; case IDC_PLAY_END: // Stop and close mciExecute (TEXT ("stop mysound")) ; mciExecute (TEXT ("close mysound")) ; // Enable and disable buttons EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG), TRUE) ; EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END), FALSE); SetFocus (GetDlgItem (hwnd, IDC_PLAY_BEG)) ; bPlaying = FALSE ; bPaused = FALSE ; return TRUE ; } break ; case WM_SYSCOMMAND: switch (wParam) { case SC_CLOSE: if (bRecording) SendMessage (hwnd, WM_COMMAND, IDC_RECORD_END, 0L); if (bPlaying) SendMessage (hwnd, WM_COMMAND, IDC_PLAY_END, 0L) ; EndDialog (hwnd, 0) ; return TRUE ; } break ; } return FALSE ; }
���о�ѶϢ��������ֵ����MCI����ʱ�����ᷢ�����Ƿdz�����������׾Ϳ��Բ²��MCI�������ִ�ת��Ϊ��Ӧ������ѶϢ�����Ͻṹ��RECORD3����ʹ����RECORD2һ��ʹ��MM_MCINOTIFYѶϢ��������û��ѡ��mciExecute��ʽ�ĺô�������ȱ���dz�ʽ��֪��ʲôʱ�򲥷��겨�ε�������ˣ���Щ��ť�����Զ��ı�״̬���������˹����¡�End����ť���Ա��ó�ʽ֪�����Ѿ�׼���ٴ�¼���򲥷š�
ע��MCI��open������alias�ؼ��ֵ��÷�������������������MCI����ʹ�ñ����������豸��
��������������ʽ
��
�����ʮ����λת����ʽ���о�δѹ����.WAV��������PCM�������ᷢ�����Ǿ��б�22-1��ʾ�ĸ�ʽ��
��22-1 .WAV������ʽ |
ƫ���� | λԪ�� | ���� |
---|---|---|
0000 | 4 | ��RIFF�� |
0004 | 4 | ���ο�Ĵ�С��������С��8�� |
0008 | 4 | ��WAVE�� |
000C | 4 | ��fmt �� |
0010 | 4 | ��ʽ��Ĵ�С��16λԪ�飩 |
0014 | 2 | wf.wFormatTag = WAVE_FORMAT_PCM = 1 |
0016 | 2 | wf.nChannels |
0018 | 4 | wf.nSamplesPerSec |
001C | 4 | wf.nAvgBytesPerSec |
0020 | 2 | wf.nBlockAlign |
0022 | 2 | wf.wBitsPerSample |
0024 | 4 | ��data�� |
0028 | 4 | �������ϵĴ�С |
002C | �������� |
����һ��������RIFF��Resource Interchange File Format����Դ����������ʽ���ĸ�ʽ��RIFF����춶�ý�����ϵ��������ø�ʽ������һ�ֱ�ǵ�����ʽ�������ָ�ʽ�£����������ϡ��项��ɣ�����Щ���Ͽ�����ǰ��4����Ԫ��ASCII���ƺ�4λԪ�飨32λԪ�������Ͽ��С��ȷ�ϡ����Ͽ��Сֵ���������ƺʹ�С����Ҫ��8λԪ�顣
�������������������ִ���RIFF����ʼ��������ʶ����һ��RIFF�������ִ�������һ��32λԪ�����Ͽ��С����ʾ�������ಿ�ֵĴ�С��������С�8λԪ��ĵ�����С��
���Ͽ��������ִ���WAVE����ʼ��������ʶ����һ�����������飬�����������ִ���fmt����ע���ÿհ�ʹ֮��Ϊ4��Ԫ���ִ���������ʶ���������������ϸ�ʽ�������Ͽ顣��fmt���ִ��������Ǹ�ʽ��Ѷ��С��������16λԪ�顣��ʽ��Ѷ��WAVEFORMATEX�ṹ��ǰ16��λԪ�飬���ߣ����������ʱһ�����ǰ���WAVEFORMAT�ṹ��PCMWAVEFORMAT�ṹ��
nChannels��λ��ֵ��1��2���ֱ��Ӧ춵���������������nSamplesPerSec��λ��ÿ�������������׼ֵ��ÿ��11,025��22,050��44 100��������nAvgBytesPerSec��λ��ȡ�����ʣ���λ��ÿ������������ͨ�������ٳ�����λԪΪ��λ��ÿ�������Ĵ�С��Ȼ�����8������ȡ��������׼������С��8λԪ��16λԪ��nBlockAlign��λ��ͨ����������λԪΪ��λ��������С��Ȼ�����8������ȡ���������ᣬ�ø�ʽ��wBitsPerSample��λ����������λ��ͨ����������λԪΪ��λ��������С��
��ʽ��Ѷ�������������ִ���data����Ȼ����32λԪ�����ϴ�С�������Dz������ϱ�������Щ�����ǰ���ͬ��ʽ���м����������������ͽײ��������豸����ʹ�õĸ�ʽ��ͬ�����������С��8λԪ�����߸��٣���ôÿ��������1λԪ����춵�������������2λԪ����������������������С��9��16λԪ֮�䣬��ÿ����������2λԪ����춵�����������4λԪ�����������������������������ϣ�ÿ������������ֵ�����������ֵ��ɡ�
���8λԪ�򲻵�8λԪ��������С������λԪ�鱻����Ϊ��������ֵ�����磬���8λԪ��������С���������0x80λԪ����ִ������9λԪ������������С������������Ϊ��������ֵ����ʱ�������ִ����ֵ0��
��춶�ȡ��ǵ�����һ����Ҫ�����Ǻ��Բ�׼�����������Ͽ顣���ܲ�������������Ҫ��fmt���͡�data�������Ͽ飨���մ�˳�򣩣��������������������Ͽ顣�����ǣ����������������ܰ���һ�����Ϊ��INFO���������Ͽ飬���ṩ��������������Ѷ�������Ͽ�������Ͽ顣
���Ӻϳ�ʵ��
��
�������������ٴӱϴ����˹����������Ǿ��Ѿ���ͼ�����������������dz��򵥣�������ͱ�ø����ˡ���Ǹ���ҽ��ظ�һЩ�Ѿ�˵�����й����������⡣
����������һЩײ�������⣬���������������Ƶ�ʡ����Ƶ�ʿ����������ܹ����ܵ���Ƶ�׷�Χ�ڣ�Ҳ���Ǵ�20Hz��20,000Hz���ڡ����磬���ٵ�Ƶ�ʷ�Χ��27.5Hz��4186Hz֮�䡣��������һ����������������ȡ�������������IJ��ε�����������Ӧ����ȵı仯�÷ֱ�����������Ϊֹ��һ�ж��ܺá�
Ȼ����һ���Ѱ���³��������ʡ����dz��򵥣����ʾ������������ʣ������������ǿ������ְ���ͬ������ͬ��������ĸ��١�С���ٺ����ȡ�
������ѧ��Fourier����һЩ�����ԵIJ��Σ����۶�ô���ӣ����Ƕ����Ա�ʾΪ����Ƶ���ǻ���Ƶ�������������Ҳ��Ρ��������Ƶ�ʣ�Ҳ������һ��г�����Dz������ڵ�Ƶ�ʡ���һ��������Ҳ��������г�����ǻ���Ƶ�ʵ��������ڶ�����������������г����Ƶ���ǻ���Ƶ�ʵ��������������ơ�г��������໥��ϵ�γ��˲��ε���״��
���磬�������Ա�ʾΪ��������Ҳ�������ż��г������2��4��6�ȵȣ����������0��������г������1��3��5�ȵȣ����������1��1/3��1/5�����������ơ��ھ�ݲ��У����еķ��������֣����������1��1/2��1/3��1/4�����������ơ�
��춵¹���ѧ��Hermann Helmholtz��1821-1894���������˽����ʵĹؼ���������������On the Sensations of Tone����1885�꣬1954����Dover Press�ٰ棩�У�Helmholtz�ٶ�����ʹ��Խ����ӵ������ֽ�Ϊ���Ҳ�������Щ���Ҳ���ص�ǿ�Ⱦ������������ܵ����ʡ����ҵ��ǣ����黹û����ô�򵥡�
����1968��Wendy Carlos�ij�Ƭ��Switched on Bach���ķ������������ֺϳ��������˹��ڵĹ㷺ע�⡣��ʱʹ�õĺϳ���������Moog������Ⱥϳ�������Щ�ϳ���ʹ����ȵ�·�����������������Σ����緽�������Dz��κ;�ݲ��Ρ�Ҫʹ��Щ����������������ʵ������������ȡ��춵��������ı仯���򡣲��ε���������ԡ����磨envelope�����γɡ���������ʼʱ�������0��ʼ���ӣ�ͨ�����ӷdz��졣�������ν�����ࡣȻ�ᵱ��������ʱ���������Ϊ��������ʱ��Ϊ��������������ʱ�������Ϊ0����ʱ��Ϊ�ͷš�
����ͨ���˲������˲���������һЩг���������򵥲���ת���ø����ӡ������ָС���Щ�˲������ж�Ƶ���ɰ�����ƣ��Ա�������г�������������ij����иı䡣
��Ϊ��Щ�ϳ����Էḻ�IJ��θ�ʽ���Ϳ�ʼ������һЩг��ͨ���˲���������������������ʽ�ĺϳɳ�Ϊ�����ϳɡ���
��ʹ�ڸ��ϳ��ڼ䣬������Ҳ�����ڵ��������з��ֵ��Ӻϳ�����һ�������⡣
�ڵ��Ӻϳ��У������Դ��������������Ҳ���������ʼ��ѡ���������Ա��ÿ�����Ҳ�����Ӧһ��г����ÿ��г�����������һ�����絥�����ơ�ʹ����ȵ�·�ĵ��Ӻϳɲ�ʵ�ã���Ϊ�Ե�����������Ҫ8��24֮����Ŀ�����Ҳ���������������Щ���Ҳ���������ص�Ƶ�ʱ��뾫ȷ�Ļ�����롣��Ȳ����������ȶ��Ժܲ�������׷���Ƶ��Ư�ơ�
����������λ�ϳ�����������λ����ʹ�ö��ձ��������Σ��͵��Բ����IJ��Σ�Ƶ��Ư�Ʋ����Ǹ����⣬������Ӻϳ�Ҳ����ʵ�����ˡ�����ܵ���˵����¼����ʵ������ʱ��������Fourier�ֽⷨ����ֽ�ɶ��г����Ȼ��Ϳ���ȷ��ÿ��г�������ǿ�ȣ����ö�����Ҳ���λ���ز���������
�����ʼʵ��ʱ��Fourier����������ʵ�ʵ����������Ӷ�����Ҳ���������Щ��������ô���ǽ��������ʲ�����Helmholtz����Ϊ�������򵥡�
������������ʵ������г��֮�䲢û�о�ȷ��������ϵ����ʵ�ϣ���г����һ�ʶ��ʵ�ʵ�������˵����ʮ���ʵ����������Ҳ���ɶ�����г�����߸�׼ȷ��˵�ǡ���������
���Ƿ��֣�ʵ����������֮��IJ���г�ڴ��졸��ʵ�ġ�����ʱ����Ҫ����̬��г�����������������ÿ���������ڵ��������ϸı������Ƶ�ʡ������У����Ƶ�ʺ�����Ĺ�ϵ��춲�ͬ�ķ����Լ�������ͬ�����IJ�ͬǿ���Dz�ͬ�ġ�ʵ����������ӵIJ��ַ��������������ಿ�֣���ʱ�Ƚϲ���г�����Ƿ���������������ӵ�����λ�ö������������ʺ���Ҫ��
�����֮��ʵ���������������κ�����Ķ������ӡ����������Ĺ۵㣬�Լ�������춿��Ʒ����������Ƶ�ʵ���Լ򵥵İ���۵���Ȼ����ʵ�á�
ʵ��������һЩ��������������ڣ�1977��1978��䣩�ġ�Computer Music Journal������ʱ��People's Computer Company���У�������MIT Press���У���James A. Moorer��John Grey��John Strawn Some��д�˵������ִ��顶Lexicon of Analyzed Tones����������ʾ����С���١�˫�ɹܡ����ɹܺ�����������һ��������С춰����֣��ķ����������Ƶ��ͼ�Ρ����õ�����������C�ϵĽ�E��С������20��������˫�ɹܺ͵��ɹ���21������������12����ʵ���ϣ���Computer Music Journal����Volume II��Number 2��1978��9�£����������߶�������˫�ɹܡ����ɹܺ����ȵIJ�ͬƵ�ʺ�����İ��硣
��ˣ�����Windows��֧Ԯ���������ι��ܣ�����ij���ܼòµ¥£ï¿½ï¿½ï¿½ï¿½ï¿½Ð©ï¿½ï¿½ï¿½Ö¼ï¿½ï¿½ï¿½ï¿½Ê½ï¿½ï¿½ÎªÃ¿ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½Ò²ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½Ð©ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ä·¢ï¿½Í¸ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½Ð§ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½Ë°ï¿½20��ǰÔʼ¼�Ƶ����������������Ҳ�����ס�ADDSYNTH�������Ӻϳɡ������ʽ22-6��ʾ��
��ʽ22-6 ADDSYNTH ADDSYNTH.C /*-------------------------------------------------------------------------- ADDSYNTH.C -- Additive Synthesis Sound Generation (c) Charles Petzold, 1998 ---------------------------------------------------------------------------*/ #include <windows.h> #include <math.h> #include "addsynth.h" #include "resource.h" #define ID_TIMER 1 #define SAMPLE_RATE 22050 #define MAX_PARTIALS 21 #define PI 3.14159 BOOL CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM) ; TCHAR szAppName [] = TEXT ("AddSynth") ; // Sine wave generator // ------------------- double SineGenerator (double dFreq, double * pdAngle) { double dAmp ; dAmp = sin (* pdAngle) ; * pdAngle += 2 * PI * dFreq / SAMPLE_RATE ; if (* pdAngle >= 2 * PI) * pdAngle -= 2 * PI ; return dAmp ; } // Fill a buffer with composite waveform // ------------------------------------- VOID FillBuffer (INS ins, PBYTE pBuffer, int iNumSamples) { static double dAngle [MAX_PARTIALS] ; double dAmp, dFrq, dComp, dFrac ; int i, iPrt, iMsecTime, iCompMaxAmp, iMaxAmp, iSmp ; // Calculate the composite maximum amplitude iCompMaxAmp = 0 ; for (iPrt = 0 ; iPrt < ins.iNumPartials ; iPrt++) { iMaxAmp = 0 ; for (i = 0 ; i < ins.pprt[iPrt].iNumAmp ; i++) iMaxAmp = max (iMaxAmp, ins.pprt[iPrt].pEnvAmp[i].iValue) ; iCompMaxAmp += iMaxAmp ; } // Loop through each sample for (iSmp = 0 ; iSmp < iNumSamples ; iSmp++) { dComp = 0 ; iMsecTime = (int) (1000 * iSmp / SAMPLE_RATE) ; // Loop through each partial for (iPrt = 0 ; iPrt < ins.iNumPartials ; iPrt++) { dAmp = 0 ; dFrq = 0 ; for (i = 0 ; i < ins.pprt[iPrt].iNumAmp - 1 ; i++) { if (iMsecTime >= ins.pprt[iPrt].pEnvAmp[i ].iTime && iMsecTime <= ins.pprt[iPrt].pEnvAmp[i+1].iTime) { dFrac = (double) (iMsecTime - ins.pprt[iPrt].pEnvAmp[i ].iTime) / (ins.pprt[iPrt].pEnvAmp[i+1].iTime - ins.pprt[iPrt].pEnvAmp[i ].iTime) ; dAmp = dFrac * ins.pprt[iPrt].pEnvAmp[i+1].iValue + (1-dFrac) * ins.pprt[iPrt].pEnvAmp[i ].iValue ; break ; } } for (i = 0 ; i < ins.pprt[iPrt].iNumFrq - 1 ; i++) { if (iMsecTime >= ins.pprt[iPrt].pEnvFrq[i ].iTime && iMsecTime <= ins.pprt[iPrt].pEnvFrq[i+1].iTime) { dFrac = (double) (iMsecTime -ins.pprt[iPrt].pEnvFrq[i ].iTime) / (ins.pprt[iPrt].pEnvFrq[i+1].iTime - ins.pprt[iPrt].pEnvFrq[i ].iTime) ; dFrq = dFrac * ins.pprt[iPrt].pEnvFrq[i+1].iValue + (1-dFrac) * ins.pprt[iPrt].pEnvFrq[i ].iValue ; break ; } } dComp += dAmp * SineGenerator (dFrq, dAngle + iPrt) ; } pBuffer[iSmp] = (BYTE) (127 + 127 * dComp / iCompMaxAmp) ; } } // Make a waveform file // ------------------------------------------------------------------------- BOOL MakeWaveFile (INS ins, TCHAR * szFileName) { DWORD dwWritten ; HANDLE hFile ; int iChunkSize, iPcmSize, iNumSamples ; PBYTE pBuffer ; WAVEFORMATEX waveform ; hFile = CreateFile (szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) ; if (hFile == NULL) return FALSE ; iNumSamples = ((long) ins.iMsecTime * SAMPLE_RATE / 1000 + 1) / 2 * 2 ; iPcmSize = sizeof (PCMWAVEFORMAT) ; iChunkSize = 12 + iPcmSize + 8 + iNumSamples ; if (NULL == (pBuffer = malloc (iNumSamples))) { CloseHandle (hFile) ; return FALSE ; } FillBuffer (ins, pBuffer, iNumSamples) ; waveform.wFormatTag = WAVE_FORMAT_PCM ; waveform.nChannels = 1 ; waveform.nSamplesPerSec = SAMPLE_RATE ; waveform.nAvgBytesPerSec = SAMPLE_RATE ; waveform.nBlockAlign = 1 ; waveform.wBitsPerSample = 8 ; waveform.cbSize = 0 ; WriteFile (hFile, "RIFF", 4, &dwWritten, NULL) ; WriteFile (hFile, &iChunkSize, 4, &dwWritten, NULL) ; WriteFile (hFile, "WAVEfmt ", 8, &dwWritten, NULL) ; WriteFile (hFile, &iPcmSize, 4, &dwWritten, NULL) ; WriteFile (hFile, &waveform, sizeof (WAVEFORMATEX) - 2, &dwWritten, NULL) ; WriteFile (hFile, "data", 4, &dwWritten, NULL) ; WriteFile (hFile, &iNumSamples, 4, &dwWritten, NULL) ; WriteFile (hFile, pBuffer, iNumSamples, &dwWritten, NULL) ; CloseHandle (hFile) ; free (pBuffer) ; if ((int) dwWritten != iNumSamples) { DeleteFile (szFileName) ; return FALSE ; } return TRUE ; } void TestAndCreateFile ( HWND hwnd, INS ins, TCHAR * szFileName, int idButton) { TCHAR szMessage [64] ; if (-1 != GetFileAttributes (szFileName)) EnableWindow (GetDlgItem (hwnd, idButton), TRUE) ; else { if (MakeWaveFile (ins, szFileName)) EnableWindow (GetDlgItem (hwnd, idButton), TRUE) ; else { wsprintf (szMessage, TEXT ("Could not create %x."), szFileName) ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szMessage, szAppName, MB_OK | MB_ICONEXCLAMATION) ; } } } int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { if (-1 == DialogBox (hInstance, szAppName, NULL, DlgProc)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; } return 0 ; } BOOL CALLBACK DlgProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static TCHAR * szTrum = TEXT ("Trumpet.wav") ; static TCHAR * szOboe = TEXT ("Oboe.wav") ; static TCHAR * szClar = TEXT ("Clarinet.wav") ; switch (message) { case WM_INITDIALOG: SetTimer (hwnd, ID_TIMER, 1, NULL) ; return TRUE ; case WM_TIMER: KillTimer (hwnd, ID_TIMER) ; SetCursor (LoadCursor (NULL, IDC_WAIT)) ; ShowCursor (TRUE) ; TestAndCreateFile (hwnd, insTrum, szTrum, IDC_TRUMPET) ; TestAndCreateFile (hwnd, insOboe, szOboe, IDC_OBOE) ; TestAndCreateFile (hwnd, insClar, szClar, IDC_CLARINET) ; SetDlgItemText (hwnd, IDC_TEXT, TEXT (" ")) ; SetFocus (GetDlgItem (hwnd, IDC_TRUMPET)) ; ShowCursor (FALSE) ; SetCursor (LoadCursor (NULL, IDC_ARROW)) ; return TRUE ; case WM_COMMAND: switch (LOWORD (wParam)) { case IDC_TRUMPET: PlaySound (szTrum, NULL, SND_FILENAME | SND_SYNC) ; return TRUE ; case IDC_OBOE: PlaySound (szOboe, NULL, SND_FILENAME | SND_SYNC) ; return TRUE ; case IDC_CLARINET: PlaySound (szClar, NULL, SND_FILENAME |SND_SYNC) ; return TRUE ; } break ; case WM_SYSCOMMAND: switch (LOWORD (wParam)) { case SC_CLOSE: EndDialog (hwnd, 0) ; return TRUE ; } break ; } return FALSE ; }
ADDSYNTH.RC ��ժ¼�� //Microsoft Developer Studio generated resource script. #include "resource.h" #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// // Dialog ADDSYNTH DIALOG DISCARDABLE 100, 100, 176, 49 STYLE WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU CAPTION "Additive Synthesis" FONT 8, "MS Sans Serif" BEGIN PUSHBUTTON "Trumpet",IDC_TRUMPET,8,8,48,16 PUSHBUTTON "Oboe",IDC_OBOE,64,8,48,16 PUSHBUTTON "Clarinet",IDC_CLARINET,120,8,48,16 LTEXT "Preparing Data...",IDC_TEXT,8,32,100,8 END
RESOURCE.H ��ժ¼�� // Microsoft Developer Studio generated include file. // Used by AddSynth.rc #define IDC_TRUMPET 1000 #define IDC_OBOE 1001 #define IDC_CLARINET 1002 #define IDC_TEXT 1003
����û�и������ӵ���ADDSYNTH.H����Ϊ��������������������������������ڱ��鸽�ϵĹ�����ҵ�������ADDSYNTH.H�Ŀ�ʼλ�ã��Ҷ����������ṹ����춴���������ϡ�ÿ�������Ƶ�ʷֱ𴢴浽��̬ENV�Ľṹ�����С���Щ���ֶ���ʱ�䣨���룩�����ֵ�������������λ����Ƶ�ʣ�������/��Ϊ��λ����ɡ���Щ���еij��ȿɱ䣬��仯��Χ��6��14���ٶ������Ƶ��ֵ֮��ֱ����ء�
ÿ������������һ����������������12����˫�ɹܺ͵��ɹֱܷ�ʹ��21��������Щ��������������̬PRT�Ľṹ�����С�PRT�ṹ���������Ƶ�ʰ���ĵ������Լ�ָ��ENV���е�ָ�ꡣINS�ṹ������������ʱ�䣨�Ժ���Ϊ��λ�����������Լ�ָ�򴢴淺����PRT���е�ָ�ꡣ
ADDSYNTH���������Ϊ��Trumpet������Oboe���͡�Clarinet���İ�ť��PC���ٶȻ�û�п쵽���Լ�ʱ�������еĵ��Ӻϳɣ���˵�һ��ִ��ADDSYNTHʱ����Щ��ť��ʧЧ��ֱ����ʽ������������������TRUMPET.WAV��OBOE.WAV��CLARINET.WAV��Ч�����ᣬ��ť�����������ҿ���ʹ��PlaySound��ʽ�����������������´�ִ��ʱ����ʽ����鲨�ε����Ƿ���ڣ����������½�����
ADDSYNTH�е�FillBuffer��ʽ����˴����������FillBuffer�Ӽ���ϳ���������������ʼ��Ϊ�ˣ����������ķ����л�Ȧ�����ҳ�ÿ����������������Ȼ�Ὣ���е�����������������ֵ������춽��������ŵ�8λԪ��������С��
Ȼ��FillBuffer����ÿ��������ֵ��ÿ����������Ӧ�һ���Ժ���Ϊ��λ��ʱ�䣬��ʱ��ȡ���ȡ��Ƶ�ʣ�ʵ���ϣ���22.05 kHz��ȡ��Ƶ���£�ÿ22��������Ӧ���ͬ�ĺ���ʱ��ֵ����Ȼ�ᣬFillBuffer�ڷ����л�Ȧ�����Ƶ�ʺ���������ҳ������ʱ��ֵ��Ӧ�İ����߶Σ���ִ�����Բ岹��
Ƶ��ֵ����λ��ֵһ�𴫵ݸ�SineGenerator��ʽ������ǰ�����۹���������λ�������Ҳ�����Ҫ������λ��ֵ��������Ƶ��ֵ���ӡ���SineGenerator��ʽ����ʱ������ֵ�����Է�����������ۼӡ����������з�������������֮�ᣬ���������ŵ�λԪ���С��
�𴲺Ų�������
��
WAKEUP�����ʽ22-7��ʾ����Ôʼ�뵵�����������Ǻ������ij�ʽ֮һ����ʽ�Ӵ���������Ի����飬����û����Դ�������������Ѿ�֪����α�д�������ҳ�ʽʹ��һ�����ε��������ڹ����ȴû�������ĵ�������������ʽ�dz���Ȥ�������ŵ������ܴ󣬲��ҷdz��������ᡣWAKEUP���ҵ����ӣ��ܹ������Ҽ���������
��ʽ22-7 WAKEUP WAKEUP.C /*--------------------------------------------------------------------------- WAKEUP.C -- Alarm Clock Program (c) Charles Petzold, 1998 ---------------------------------------------------------------------------*/ #include <windows.h> #include <commctrl.h> // ID values for 3 child windows #define ID_TIMEPICK 0 #define ID_CHECKBOX 1 #define ID_PUSHBTN 2 // Timer ID #define ID_TIMER 1 // Number of 100-nanosecond increments (ie FILETIME ticks) in an hour #define FTTICKSPERHOUR (60 * 60 * (LONGLONG) 10000000) // Defines and structure for waveform "file" #define SAMPRATE 11025 #define NUMSAMPS (3 * SAMPRATE) #define HALFSAMPS (NUMSAMPS / 2) typedef struct { char chRiff[4] ; DWORD dwRiffSize ; char chWave[4] ; char chFmt [4] ; DWORD dwFmtSize ; PCMWAVEFORMAT pwf ; char chData[4] ; DWORD dwDataSize ; BYTE byData[0] ; } WAVEFORM ; // The window proc and the subclass proc LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; LRESULT CALLBACK SubProc (HWND, UINT, WPARAM, LPARAM) ; // Original window procedure addresses for the subclassed windows WNDPROC SubbedProc [3] ; // The current child window with the input focus HWND hwndFocus ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInst, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName [] = TEXT ("WakeUp") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = 0 ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) (1 + COLOR_BTNFACE) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow ( szAppName, szAppName, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hwndDTP, hwndCheck, hwndPush ; static WAVEFORM waveform = { "RIFF", NUMSAMPS + 0x24, "WAVE", "fmt ", sizeof (PCMWAVEFORMAT), 1, 1, SAMPRATE, SAMPRATE, 1, 8, "data", NUMSAMPS } ; static WAVEFORM * pwaveform ; FILETIME ft ; HINSTANCE hInstance ; INITCOMMONCONTROLSEX icex ; int i, cxChar, cyChar ; LARGE_INTEGER li ; SYSTEMTIME st ; switch (message) { case WM_CREATE: // Some initialization stuff hInstance = (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE) ; icex.dwSize = sizeof (icex) ; icex.dwICC = ICC_DATE_CLASSES ; InitCommonControlsEx (&icex) ; // Create the waveform file with alternating square waves pwaveform = malloc (sizeof (WAVEFORM) + NUMSAMPS) ; * pwaveform = waveform ; for (i = 0 ; i < HALFSAMPS ; i++) if (i % 600 < 300) if (i % 16 < 8) pwaveform->byData[i] = 25 ; else pwaveform->byData[i] = 230 ; else if (i % 8 < 4) pwaveform->byData[i] = 25 ; else pwaveform->byData[i] = 230 ; // Get character size and set a fixed window size. cxChar = LOWORD (GetDialogBaseUnits ()) ; cyChar = HIWORD (GetDialogBaseUnits ()) ; SetWindowPos ( hwnd, NULL, 0, 0, 42 * cxChar, 10 * cyChar / 3 + 2 * GetSystemMetrics (SM_CYBORDER) +GetSystemMetrics (SM_CYCAPTION) ,SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE) ; // Create the three child windows hwndDTP = CreateWindow (DATETIMEPICK_CLASS, TEXT (""), WS_BORDER | WS_CHILD | WS_VISIBLE | DTS_TIMEFORMAT, 2 * cxChar, cyChar, 12 * cxChar, 4 * cyChar / 3, hwnd, (HMENU) ID_TIMEPICK, hInstance, NULL) ; hwndCheck = CreateWindow (TEXT ("Button"), TEXT ("Set Alarm"), WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 16 * cxChar, cyChar, 12 * cxChar, 4 * cyChar / 3, hwnd, (HMENU) ID_CHECKBOX, hInstance, NULL) ; hwndPush = CreateWindow (TEXT ("Button"), TEXT ("Turn Off"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED, 28 * cxChar, cyChar, 12 * cxChar, 4 * cyChar / 3, hwnd, (HMENU) ID_PUSHBTN, hInstance, NULL) ; hwndFocus = hwndDTP ; // Subclass the three child windows SubbedProc [ID_TIMEPICK] = (WNDPROC) SetWindowLong (hwndDTP, GWL_WNDPROC, (LONG) SubProc) ; SubbedProc [ID_CHECKBOX] = (WNDPROC) SetWindowLong (hwndCheck, GWL_WNDPROC, (LONG) SubProc); SubbedProc [ID_PUSHBTN] = (WNDPROC) SetWindowLong (hwndPush, GWL_WNDPROC, (LONG) SubProc) ; // Set the date and time picker control to the current time // plus 9 hours, rounded down to next lowest hour GetLocalTime (&st) ; SystemTimeToFileTime (&st, &ft) ; li = * (LARGE_INTEGER *) &ft ; li.QuadPart += 9 * FTTICKSPERHOUR ; ft = * (FILETIME *) &li ; FileTimeToSystemTime (&ft, &st) ; st.wMinute = st.wSecond = st.wMilliseconds = 0 ; SendMessage (hwndDTP, DTM_SETSYSTEMTIME, 0, (LPARAM) &st) ; return 0 ; case WM_SETFOCUS: SetFocus (hwndFocus) ; return 0 ; case WM_COMMAND: switch (LOWORD (wParam)) // control ID { case ID_CHECKBOX: // When the user checks the "Set Alarm" button, get the // time in the date and time control and subtract from // it the current PC time. if (SendMessage (hwndCheck, BM_GETCHECK, 0, 0)) { SendMessage (hwndDTP, DTM_GETSYSTEMTIME, 0, (LPARAM) &st) ; SystemTimeToFileTime (&st, &ft) ; li = * (LARGE_INTEGER *) &ft ; GetLocalTime (&st) ; SystemTimeToFileTime (&st, &ft) ; li.QuadPart -= ((LARGE_INTEGER *) &ft)->QuadPart ; // Make sure the time is between 0 and 24 hours! // These little adjustments let us completely ignore // the date part of the SYSTEMTIME structures. while ( li.QuadPart < 0) li.QuadPart += 24 * FTTICKSPERHOUR ; li.QuadPart %= 24 * FTTICKSPERHOUR ; // Set a one-shot timer! (See you in the morning.) SetTimer (hwnd, ID_TIMER, (int) (li.QuadPart / 10000), 0) ; } // If button is being unchecked, kill the timer. else KillTimer (hwnd, ID_TIMER) ; return 0 ; // The "Turn Off" button turns off the ringing alarm, and also // unchecks the "Set Alarm" button and disables itself. case ID_PUSHBTN: PlaySound (NULL, NULL, 0) ; SendMessage (hwndCheck, BM_SETCHECK, 0, 0) ; EnableWindow (hwndDTP, TRUE) ; EnableWindow (hwndCheck, TRUE) ; EnableWindow (hwndPush, FALSE) ; SetFocus (hwndDTP) ; return 0 ; } return 0 ; // The WM_NOTIFY message comes from the date and time picker. // If the user has checked "Set Alarm" and then gone back to // change the alarm time, there might be a discrepancy between // the displayed time and the one-shot timer. So the program // unchecks "Set Alarm" and kills any outstanding timer. case WM_NOTIFY: switch (wParam) // control ID { case ID_TIMEPICK: switch (((NMHDR *) lParam)->code) // notification code { case DTN_DATETIMECHANGE: if (SendMessage (hwndCheck, BM_GETCHECK, 0, 0)) { KillTimer (hwnd, ID_TIMER) ; SendMessage (hwndCheck, BM_SETCHECK, 0, 0) ; } return 0 ; } } return 0 ; // The WM_COMMAND message comes from the two buttons. case WM_TIMER: // When the timer message comes, kill the timer (because we only // want a one-shot) and start the annoying alarm noise going. KillTimer ( hwnd, ID_TIMER) ; PlaySound ( (PTSTR) pwaveform, NULL, SND_MEMORY | SND_LOOP | SND_ASYNC); // Let the sleepy user turn off the timer by slapping the // space bar. If the window is minimized, it's restored; then // it's brought to the forefront; then the pushbutton is enabled // and given the input focus. EnableWindow (hwndDTP, FALSE) ; EnableWindow (hwndCheck, FALSE) ; EnableWindow (hwndPush, TRUE) ; hwndFocus = hwndPush ; ShowWindow (hwnd, SW_RESTORE) ; SetForegroundWindow (hwnd) ; return 0 ; // Clean up if the alarm is ringing or the timer is still set. case WM_DESTROY: free (pwaveform) ; if (IsWindowEnabled (hwndPush)) PlaySound (NULL, NULL, 0) ; if (SendMessage (hwndCheck, BM_GETCHECK, 0, 0)) KillTimer (hwnd, ID_TIMER) ; PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; } LRESULT CALLBACK SubProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { int idNext, id = GetWindowLong (hwnd, GWL_ID) ; switch (message) { case WM_CHAR: if (wParam == '\t') { idNext = id ; do idNext = (idNext + (GetKeyState (VK_SHIFT) < 0 ? 2 : 1)) % 3 ; while (!IsWindowEnabled (GetDlgItem (GetParent (hwnd), idNext))); SetFocus (GetDlgItem (GetParent (hwnd), idNext)) ; return 0 ; } break ; case WM_SETFOCUS: hwndFocus = hwnd ; break ; } return CallWindowProc ( SubbedProc [id], hwnd, message, wParam,lParam) ; }
WAKEUPʹ�õIJ���ֻ���������������DZ仯Ѹ�١�ʵ�ʵIJ�����WndProc��WM_CREATEѶϢ�����ڼ���㡣���еIJ��ε����������ڼ������С�ָ�������������ָ�괫�ݸ�PlaySound��ʽ���ú�ʽʹ��SND_MEMORY��SND_LOOP��SND_ASYNC������
WAKEUPʹ�ó�Ϊ��Date-Time Picker����ͨ�ÿ�������������������ʹ����ѡ��ָ�������ں�ʱ�䣨WAKEUPֻʹ��ʱ����ѡ���ܣ�����ʽ����ʹ��SYSTEMTIME�ṹ����ú��趨ʱ�䣬�ڻ�ú��趨PC����ʱ��ʱҲʹ�øýṹ��Ҫ�෽���˽�Date-Time Picker�������������������κ�DTS��ʽ�����Ӵ���
ע��WM_CREATEѶϢ����ʱ�Ĵ�����ʽ����ʽ�ٶ�����˯��֮ǰִ��������ϣ������8Сʱ֮������������
���ں����ԣ����Դ�GetLocalTime��ʽ��SYSTEMTIME�ṹ���Ŀǰʱ�䣬���ҿ��ԡ��ֹ�������ʱ�䡣����һ������£��˼��㽫�漰�����24Сʱ�Ľ��ʱ�䣬����ζ������������������λ��Ȼ������漰�����£���˻����������ÿ����������������߼��������������ܻ�Ҫ�����ꡣ
��ʵ�ϣ��Ƽ��ķ���������/Platform SDK/Windows Base Services/General Library/Time/Time Reference/Time Structures/SYSTEMTIME���ǽ�SYSTEMTIMEת��ΪFILETIME�ṹ��ʹ��SystemTimeToFileTime������FILETIME�ṹǿ��ת��ΪLARGE_INTEGER�ṹ���ڴ�������ִ�м��㣬��ǿ��ת����FILETIME�ṹ��Ȼ��ת����SYSTEMTIME�ṹ��ʹ��FileTimeToSystemTime����
����˼�壬FILETIME�ṹ��춻�ú��趨��������һ�θ��µ�ʱ�䡣�˽ṹ���£�
type struct _FILETIME // ft { DWORD dwLowDateTime ; DWORD dwHighDateTime ; } FILETIME ;
��������λһ���ʾ�˴�1601��1��1����ÿ��1000�ڷ�֮һ������ʾ��64λԪֵ��
Microsoft C/C++������֧Ԯ64λԪ������ΪANSI C�ķDZ�׼�����﷨��������̬��__int64�������Զ�__int64��ִ̬�����еij����������㣬������һЩִ��ʱ�ڳ�ʽ�⺯ʽҲ֧Ԯ���ǡ�Windows��WINNT.H��ͷ�����������£�
typedef __int64 LONGLONG ; typedef unsigned __int64 DWORDLONG ;
��Windows�У�����ʱ��Ϊ�������项�����߸��ձ�س�Ϊ������������Ҳ��һ��union�������£�
typedef union _LARGE_INTEGER { struct { DWORD LowPart ; LONG HighPart ; } ; LONGLONG QuadPart ; } LARGE_INTEGER ;
����/Platform SDK/Windows Base Services/General Library/Large Integer Operations�е�ȫ���ļ�����union������ʹ��32λԪ����64λԪ�Ĵ�������
MIDI������
��
�ɵ������ֺϳ���������Ð����19����80������ڿ����ˡ�������λ�����桹��MIDI��Musical Instrument Digital Interface����MIDI����춽������еĵ����������������������Ð����Ҳ�ǵ��������������൱��Ҫ�ı�׼��MIDI�淶��MIDI Manufacturers Association��MMA��ά����������վ��
http://www.midi.org ��
ʹ��MIDI
��
MIDIΪ͸��������������λ������˴���Ð����MIDI����ʹ��5��DIN��ͷ������ֻʹ����������ͷ��һ�������֣�һ���ǻ�·�����������������ϡ�MIDIÐ����ÿ��31,250λԪ���ٶ����ǵ���ġ����ϵ�ÿ��λԪ�鶼��һ����ʼλԪ��ʼ����һ��ֹͣλԪ���������ÿ��3,125λԪ�����Ч�������ʡ�
��Ҫ����Ҫ�˽���ʵ����������������ȸ�ʽ������λ��ʽ�����Ǿ���MIDI���´���ġ�ͨ�����´����ͨ�����Ǽ򵥵�����ѶϢ������һ����1��2��3λԪ�顣
�򵥵�MIDI�趨���԰�����ƬMIDI����Ӳ�塣һ���DZ��������������ǵ�������MIDIѶϢ��MIDI���̡��˼�����һ���б���С�MIDI Out����MIDI������MIDI���½��������MIDI�����ϳ����ġ�MIDI In���������������ϳ�������������ǰ���м�����ť��С���ӡ�
���¼����ϵ�һ����ʱ���ٶ�������C�������̾ͽ�3��λԪ�鷢�͸�MIDI Out������ʮ����λ�У���ЩλԪ���ǣ�
90 3C 40
��һ��λԪ�飨90����ʾNote OnѶϢ���ڶ���λԪ���Ǽ��ţ�����3C������C��������λԪ�����ð������ٶȣ����ٶȷ�Χ�Ǵ�1��127������ǡ��ʹ����һ�����ٶȲ����еļ��̣����������ƽ���ٶ�ֵ�����3λԪ���ѶϢ˳��MIDI���½���ϳ�����Midi In����ͨ����������C����������Ӧ�ϳ�����
�ͷż�ʱ�����̻Ὣ��һ��3λԪ��ѶϢ���͸�MIDI Out����
90 3C 00
����Note On������ͬ��������0��λԪ�顣���λԪ��ֵ0��ʾNote Off�����ζ��Ӧ�ùر��������ϳ���ͨ��ֹͣ��������Ӧ��
����ϳ����и������ֵ�����������ͬʱ���Ŷ������������������ô���Ϳ����ڼ�����������ҡ����̲�������Note OnѶϢ�����Һϳ������������е������������ͷź���ʱ�����̾ͽ�����Note OffѶϢ���͸��ϳ�����
һ����˵�������趨�еļ��̳�Ϊ��MIDI�������������������MIDIѶϢ�����ƺϳ�����MIDI������������������̡�MIDI�������������漸�֣��������񵥻ɹܻ�����˹�ܵ�MID���ֿ�������MIDI������������MIDI���ֿ�������MIDI�Ŀ�����������������Щ������������3λԪ���Note On��Note OffѶϢ��
ʤ�����Ƶļ��̻�ͳ������������Ҳ�����ǡ����������������ڼ������д���Note On��Note OffѶϢ˳��Ȼ���ٲ��ŵ�Ӳ�塣���ڵ����������Ѿ��ȼ���ǰ�ټ����ˣ���Ϊ�����Ѿ����������������װMIDI���ĵ���Ҳ��������Note On��Note OffѶϢ�����ƺϳ�����MIDI�à¼ï¿½ï¿½ï¿½å£¬ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½Ó©Ä»ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½Ô´ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½MIDI��������MIDIѶϢ����������ЩѶϢ��Ȼ�ὫMIDIѶϢ���͸��ϳ�����
�ϳ�����ʱҲ��Ϊ������ģ�飨sound module��������Դ����tone generator������MIDI��ָ���������������Щ�����ķ������ϳ�������ʹ���κ�һ���������ɼ�����
ʵ���ϣ�ֻ�зdz��򵥵�MIDI��������������ֿ���������ֻ��MIDI Out���²���ͨ�����̶����ڽ��ϳ���������������MIDI���²����ֱ���Ϊ��MIDI In������MIDI Out���͡�MIDI Thru����MIDI In������MIDIѶϢ���Ӷ����ż��̵��ڲ��ϳ�����MIDI Out����MIDIѶϢ�Ӽ��̷��͵��ⲿ�ϳ�����MIDI Thru����һ���������������MIDI In���������źţ����۴�MIDI In�����ʲô�����͸�MIDI Thru����MIDI Thru����������MIDI Out�����͵��κ���Ѷ����
͸����������MIDIӲ��ֻ�����ַ�������һ��Ӳ���ϵ�MIDI Out���ᵽ��һ����MIDI In�����߽�MIDI Thru��MIDI In���ᡣMIDI Thru����������һϵ�е�MIDI�ϳ�����
��ʽ����
��
�ϳ��������������������Ǹ�������С�����������������Ƿɵ�����ͨ���ϳ����ܹ����ɵĸ���������������ROM���������ط�������ͨ����Ϊ���������������������ߡ���ɫ������ ����ɫ��һ��������Ⱥϳ�����ʱ������ʱͨ������ɫ���Ҳ���ϳ���ǰ��IJ�������趨��ͬ����������
��MIDI�У��ϳ����ܹ����ɵĸ���������Ϊ����ʽ�����ı������ʽ��Ҫ��ϳ�������MIDI Program ChangeѶϢ
C0 pp
���У�pp�ķ�Χ��0��127��ͨ��MIDI���̵Ķ�����һϵ�����޵İ�ť����Щ��ť������Program ChangeѶϢ��͸��������Щ��ť�������ԴӼ��̿��ƺϳ�������������Щ��ť��ͨ����1��ʼ����������0��ʼ����˳�ʽ����1��Program ChangeλԪ���0��Ӧ��
MIDI���û��˵����ʽ�����������Ķ�Ӧ��ϵ�����磬������Yamaha DX7�ϳ����ϵ�ǰ������ʽ�ֱ��Ϊ��Warm Strings������ Mellow Horn���͡�Pick Guitar��������Yamaha TX81Z�����������ϣ�������Grand Piano��Upright Piano��Deep Grand����Roland MT-32����ģ���ϣ�������Acoustic Piano 1��Acoustic Piano 2��Acoustic Piano 3����ˣ������ϣ���ڴӼ���������ʽ�ı�ʱ�е��Ծ�����ô����˽�һ��������������ʹ�õĺϳ����ij�ʽ���ŵĶ�Ӧ��ϵ��
���춰���Program ChangeѶϢ��MIDI������˵��һ��ʵ�����â£ï¿½ï¿½Ð©ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½×°ï¿½ï¿½ï¿½Þ¹ØµÄ£ï¿½ï¿½ï¿½Îªï¿½ï¿½ï¿½Çµï¿½ï¿½ï¿½ï¿½ï¿½ï¿½Ú²ï¿½Í¬ï¿½ÄºÏ³ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½Ç²ï¿½Ò»ï¿½ï¿½ï¿½Ä¡ï¿½È»ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ê£¬ï¿½ï¿½General MIDI����GM����׼�Ѿ�����Щ��ʽ���ű�׼����WindowsÖ§Ô®General MIDI������ϳ�����General MIDI���һ�£���ô��ʽת����ʹ��ģ��General MIDI�ϳ�����
MIDIͨ��
��
����Ϊֹ�����Ѿ�����������MIDIѶϢ����һ����Note On��
90 kk vv
���У�kk�Ǽ��ţ�0��127����v v���ٶȣ�0��127����0�ٶȱ�ʾNote Off����ڶ�����Program Change��
C0 pp
���У�pp�ķ�Χ�Ǵ�0��127����Щ�ǵ��͵�MIDIѶϢ����һ��λԪ�������״̬��λԪ�顣����λԪ���״̬����ͨ�����0��1��2λԪ��ġ����ϡ����Ҽ���˵���ġ�ϵͳר�С�ѶϢ���⣩��������λԪ���зֱ��״̬λԪ������ף���λ����1���״̬λԪ�飬0�������λԪ�顣
Ȼ�����һ�û�����۹�������ѶϢ����ͨ��ʽ��Note OnѶϢ����ͨ��ʽ���£�
9n kk vv
��Program Change�ǣ�
Cn pp
������������£�n��ʾ״̬λԪ��ĵ���λԪ����仯��Χ��0��15�������MIDI��ͨ������ͨ��һ���1��ʼ��ţ���ˣ����nΪ0�������ͨ��1��
ʹ��16����ͬͨ������һ��MIDI���´���16�ֲ�ͬ������ѶϢ��ͨ������������MIDIѶϢ�������ִ���Program ChangeѶϢ��ʼ��Ϊ���õIJ�ͬͨ���趨���������ִ��������Ƕ���Note On��Note Off��������������������Program Change������κ�ʱ��ÿ��ͨ����ֻ��һ��������ϵ��
��������һ���򵥷������ٶ����Ѿ����۹��ļ��̿����ܹ�ͬʱ�������������ͬͨ����ͨ��1��ͨ��2����MIDIѶϢ��͸�����¼����ϵİ�ť������Program ChangeѶϢ���͸��ϳ�����
C0 01 C1 05
�����趨ͨ��1��춳�ʽ2�����趨ͨ��2��춳�ʽ6������ͨ�����źͳ�ʽ���Ŷ��ǻ��1�ģ���ѶϢ�еı����ǻ��0�ģ������ڰ��¼����ϵļ�ʱ���ͷ�������Note OnѶϢ��һ�����һ��ͨ����
90 kk vv 91 kk vv
�����������г��ͬʱ��������������������
��һ�ַ����ǡ��ֿ������̡��ͼ�������ͨ��1�ϲ���Note OnѶϢ���߼�������ͨ��2�ϲ���Note OnѶϢ�������������һ�������϶�����������������������
��������PC�ϵ�MIDI��������ʱ��ʹ��16��ͨ������Ϊ������ÿ��ͨ����������ͬ��������������ܹ���������16�ֲ�ͬ�����ĺϳ�������ô���Ϳ��Ա�д���16�����εĹ�������������ֻʹ��һ��MIDI���½�MIDI����ϳ�������������
MIDIѶϢ
��
����Note On��Program ChangeѶϢ���κ�MIDIִ���ж�������Ҫ��ѶϢ�������������е�MIDI������ִ�С���22-2��MIDI����ж����MIDIͨ��ѶϢ��������ǰ���ᵽ����״̬λԪ��ĸ�λԪ�����趨������״̬λԪ�����������λԪ��ĸ�λԪ�����0������ζ��״̬λԪ��ķ�Χ��0x80��0xFF��������λԪ��ķ�Χ��0��0x7F��
��22-2 MIDIͨ��ѶϢ��n =ͨ�����ţ���0��15�� |
MIDIѶϢ | ����λԪ�� | ֵ |
---|---|---|
Note Off | 8n kk vv |
kk = ���ţ�0-127��
vv = �ٶȣ�0-127�� |
Note On | 9n kk vv |
kk = ���ţ�0-127��
vv = �ٶȣ�1-127, 0 = note off�� |
Polyphonic After Touch | An kk tt |
kk = ���ţ�0-127��
tt = ����֮�� ��0-127�� |
Control Change | Bn cc xx |
cc = ��������0-121��
xx = ֵ��0-127�� |
Channel Mode Local Control | Bn 7A xx | xx = 0���أ���127������ |
All Notes Off | Bn 7B 00 | |
Omni Mode Off | Bn 7C 00 | |
Omni Mode On | Bn 7D 00 | |
Mono Mode On | Bn 7E cc | cc = Ƶ���� |
Poly Mode On | Bn 7F 00 | |
Program Change | Cn pp | pp = ��ʽ��0-127�� |
Channel After Touch | Dn tt | tt = ����֮�ᣨ0-127�� |
Pitch Wheel Change | En ll hh |
ll = ��7λԪ��0-127��
hh = ��7λԪ��0-127�� |
��Ȼû���ϸ��Ҫ�󣬼���ͨ���������������ֵĴ�ͳ�������Ӧ�����磬��춴��������ÿ������������Dz�ͬ�Ĵ�����������������������ļ��̶�Ӧʱ����60��ʮ��λ��������C��MIDI��������ͨ��88�����ٷ�Χ�Ļ�����������չ��21��������������չ��19���������ٶȴ����ǰ���ij�����ٶȣ��ڸ�����������������������г���硣������������������ַ�ʽ��������ʽ����Ӧ�����ٶȡ�
ǰ��չʾ������ʹ�ô���0�ٶ�λԪ���Note OnѶϢ����ʾNote Off�����춼��̣���������������������һ��������Note Off���������ʵ���ͷż����ٶȣ��������dz��ټ���
�����������Ӵ��᡹ѶϢ���Ӵ�����һЩ���̵����磬����ij�������ᣬ���������¼�������ijЩ��ʽ�ϸı�������һ��ѶϢ��״̬λԪ��0xDn���ǽ��Ӵ���Ӧ���ͨ����Ŀǰ�����������������������ġ�״̬λԪ��0xAn��ʾ����Ӧ��ÿ���������ĽӴ��ᡣ
ͨ���������϶���һЩ��춽�һ�����������Ŀ̶��̻򿪹ء���Щװ�ó�Ϊ���������������б仯����״̬λԪ��0xBn��ʾ��ͨ����0��121�ĺ���ȷ�Ͽ�������0xBn״̬λԪ��Ҳ���Channel ModeѶϢ����ЩѶϢ��ʾ�˺ϳ��������ͨ���л�Ӧͬʱ������������
һ���dz���Ҫ�Ŀ�����������ת���������֣�����һ��������MIDIѶϢ����״̬λԪ����0xEn��
��22-2����ȱ�ٵ���״̬λԪ���Դ�F0��FF��ʼ��ѶϢ����ЩѶϢ��ΪϵͳѶϢ����Ϊ�������������MIDIϵͳ�������Dz���ͨ����ϵͳѶϢͨ�����ͬ����Ŀ�ġ������������������趨Ӳ���Լ������Ѷ��
����MIDI��������������״̬λԪ��0xFE����λԪ���ΪActive SensingѶϢ����򵥵ر�ʾ��MIDI�������������ϵͳ��
һ����Ҫ��ϵͳѶϢ����״̬λԪ��0xF0��ʼ�ġ�ϵͳר�á�ѶϢ����ѶϢ��춽����Ͽ鰴������ϳ����������ĸ�ʽ���ݸ��ϳ��������磬�����ַ������Խ��µ���������ӵ��Դ��ݸ��ϳ�������ϵͳר��ѶϢֻ�ǿ��԰������2������λԪ���ΨһѶϢ��ʵ���ϣ�����λԪ�����DZ仯�ģ���ÿ������λԪ��ĸ�λ���趨Ϊ0��״̬λԪ��0xF7��ʾϵͳר��ѶϢ�Ľ�β��
ϵͳר��ѶϢҲ��춴Ӻϳ���ת�����ϣ����磬�������壩����Щ���϶���ͨ��MIDI Out�����Ժϳ��������Ҫ��װ���޹صķ�ʽ��MIDI��д��ʽ����Ӧ�þ����ܱ���ʹ��ϵͳר��ѶϢ���������Ƕ�춶����µĺϳ��������Ƿdz����õġ�
MIDI��������������.MDI���Ǵ��ж�ʱ��Ѷ��MIDI��Ѷ����������MCI����MIDI�������������ҽ��ڱ��µ��������۵ͽ�midiOut��ʽ��
MIDI�������
��
�ͽ�MIDI��API��������ΪmidiIn��midiOut�ĺ�ʽ�����Ƿֱ���춶�ȡ�����ⲿ��������MIDI���к����ڲ����ⲿ�ĺϳ����ϲ������֡�����������Ϊ���ͽס�����ʹ����Щ��ʽʱ������Ҫ�˽�MIDI���ϵ�Ӳ����档
Ҫ�ڲ������ֵ�׼���ڼ��һ��MIDI����豸�����Ժ���midiOutOpen��ʽ��
error = midiOutOpen (&hMidiOut, wDeviceID, dwCallBack, dwCallBackData, dwFlags) ;
������гɹ�����ʽ����0�����򴫻ش�����롣��������趨��ȷ���򳣼���һ�ִ������MIDI�豸�ѱ�������ʽʹ�á�
�ú�ʽ�ĵ�һ��������ָ��HMIDIOUT��̬������ָ�꣬�������������MIDI�����ʽ��MIDI������š��ڶ����������豸ID��Ҫʹ����ʵ��MIDI�豸�����������Χ�����Ǵ�0��С���midiOutGetNumDevs���ص���ֵ����������ʹ��MIDIMAPPER������MMSYSTEM.H�ж���Ϊ-1�����������£���ʽ�������������趨ΪNULL��0��
һ����һ��MIDI����豸�����������ţ����Ϳ�������豸����MIDIѶϢ����ʱ���Ժ��У�
error = midiOutShortMsg (hMidiOut, dwMessage) ;
��һ�������Ǵ�midiOutOpen��ʽ��õĴ��š��ڶ��������ǰ�װ��32λԪDWORD�е�1λԪ�顢2λԪ�����3λԪ���ѶϢ������ǰ�����۹���MIDIѶϢ��״̬λԪ�鿪ʼ��������0��1��2λԪ������ϡ���dwMessage�У�״̬λԪ�������Ҫ�ģ���һ������λԪ���֮���ڶ�������λԪ���ٴ�֮������Ҫ��λԪ����0��
���磬Ҫ��MIDIͨ��5����0x7F���ٶ���������C��������0x3C��������Ҫ3λԪ���Note OnѶϢ��
0x95 0x3C 0x7F
midiOutShortMsg�IJ���dwMessage���0x007F3C95��
����������MIDIѶϢ��Program Change����Ϊijһ�ض�ͨ�����ı�������������Note On��Note Off����һ��MIDI����豸�ᣬӦ�ô�һ��Program ChangeѶϢ��ʼ��Ȼ�ᷢ����ͬ������Note On��Note OffѶϢ��
����һֱ�����������������ʱ������������MIDI����豸��ȷ���ر����е�������
midiOutReset (hMidiOut) ;
Ȼ��ر��豸��
midiOutClose (hMidiOut) ;
ʹ�õͽ׵�MIDI���APIʱ��midiOutOpen��midiOutShortMsg��midiOutReset��midiOutClose������Ҫ���ĸ�������ʽ��
��������������һ�����֡�BACHTOCC�����ʽ22-8��ʾ��������J. S. Bach�����ķ��������DС����Toccata and Fugue�����п������ֵĵ�һС�ڡ�
��ʽ22-8 BACHTOCC BACHTOCC.C /*----------------------------------------------------------------------------- BACHTOCC.C -- Bach Toccata in D Minor (First Bar) (c) Charles Petzold, 1998 -----------------------------------------------------------------------------*/ #include <windows.h> #define ID_TIMER 1 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; TCHAR szAppName[] = TEXT ("BachTocc") ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow ( szAppName, TEXT ("Bach Toccata in D Minor (First Bar)"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; if (!hwnd) return 0 ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } DWORD MidiOutMessage ( HMIDIOUT hMidi, int iStatus, int iChannel, int iData1, int iData2) { DWORD dwMessage = iStatus | iChannel | (iData1 << 8) | (iData2 << 16) ; return midiOutShortMsg (hMidi, dwMessage) ; } LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static struct { int iDur ; int iNote [2] ; } noteseq [] = { 110, 69, 81, 110, 67, 79, 990, 69, 81, 220, -1, -1, 110, 67, 79, 110, 65, 77, 110, 64, 76, 110, 62, 74, 220, 61, 73, 440, 62, 74, 1980, -1, -1, 110, 57, 69, 110, 55, 67, 990, 57, 69, 220, -1, -1, 220, 52, 64, 220, 53, 65, 220, 49, 61, 440, 50, 62, 1980, -1, -1 } ; static HMIDIOUT hMidiOut ; static int iIndex ; int i ; switch (message) { case WM_CREATE: // Open MIDIMAPPER device if (midiOutOpen (&hMidiOut, MIDIMAPPER, 0, 0, 0)) { MessageBeep (MB_ICONEXCLAMATION) ; MessageBox ( hwnd, TEXT ("Cannot open MIDI output device!"), szAppName, MB_ICONEXCLAMATION | MB_OK) ; return -1 ; } // Send Program Change messages for "Church Organ" MidiOutMessage (hMidiOut, 0xC0, 0, 19, 0) ; MidiOutMessage (hMidiOut, 0xC0, 12, 19, 0) ; SetTimer (hwnd, ID_TIMER, 1000, NULL) ; return 0 ; case WM_TIMER: // Loop for 2-note polyphony for (i = 0 ; i < 2 ; i++) { // Note Off messages for previous note if (iIndex != 0 && noteseq[iIndex - 1].iNote[i] != -1) { MidiOutMessage (hMidiOut, 0x80, 0, noteseq[iIndex - 1].iNote[i], 0) ; MidiOutMessage (hMidiOut, 0x80, 12, noteseq[iIndex - 1].iNote[i], 0) ; } // Note On messages for new note if (iIndex != sizeof (noteseq) / sizeof (noteseq[0]) && noteseq[iIndex].iNote[i] != -1) { MidiOutMessage (hMidiOut, 0x90, 0, noteseq[iIndex].iNote[i], 127) ; MidiOutMessage (hMidiOut, 0x90, 12,noteseq[iIndex].iNote[i], 127) ; } } if (iIndex != sizeof (noteseq) / sizeof (noteseq[0])) { SetTimer (hwnd, ID_TIMER, noteseq[iIndex++].iDur - 1, NULL) ; } else { KillTimer (hwnd, ID_TIMER) ; DestroyWindow (hwnd) ; } return 0 ; case WM_DESTROY: midiOutReset (hMidiOut) ; midiOutClose (hMidiOut) ; PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }
ͼ22-1��ʾ��Bach��DС��Toccata�ĵ�һС�ڡ�
��
ͼ22-1 Bach��DС��Toccata and Fugue�ĵ�һС�� |
������Ҫ���ľ��ǰ�����ת����һϵ�е���ֵ���������źͶ�ʱ��Ѷ�����ж�ʱ��Ѷ��ʾ����Note On����Ӧ춷��ټ����£���Note Off���ͷż���ѶϢ��ʱ�䡣��춷��ټ��̶��ٶȲ����У�������������ͬ���ٶ����������е�����������һ�����Ǻ��Զ��ࣨ����������������֮������һ���̵ܶ�ͣ�٣��Դﵽ��Ӳ��Ч���������ࣨ������������֮���и�Բ����ص���֮����������Ǽٶ�һ���������������������һ��������ʼ��
������ö����ף���ô���ͻ�ע�⵽�п�����������ƽ�еİ˶����׿�ʼ�����BACHTOCC������һ�����Ͻṹnoteseq������һϵ�е���������ʱ���Լ��������š����ҵ��ǣ����ֳ�������ڶ�С�ھ���Ҫ������ķ������������Ѷ���ҽ��ķ������ij���ʱ�䶨��Ϊ1760���룬Ҳ����˵���˷�������������������ֹ������һ����β���ij���ʱ����880���룬ʮ����������������β����440���룬��ʮ����������������β����220���룬��ʮ�ķ��������ĸ���β����110���롣
���һС����������������һ���ڵ�һ������������һ����С�ڵ��м䡣�����������ô�һ�������ߵ����߱�ʾ���ڽṹ���ӵ������У��������ű�ʾ������ʵ��Ӧ����Ϊ���������������������������һ��ȫ����������Ȼ�ỹ�DZ����������ǰ�������������Ҫ�죬����������Ҫ����ʣ���ʱ�䡣���磬��һ�������Ǵ�������A����Ӧ����ΪA��G��A���ҽ�������ǰ������������Ϊ��ʮ�ķ�����������ÿ������������110���롣
�ڵ�һС�ڻ����ĸ��ӳ����š������ϱ�ʾΪ�м����İ�Բ�Ρ��ӳ����ű�ʾ������������ʱ��������ʱ��ȱ�ǵ�ʱ��Ҫ����ͨ���������߾��������ʱ�䡣�Ҷ���ӳ������ӳ���50%��ʱ�䡣
���Կ�������ʹ��ת��һС�ο�����ֱ�ӵ�����������DС����Toccata���Ŀ�ͷ��Ҳ�����Ǽ����׵��£�
noteseq�ṹ���а�������һС����ƽ�е���������ֹ����������λ����������ʱ������������ƽ�а˶����׵�����MIDI���š����磬��һ��������A������ʱ����110���롣��Ϊ����C��MIDI������60����������C�����A�ļ�����69����A��һ���˶����׵ļ�����81����ˣ�noteseq���е�ǰ��������110��69��81����������ֵ-1��ʾ��ֹ����
WM_CREATEѶϢ�����ڼ䣬BACHTOCC�趨һ��Windows��ʱ����춶�ʱ1000���ë£ï¿½ï¿½Ê¾ï¿½ï¿½ï¿½ï¿½ï¿½Óµï¿½1�뿪ʼ���à£È»ï¿½ï¿½ï¿½ï¿½MIDIMAPPER�豸ID����midiOutOpen��
BACHTOCCֻ��Ҫһ�����������٣�������������ֻ��Ҫһ��ͨ����Ϊ�˼�MIDIѶϢ�ķ��ͣ�BACHTOCC�л�������һ��С��ʽMidiOutMessage���˺�ʽ����MIDI������š�״̬λԪ�顢ͨ�����ź�����λԪ�����ϡ��书���ǰ���Щ���ִ����һ��32λԪ��ѶϢ������midiOutShortMsg��
��WM_CREATEѶϢ������������ڣ�BACHTOCC����һ��Program ChangeѶϢ��ѡ�񡸽��÷��١�����������General MIDI���������У����÷���������Program ChangeѶϢ������λλԪ��19��ʾ��ʵ�����������������WM_TIMERѶϢ�����ڼ䡣�û�Ȧ���������������Ķ��������ǰһ�������������࣬BACHTOCC��Ϊ����������Note OffѶϢ��Ȼ�ᣬ�����һ������������ֹ��������ͨ��0��12����Note OnѶϢ�����ᣬ����Windows��ʱ����ʹ����noteseq�ṹ�������ij���ʱ��һ�¡�
�����������ᣬBACHTOCCɾ���Ӵ�����WM_DESTROYѶϢ�����ڼ䣬��ʽ����midiOutReset��midiOutClose��Ȼ����ֹ��ʽ��
����BACHTOCC�����ش����ͼ�����������ʹ������ȫ������������٣�����һ���������Windows��ʱ�������ַ�ʽ���������ֲ������á��������Windows��ʱ��������PC��ϵͳʱ�ӣ�������Ȳ����������ֵ�Ҫ�󡣶��ң�Windows��ʱ������ͬ���ġ����������������ʽ��æ�ִ�У�����WM_TIMERѶϢ�ͻ�����΢���ӳ١������ʽ��������������ЩѶϢ���ͻ����WM_TIMERѶϢ����ʱ������������һ���㡣
��ˣ���BACHTOCC��ʾ����κ��еͽ�MIDI�����ʽʱ��ʹ��Windows��ʱ����Ȼ���ʺϾ�ȷ�����ִ��������ԣ�Windows���ṩ��һϵ�и��ӵļ�ʱ����ʽ��ʹ�õͽ׵�MIDI�����ʽʱ����������Щ��ʽ����Щ��ʽ������Ϊtime���������������ǽ���ʱ���Ľ������趨����С1���롣�ҽ��ڱ��½�β��DRUM��ʽ����չʾʹ����Щ��ʽ�ķ�����
ͨ����������MIDI�ϳ���
��
��Ϊ�����PCʹ���߿��ܶ�û�������ڻ����ϵ�MIDI���̣����Կ�����ÿ���˶��еļ��̣�����ȫ������ĸ�������ϼ��������档��ʽ22-9��ʾ�ij�ʽKBMIDI��������PC����������������ֺϳ�������������������Ч���ϵģ����ǹҽ���MIDI Out�����ⲿ�ϳ�����KBMIDI������ȫ����MIDI����豸�����ڲ����ⲿ�ĺϳ�������MIDIͨ����������������������ʱ��Ȥζ�����⣬�һ����ִ˳�ʽ��춿���Windows���ʵ��MIDI֧Ԯ�����á�
��ʽ22-9 KBMIDI KBMIDI.C /*-------------------------------------------------------------------------- KBMIDI.C -- Keyboard MIDI Player (c) Charles Petzold, 1998 ---------------------------------------------------------------------------*/ #include <windows.h> // Defines for Menu IDs // -------------------- #define IDM_OPEN 0x100 #define IDM_CLOSE 0x101 #define IDM_DEVICE 0x200 #define IDM_CHANNEL 0x300 #define IDM_VOICE 0x400 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); TCHAR szAppName [] = TEXT ("KBMidi") ; HMIDIOUT hMidiOut ; int iDevice = MIDIMAPPER, iChannel = 0, iVoice = 0, iVelocity = 64 ; int cxCaps, cyChar, xOffset, yOffset ; // Structures and data for showing families and instruments on menu // -------------------------------------------------------------------- typedef struct { TCHAR * szInst ; int iVoice ; } INSTRUMENT ; typedef struct { TCHAR * szFam ; INSTRUMENT inst [8] ; } FAMILY ; FAMILY fam [16] = { TEXT ("Piano"), TEXT ("Acoustic Grand Piano"), 0, TEXT ("Bright Acoustic Piano"),1, TEXT ("Electric Grand Piano"), 2, TEXT ("Honky-tonk Piano"), 3, TEXT ("Rhodes Piano"), 4, TEXT ("Chorused Piano"), 5, TEXT ("Harpsichord"), 6, TEXT ("Clavinet"), 7, TEXT ("Chromatic Percussion"), TEXT ("Celesta"), 8, TEXT ("Glockenspiel"), 9, TEXT ("Music Box"), 10, TEXT ("Vibraphone"), 11, TEXT ("Marimba"), 12, TEXT ("Xylophone"), 13, TEXT ("Tubular Bells"), 14, TEXT ("Dulcimer"), 15, TEXT ("Organ"), TEXT ("Hammond Organ"), 16, TEXT ("Percussive Organ"), 17, TEXT ("Rock Organ"), 18, TEXT ("Church Organ"), 19, TEXT ("Reed Organ"), 20, TEXT ("Accordian"), 21, TEXT ("Harmonica"), 22, TEXT ("Tango Accordian"), 23, TEXT ("Guitar"), TEXT ("Acoustic Guitar (nylon)"), 24, TEXT ("Acoustic Guitar (steel)"), 25, TEXT ("Electric Guitar (jazz)"), 26, TEXT ("Electric Guitar (clean)"), 27, TEXT ("Electric Guitar (muted)"), 28, TEXT ("Overdriven Guitar"), 29, TEXT ("Distortion Guitar"), 30, TEXT ("Guitar Harmonics"), 31, TEXT ("Bass"), TEXT ("Acoustic Bass"), 32, TEXT ("Electric Bass (finger)"), 33, TEXT ("Electric Bass (pick)"), 34, TEXT ("Fretless Bass"), 35, TEXT ("Slap Bass 1"), 36, TEXT ("Slap Bass 2"), 37, TEXT ("Synth Bass 1"), 38, TEXT ("Synth Bass 2"), 39, TEXT ("Strings"), TEXT ("Violin"), 40, TEXT ("Viola"), 41, TEXT ("Cello"), 42, TEXT ("Contrabass"), 43, TEXT ("Tremolo Strings"), 44, TEXT ("Pizzicato Strings"), 45, TEXT ("Orchestral Harp"), 46, TEXT ("Timpani"), 47, TEXT ("Ensemble"), TEXT ("String Ensemble 1"), 48, TEXT ("String Ensemble 2"), 49, TEXT ("Synth Strings 1"), 50, TEXT ("Synth Strings 2"), 51, TEXT ("Choir Aahs"), 52, TEXT ("Voice Oohs"), 53, TEXT ("Synth Voice"), 54, TEXT ("Orchestra Hit"), 55, TEXT ("Brass"), TEXT ("Trumpet"), 56, TEXT ("Trombone"), 57, TEXT ("Tuba"), 58, TEXT ("Muted Trumpet"), 59, TEXT ("French Horn"), 60, TEXT ("Brass Section"), 61, TEXT ("Synth Brass 1"), 62, TEXT ("Synth Brass 2"), 63, TEXT ("Reed"), TEXT ("Soprano Sax"), 64, TEXT ("Alto Sax"), 65, TEXT ("Tenor Sax"), 66, TEXT ("Baritone Sax"), 67, TEXT ("Oboe"), 68, TEXT ("English Horn"), 69, TEXT ("Bassoon"), 70, TEXT ("Clarinet"), 71, TEXT ("Pipe"), TEXT ("Piccolo"), 72, TEXT ("Flute "), 73, TEXT ("Recorder"), 74, TEXT ("Pan Flute"), 75, TEXT ("Bottle Blow"), 76, TEXT ("Shakuhachi"), 77, TEXT ("Whistle"), 78, TEXT ("Ocarina"), 79, TEXT ("Synth Lead"), TEXT ("Lead 1 (square)"), 80, TEXT ("Lead 2 (sawtooth)"), 81, TEXT ("Lead 3 (caliope lead)"), 82, TEXT ("Lead 4 (chiff lead)"), 83, TEXT ("Lead 5 (charang)"), 84, TEXT ("Lead 6 (voice)"), 85, TEXT ("Lead 7 (fifths)"), 86, TEXT ("Lead 8 (brass + lead)"), 87, TEXT ("Synth Pad"), TEXT ("Pad 1 (new age)"), 88, TEXT ("Pad 2 (warm)"), 89, TEXT ("Pad 3 (polysynth)"), 90, TEXT ("Pad 4 (choir)"), 91, TEXT ("Pad 5 (bowed)"), 92, TEXT ("Pad 6 (metallic)"), 93, TEXT ("Pad 7 (halo)"), 94, TEXT ("Pad 8 (sweep)"), 95, TEXT ("Synth Effects"), TEXT ("FX 1 (rain)"), 96, TEXT ("FX 2 (soundtrack)"), 97, TEXT ("FX 3 (crystal)"), 98, TEXT ("FX 4 (atmosphere)"), 99, TEXT ("FX 5 (brightness)"), 100, TEXT ("FX 6 (goblins)"), 101, TEXT ("FX 7 (echoes)"), 102, TEXT ("FX 8 (sci-fi)"), 103, TEXT ("Ethnic"), TEXT ("Sitar"), 104, TEXT ("Banjo"), 105, TEXT ("Shamisen"), 106, TEXT ("Koto"), 107, TEXT ("Kalimba"), 108, TEXT ("Bagpipe"), 109, TEXT ("Fiddle"), 110, TEXT ("Shanai"), 111, TEXT ("Percussive"), TEXT ("Tinkle Bell"), 112, TEXT ("Agogo"), 113, TEXT ("Steel Drums"), 114, TEXT ("Woodblock"), 115, TEXT ("Taiko Drum"), 116, TEXT ("Melodic Tom"), 117, TEXT ("Synth Drum"), 118, TEXT ("Reverse Cymbal"), 119, TEXT ("Sound Effects"), TEXT ("Guitar Fret Noise"), 120, TEXT ("Breath Noise"), 121, TEXT ("Seashore"), 122, TEXT ("Bird Tweet"), 123, TEXT ("Telephone Ring"), 124, TEXT ("Helicopter"), 125, TEXT ("Applause"), 126, TEXT ("Gunshot"), 127 } ; // Data for translating scan codes to octaves and notes // ---------------------------------------------------- #define NUMSCANS (sizeof key / sizeof key[0]) struct { int iOctave ; int iNote ; int yPos ; int xPos ; TCHAR * szKey ; } key [] = { // Scan Char Oct Note // ---- ---- --- ---- -1, -1, 1, -1, NULL, // 0 None -1, -1, -1, -1, NULL, // 1 Esc -1, -1, 0, 0, TEXT (""), // 2 1 5, 1, 0, 2, TEXT ("C#"), // 3 2 5 C# 5, 3, 0, 4, TEXT ("D#"), // 4 3 5 D# -1, -1, 0, 6, TEXT (""), // 5 4 5, 6, 0, 8, TEXT ("F#"), // 6 5 5 F# 5, 8, 0, 10, TEXT ("G#"), // 7 6 5 G# 5, 10, 0, 12, TEXT ("A#"), // 8 7 5 A# -1, -1, 0, 14, TEXT (""), // 9 8 6, 1, 0, 16, TEXT ("C#"), // 10 9 6 C# 6, 3, 0, 18, TEXT ("D#"), // 11 0 6 D# -1, -1, 0, 20, TEXT (""), // 12 - 6, 6, 0, 22, TEXT ("F#"), // 13 = 6 F# -1, -1, -1, -1, NULL, // 14 Back -1, -1, -1, -1, NULL, // 15 Tab 5, 0, 1, 1, TEXT ("C"), // 16 q 5 C 5, 2, 1, 3, TEXT ("D"), // 17 w 5 D 5, 4, 1, 5, TEXT ("E"), // 18 e 5 E 5, 5, 1, 7, TEXT ("F"), // 19 r 5 F 5, 7, 1, 9, TEXT ("G"), // 20 t 5 G 5, 9, 1, 11, TEXT ("A"), // 21 y 5 A 5, 11, 1, 13, TEXT ("B"), // 22 u 5 B 6, 0, 1, 15, TEXT ("C"), // 23 i 6 C 6, 2, 1, 17, TEXT ("D"), // 24 o 6 D 6, 4, 1, 19, TEXT ("E"), // 25 p 6 E 6, 5, 1, 21, TEXT ("F"), // 26 [ 6 F 6, 7, 1, 23, TEXT ("G"), // 27 ] 6 G -1, -1, -1, -1, NULL, // 28 Ent -1, -1, -1, -1, NULL, // 29 Ctrl 3, 8, 2, 2, TEXT ("G#"), // 30 a 3 G# 3, 10, 2, 4, TEXT ("A#"), // 31 s 3 A# -1, -1, 2, 6, TEXT (""), // 32 d 4, 1, 2, 8, TEXT ("C#"), // 33 f 4 C# 4, 3, 2, 10, TEXT ("D#"), // 34 g 4 D# -1, -1, 2, 12, TEXT (""), // 35 h 4, 6, 2, 14, TEXT ("F#"), // 36 j 4 F# 4, 8, 2, 16, TEXT ("G#"), // 37 k 4 G# 4, 10, 2, 18, TEXT ("A#"), // 38 l 4 A# -1, -1, 2, 20, TEXT (""), // 39 ; 5, 1, 2, 22, TEXT ("C#"), // 40 ' 5 C# -1, -1, -1, -1, NULL, // 41 ` -1, -1, -1, -1, NULL, // 42 Shift -1, -1, -1, -1, NULL, // 43 \ (not line continuation) 3, 9, 3, 3, TEXT ("A"), // 44 z 3 A 3, 11, 3, 5, TEXT ("B"), // 45 x 3 B 4, 0, 3, 7, TEXT ("C"), // 46 c 4 C 4, 2, 3, 9, TEXT ("D"), // 47 v 4 D 4, 4, 3, 11, TEXT ("E"), // 48 b 4 E 4, 5, 3, 13, TEXT ("F"), // 49 n 4 F 4, 7, 3, 15, TEXT ("G"), // 50 m 4 G 4, 9, 3, 17, TEXT ("A"), // 51 , 4 A 4, 11, 3, 19, TEXT ("B"), // 52 . 4 B 5, 0, 3, 21, TEXT ("C") // 53 / 5 C } ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { MSG msg; HWND hwnd ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow ( szAppName, TEXT ("Keyboard MIDI Player"), WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; if (!hwnd) return 0 ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd); while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } // Create the program's menu (called from WndProc, WM_CREATE) // -------------------------------------------------------------------- HMENU CreateTheMenu (int iNumDevs) { TCHAR szBuffer [32] ; HMENU hMenu, hMenuPopup, hMenuSubPopup ; int i, iFam, iIns ; MIDIOUTCAPS moc ; hMenu = CreateMenu () ; // Create "On/Off" popup menu hMenuPopup = CreateMenu () ; AppendMenu (hMenuPopup, MF_STRING, IDM_OPEN, TEXT ("&Open")) ; AppendMenu (hMenuPopup, MF_STRING | MF_CHECKED, IDM_CLOSE, TEXT ("&Closed")) ; AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup, TEXT ("&Status")) ; // Create "Device" popup menu hMenuPopup = CreateMenu () ; // Put MIDI Mapper on menu if it's installed if (!midiOutGetDevCaps (MIDIMAPPER, &moc, sizeof (moc))) AppendMenu (hMenuPopup, MF_STRING, IDM_DEVICE + (int) MIDIMAPPER, moc.szPname) ; else iDevice = 0 ; // Add the rest of the MIDI devices for (i = 0 ; i < iNumDevs ; i++) { midiOutGetDevCaps (i, &moc, sizeof (moc)) ; AppendMenu (hMenuPopup, MF_STRING, IDM_DEVICE + i, moc.szPname) ; } CheckMenuItem (hMenuPopup, 0, MF_BYPOSITION | MF_CHECKED) ; AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup, TEXT ("&Device")) ; // Create "Channel" popup menu hMenuPopup = CreateMenu () ; for (i = 0 ; i < 16 ; i++) { wsprintf (szBuffer, TEXT ("%d"), i + 1) ; AppendMenu (hMenuPopup, MF_STRING | (i ? MF_UNCHECKED : MF_CHECKED), IDM_CHANNEL + i, szBuffer) ; } AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup, TEXT ("&Channel")) ; // Create "Voice" popup menu hMenuPopup = CreateMenu () ; for (iFam = 0 ; iFam < 16 ; iFam++) { hMenuSubPopup = CreateMenu () ; for (iIns = 0 ; iIns < 8 ; iIns++) { wsprintf (szBuffer, TEXT ("&%d.\t%s"), iIns + 1, fam[iFam].inst[iIns].szInst) ; AppendMenu (hMenuSubPopup, MF_STRING | (fam[iFam].inst[iIns].iVoice ? MF_UNCHECKED : MF_CHECKED), fam[iFam].inst[iIns].iVoice + IDM_VOICE, szBuffer) ; } wsprintf (szBuffer, TEXT ("&%c.\t%s"), 'A' + iFam, fam[iFam].szFam) ; AppendMenu (hMenuPopup, MF_STRING | MF_POPUP, (UINT) hMenuSubPopup, szBuffer) ; } AppendMenu (hMenu, MF_STRING | MF_POPUP, (UINT) hMenuPopup, TEXT ("&Voice")) ; return hMenu ; } // Routines for simplifying MIDI output // ------------------------------------ DWORD MidiOutMessage ( HMIDIOUT hMidi, int iStatus, int iChannel, int iData1, int iData2) { DWORD dwMessage ; dwMessage = iStatus | iChannel | (iData1 << 8) | (iData2 << 16) ; return midiOutShortMsg (hMidi, dwMessage) ; } DWORD MidiNoteOff ( HMIDIOUT hMidi, int iChannel, int iOct, int iNote, int iVel) { return MidiOutMessage (hMidi, 0x080, iChannel, 12 * iOct + iNote, iVel) ; } DWORD MidiNoteOn ( HMIDIOUT hMidi, int iChannel, int iOct, int iNote, int iVel) { return MidiOutMessage ( hMidi, 0x090, iChannel, 12 * iOct + iNote, iVel) ; } DWORD MidiSetPatch (HMIDIOUT hMidi, int iChannel, int iVoice) { return MidiOutMessage (hMidi, 0x0C0, iChannel, iVoice, 0) ; } DWORD MidiPitchBend (HMIDIOUT hMidi, int iChannel, int iBend) { return MidiOutMessage (hMidi, 0x0E0, iChannel, iBend & 0x7F, iBend >> 7) ; } // Draw a single key on window // ---------------------------------- VOID DrawKey (HDC hdc, int iScanCode, BOOL fInvert) { RECT rc ; rc.left = 3 * cxCaps * key[iScanCode].xPos / 2 + xOffset ; rc.top = 3 * cyChar * key[iScanCode].yPos / 2 + yOffset ; rc.right = rc.left + 3 * cxCaps ; rc.bottom = rc.top + 3 * cyChar / 2 ; SetTextColor (hdc, fInvert ? 0x00FFFFFFul : 0x00000000ul) ; SetBkColor (hdc, fInvert ? 0x00000000ul : 0x00FFFFFFul) ; FillRect (hdc, &rc, GetStockObject (fInvert ? BLACK_BRUSH : WHITE_BRUSH)) ; DrawText (hdc, key[iScanCode].szKey, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ; FrameRect (hdc, &rc, GetStockObject (BLACK_BRUSH)) ; } // Process a Key Up or Key Down message // ------------------------------------ VOID ProcessKey (HDC hdc, UINT message, LPARAM lParam) { int iScanCode, iOctave, iNote ; iScanCode = 0x0FF & HIWORD (lParam) ; if (iScanCode >= NUMSCANS) // No scan codes over 53 return ; if ((iOctave = key[iScanCode].iOctave) == -1) // Non-music key return ; if (GetKeyState (VK_SHIFT) < 0) iOctave += 0x20000000 & lParam ? 2 : 1 ; if (GetKeyState (VK_CONTROL) < 0) iOctave -= 0x20000000 & lParam ? 2 : 1 ; iNote = key[iScanCode].iNote ; if (message == WM_KEYUP) // For key up { MidiNoteOff (hMidiOut, iChannel, iOctave, iNote, 0) ; // Note off DrawKey (hdc, iScanCode, FALSE) ; return ; } if (0x40000000 & lParam) // ignore typematics return ; MidiNoteOn (hMidiOut, iChannel, iOctave, iNote, iVelocity) ; // Note on DrawKey (hdc, iScanCode, TRUE) ; // Draw the inverted key } // Window Procedure // --------------------- LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bOpened = FALSE ; HDC hdc ; HMENU hMenu ; int i, iNumDevs, iPitchBend, cxClient, cyClient ; MIDIOUTCAPS moc ; PAINTSTRUCT ps ; SIZE size ; TCHAR szBuffer [16] ; switch (message) { case WM_CREATE: // Get size of capital letters in system font hdc = GetDC (hwnd) ; GetTextExtentPoint (hdc, TEXT ("M"), 1, &size) ; cxCaps = size.cx ; cyChar = size.cy ; ReleaseDC (hwnd, hdc) ; // Initialize "Volume" scroll bar SetScrollRange (hwnd, SB_HORZ, 1, 127, FALSE) ; SetScrollPos (hwnd, SB_HORZ, iVelocity, TRUE) ; // Initialize "Pitch Bend" scroll bar SetScrollRange (hwnd, SB_VERT, 0, 16383, FALSE) ; SetScrollPos (hwnd, SB_VERT, 8192, TRUE) ; // Get number of MIDI output devices and set up menu if (0 == (iNumDevs = midiOutGetNumDevs ())) { MessageBeep (MB_ICONSTOP) ; MessageBox ( hwnd, TEXT ("No MIDI output devices!"), szAppName, MB_OK | MB_ICONSTOP) ; return -1 ; } SetMenu (hwnd, CreateTheMenu (iNumDevs)) ; return 0 ; case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; xOffset = (cxClient - 25 * 3 * cxCaps / 2) / 2 ; yOffset = (cyClient - 11 * cyChar) / 2 + 5 * cyChar ; return 0 ; case WM_COMMAND: hMenu = GetMenu (hwnd) ; // "Open" menu command if (LOWORD (wParam) == IDM_OPEN && !bOpened) { if (midiOutOpen (&hMidiOut, iDevice, 0, 0, 0)) { MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, TEXT ("Cannot open MIDI device"), szAppName, MB_OK | MB_ICONEXCLAMATION) ; } else { CheckMenuItem (hMenu, IDM_OPEN, MF_CHECKED) ; CheckMenuItem (hMenu, IDM_CLOSE, MF_UNCHECKED) ; MidiSetPatch (hMidiOut, iChannel, iVoice) ; bOpened = TRUE ; } } // "Close" menu command else if (LOWORD (wParam) == IDM_CLOSE && bOpened) { CheckMenuItem (hMenu, IDM_OPEN, MF_UNCHECKED) ; CheckMenuItem (hMenu, IDM_CLOSE, MF_CHECKED) ; // Turn all keys off and close device for (i = 0 ; i < 16 ; i++) MidiOutMessage (hMidiOut, 0xB0, i, 123, 0) ; midiOutClose (hMidiOut) ; bOpened = FALSE ; } // Change MIDI "Device" menu command else if ( LOWORD (wParam) >= IDM_DEVICE - 1 && LOWORD (wParam) < IDM_CHANNEL) { CheckMenuItem (hMenu, IDM_DEVICE + iDevice, MF_UNCHECKED) ; iDevice = LOWORD (wParam) - IDM_DEVICE ; CheckMenuItem (hMenu, IDM_DEVICE + iDevice, MF_CHECKED) ; // Close and reopen MIDI device if (bOpened) { SendMessage (hwnd, WM_COMMAND, IDM_CLOSE, 0L) ; SendMessage (hwnd, WM_COMMAND, IDM_OPEN, 0L) ; } } // Change MIDI "Channel" menu command else if ( LOWORD (wParam) >= IDM_CHANNEL && LOWORD (wParam) < IDM_VOICE) { CheckMenuItem (hMenu, IDM_CHANNEL + iChannel, MF_UNCHECKED); iChannel = LOWORD (wParam) - IDM_CHANNEL ; CheckMenuItem (hMenu, IDM_CHANNEL + iChannel, MF_CHECKED) ; if (bOpened) MidiSetPatch (hMidiOut, iChannel, iVoice) ; } // Change MIDI "Voice" menu command else if (LOWORD (wParam) >= IDM_VOICE) { CheckMenuItem (hMenu, IDM_VOICE + iVoice, MF_UNCHECKED) ; iVoice = LOWORD (wParam) - IDM_VOICE ; CheckMenuItem (hMenu, IDM_VOICE + iVoice, MF_CHECKED) ; if (bOpened) MidiSetPatch (hMidiOut, iChannel, iVoice) ; } InvalidateRect (hwnd, NULL, TRUE) ; return 0 ; // Process a Key Up or Key Down message case WM_KEYUP: case WM_KEYDOWN: hdc = GetDC (hwnd) ; if (bOpened) ProcessKey (hdc, message, lParam) ; ReleaseDC (hwnd, hdc) ; return 0 ; // For Escape, turn off all notes and repaint case WM_CHAR: if (bOpened && wParam == 27) { for (i = 0 ; i < 16 ; i++) MidiOutMessage (hMidiOut, 0xB0, i, 123, 0) ; InvalidateRect (hwnd, NULL, TRUE) ; } return 0 ; // Horizontal scroll: Velocity case WM_HSCROLL: switch (LOWORD (wParam)) { case SB_LINEUP: iVelocity -= 1 ; break ; case SB_LINEDOWN: iVelocity += 1 ; break ; case SB_PAGEUP: iVelocity -= 8 ; break ; case SB_PAGEDOWN: iVelocity += 8 ; break ; case SB_THUMBPOSITION: iVelocity = HIWORD (wParam) ; break ; default: return 0 ; } iVelocity = max (1, min (iVelocity, 127)) ; SetScrollPos (hwnd, SB_HORZ, iVelocity, TRUE) ; return 0 ; // Vertical scroll: Pitch Bend case WM_VSCROLL: switch (LOWORD (wParam)) { case SB_THUMBTRACK: iPitchBend = 16383 - HIWORD (wParam) ; break ; case SB_THUMBPOSITION: iPitchBend = 8191 ; break ; default: return 0 ; } iPitchBend = max (0, min (iPitchBend, 16383)) ; SetScrollPos (hwnd, SB_VERT, 16383 - iPitchBend, TRUE) ; if (bOpened) MidiPitchBend (hMidiOut, iChannel, iPitchBend) ; return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; for (i = 0 ; i < NUMSCANS ; i++) if (key[i].xPos != -1) DrawKey (hdc, i, FALSE) ; midiOutGetDevCaps (iDevice, &moc, sizeof (MIDIOUTCAPS)) ; wsprintf (szBuffer, TEXT ("Channel %i"), iChannel + 1) ; TextOut ( hdc, cxCaps, 1 * cyChar, Opened ? TEXT ("Open") : TEXT ("Closed"), bOpened ? 4 : 6) ; TextOut ( hdc, cxCaps, 2 * cyChar, moc.szPname, lstrlen (moc.szPname)) ; TextOut (hdc, cxCaps, 3 * cyChar, szBuffer, lstrlen (szBuffer)) ; TextOut (hdc, cxCaps, 4 * cyChar, fam[iVoice / 8].inst[iVoice % 8].szInst, lstrlen (fam[iVoice / 8].inst[iVoice % 8].szInst)) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY : SendMessage (hwnd, WM_COMMAND, IDM_CLOSE, 0L) ; PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }
ִ��KBMIDIʱ���Ӵ���ʾ�˼����ϵļ��봫ͳ���ٻ���ٰ����Ķ�Ӧ��ʽ�����½ǵ�Z����110 Hz��Ƶ������A�����̵������У��ұ�������C�������ڶ���Ϊ�������������������м��������˹��ɱ仯��������C��G#��������������Χ�������˶����ס����⣬�ֱ�Shift����Ctrl����ʹ���������������½�1���˶����ף�������Ч���������5���˶����ס�
���������������ʼ���࣬��ô�����������κ��������������ȴӡ�Status�����ܱ���ѡ��Open������һ��MIDI����豸��������򿪳ɹ�������һ��������ϳ�������һ��MIDI Note OnѶϢ���ͷż������һ��Note OffѶϢ��ȡ��춼��̵İ������ԣ�������ͬʱ���༸��������
�ӡ�Status�����ܱ���ѡ��Close�����ر�MIDI�豸��������Ҫ�ڲ���ֹKBMIDI��ʽ�������ִ��Windows�µ�����MIDI������˵�Ǻܷ���ġ�
��Device�����ܱ��г����Ѱ�װ��MIDI����豸����Щ�豸ͨ������midiOutGetDevCaps��ʽ��á�������Щ�豸������MIDI Out�������ʵ�ʴ��ڻ򲻴��ڵ��ⲿ�ϳ������б�������MIDI Mapper�豸�����Ǵӡ�����̨���ġ���ý�塹��ѡ���MIDI�ϳ�����
��Channel�����ܱ�����ѡ���1��16��MIDIͨ�����ڶ�״̬��ѡ��ͨ��1��KBMIDI��ʽ����������MIDIѶϢ�����͵���ѡ��ͨ����
KBMIDI����һ�����ܱ����ǡ�Voice��������һ��˫�㹦�ܱ������ѡ��128��������������Щ������General MIDI�淶�ж��岢��Windows��ʵ������128������������Ϊ16�����飬ÿ����������8����������춲�ͬ��MIDI���Ŷ�Ӧ춲�ͬ�ķ�����������128����������Ҳ��Ϊ�����ɵ�������
General MIDI�л������˴��������ɵĴ��������Ҫ���������������Դӡ�Channel�����ܱ�ѡ��ͨ��10�������Դӡ�Voice�����ܱ�ѡ���һ��������������Acoustic Grand Piano����������������ͬ�ļ��Ϳ��Եõ���ͬ�����������������MIDI����35���������C�����˶����׵�B����81���������C�������˶����׵�A��������47�ֲ�ͬ�Ĵ�������������������DRUM��ʽ�о������˴������ͨ����
KBMIDI��ʽ��ˮƽ�ʹ�ֱ�����С����PC���̶԰����ٶȲ����У�������ˮƽ�����������������ٶȡ�һ����˵��������������������һ�¡��趨��ˮƽ���������ᣬ���е�Note OnѶϢ����ʹ������ٶȡ�
��ֱ�����н�����һ����Ϊ��Pitch Bend����MIDIѶϢ��Ҫʹ�ô����ԣ��밴��һ����������Ȼ���û����϶������С������϶�����������Ƶ�ʽ������������϶���Ƶ���½����ͷž������Ὣ�ָ������Ļ�����
������������ҪС��ʹ�ã���Ϊ�϶�������ʱ������ѶϢ���������ʽ��ѶϢ��Ȧ����ˣ��������һ������Ϳ�ʼ�϶������У�Ȼ��������϶�֮ǰ���ͷ��˸ü�����ô�����Խ����������ԣ��϶�������ʱ��Ҫ���»����ͷ��κμ����Թ��ܱ�Ҳ�����ƵĹ��򣺰�����ʱ��Ҫ���й��ܱ�ѡ�����⣬�ڰ������ͷ�ij�����ڼ䣬��Ҫ��Ctrl��Shift�����ı�˶����ס�
���һ�����߶���������֡�ճ�����󡹣����ͷ��������������ô�밴��Esc�������´˼���ͨ����MIDI�ϳ�����16��ͨ������16��All Notes OffѶϢ�����ر�������
KBMIDIû����Դ������������ͨ�������������Ĺ��ܱ����豸���ƴ�midiOutGetDevCaps��ʽ��ã���������������򴢴��ڳ�ʽ��һ�������Ͻṹ�С�
KBMIDI�����˼���С��ʽ����MIDIѶϢ������Pitch BendѶϢ���⣬����ѶϢ����ǰ�����۹��ˡ�Pitch BendѶϢ������7λԪֵ���һ��14λԪ�����������ȼ���0��0x1FFF֮���ֵ���ͻ�����0x2001��0x3FFF֮���ֵ���߻�����
�ӡ�Status�����ܱ�ѡ��Open��ʱ��KBMIDIΪѡ����豸����midiOutOpen������гɹ��������MidiSetPatch��ʽ���豸�ı�ʱ��KBMIDI����ر�ǰһ���豸����Ҫʱ�ٴ����豸�����ı�MIDI�豸��MIDIͨ������������ʱ��KBMIDIҲ�������MidiSetPatch��
KBMIDIͨ������WM_KEYUPѶϢ��WM_KEYDOWNѶϢ�����������ķ�����KBMIDI����һ�����аѼ���ɨ����ӳ��ɰ˶����׺����������磬����Ӣ�������Z����ɨ������44�����н�����Ϊ�˶�������3��������9����A������KBMIDI��MidiNoteOn��ʽ���Щ��ϳ���MIDI����45����12����3�ټ���9���������ϽṹҲ������Ӵ��л�������ÿ���������ض���ˮƽ�ʹ�ֱλ�ã��Լ���ʾ�ھ����е������ִ���
ˮƽ�����еĴ����Ǻ�ֱ�ӵģ�������Ҫ���ľ��Ǵ����µ��ٶȼ����趨�µľ����е�λ�á����Ǵ�����ֱ�������Կ������������IJ�������һ�����⣬�������ľ���������ֻ���������û����϶�������ʱ������SB_THUMBTRACK���Լ��ͷž�����ʱ��SB_THUMBPOSITION������SB_THUMBPOSITION����ʱ��KBMIDI��������λ���趨Ϊ�м�ȼ���������MidiPitchBend�����в���ֵ��8192��
MIDI������
��
��Щ�����������ľ�ٻ����ģ��ǡ������ɵġ��򡸰����׵ġ�����Ϊ���ǿ����ò�ͬ����������������ľ����ľ������Ӧ��ͬ�����ף�������Ҳ�������������������������������������ɵĴ��������������KBMIDI�ġ�Voice�����ܱ���ѡ��
���ǣ�����������������û�����ɣ����Dz��ܵ���������ͨ������̫������������²�����ij����������ϵ���ڡ�General MIDI���淶�У���Щû���ɵĴ����������ͨ��10��Ч����ͬ�ļ��Ŷ�Ӧ47�ֲ�ͬ�Ĵ��������
DRUM��ʽ�����ʽ22-10��ʾ����һ�����Ի��������˳�ʽ������47�ֲ�ͬ�Ĵ���������������������32��������һ�����У�Ȼ����ѡ����ٶȺ������·�������������С�
��ʽ22-10 DRUM DRUM.C /*--------------------------------------------------------------------------- DRUM.C -- MIDI Drum Machine (c) Charles Petzold, 1998 ----------------------------------------------------------------------------*/ #include <windows.h> #include <stdlib.h> #include <string.h> #include <math.h> #include "drumtime.h" #include "drumfile.h" #include "resource.h" LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; BOOL CALLBACK AboutProc (HWND, UINT, WPARAM, LPARAM) ; void DrawRectangle (HDC, int, int, DWORD *, DWORD *) ; void ErrorMessage (HWND, TCHAR *, TCHAR *) ; void DoCaption (HWND, TCHAR *) ; int AskAboutSave (HWND, TCHAR *) ; TCHAR * szPerc [NUM_PERC] = { TEXT ("Acoustic Bass Drum"), TEXT ("Bass Drum 1"), TEXT ("Side Stick"), TEXT ("Acoustic Snare"), TEXT ("Hand Clap"), TEXT ("Electric Snare"), TEXT ("Low Floor Tom"), TEXT ("Closed High Hat"), TEXT ("High Floor Tom"), TEXT ("Pedal High Hat"), TEXT ("Low Tom"), TEXT ("Open High Hat"), TEXT ("Low-Mid Tom"), TEXT ("High-Mid Tom"), TEXT ("Crash Cymbal 1"), TEXT ("High Tom"), TEXT ("Ride Cymbal 1"), TEXT ("Chinese Cymbal"), TEXT ("Ride Bell"), TEXT ("Tambourine"), TEXT ("Splash Cymbal"), TEXT ("Cowbell"), TEXT ("Crash Cymbal 2"), TEXT ("Vibraslap"), TEXT ("Ride Cymbal 2"), TEXT ("High Bongo"), TEXT ("Low Bongo"), TEXT ("Mute High Conga"), TEXT ("Open High Conga"), TEXT ("Low Conga"), TEXT ("High Timbale"), TEXT ("Low Timbale"), TEXT ("High Agogo"), TEXT ("Low Agogo"), TEXT ("Cabasa"), TEXT ("Maracas"), TEXT ("Short Whistle"), TEXT ("Long Whistle"), TEXT ("Short Guiro"), TEXT ("Long Guiro"), TEXT ("Claves"), TEXT ("High Wood Block"), TEXT ("Low Wood Block"), TEXT ("Mute Cuica"), TEXT ("Open Cuica"), TEXT ("Mute Triangle"), TEXT ("Open Triangle") } ; TCHAR szAppName [] = TEXT ("Drum") ; TCHAR szUntitled [] = TEXT ("(Untitled)") ; TCHAR szBuffer [80 + MAX_PATH] ; HANDLE hInst ; int cxChar, cyChar ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd ; MSG msg ; WNDCLASS wndclass ; hInst = hInstance ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (hInstance, szAppName) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = szAppName ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox ( NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szAppName, NULL, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_HSCROLL | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, szCmdLine) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bNeedSave ; static DRUM drum ; static HMENU hMenu ; static int iTempo = 50, iIndexLast ; static TCHAR szFileName [MAX_PATH], szTitleName [MAX_PATH] ; HDC hdc ; int i, x, y ; PAINTSTRUCT ps ; POINT point ; RECT rect ; TCHAR * szError ; switch (message) { case WM_CREATE: // Initialize DRUM structure drum.iMsecPerBeat = 100 ; drum.iVelocity = 64 ; drum.iNumBeats = 32 ; DrumSetParams (&drum) ; // Other initialization cxChar = LOWORD (GetDialogBaseUnits ()) ; cyChar = HIWORD (GetDialogBaseUnits ()) ; GetWindowRect (hwnd, &rect) ; MoveWindow (hwnd, rect.left, rect.top, 77 * cxChar, 29 * cyChar, FALSE) ; hMenu = GetMenu (hwnd) ; // Initialize "Volume" scroll bar SetScrollRange (hwnd, SB_HORZ, 1, 127, FALSE) ; SetScrollPos (hwnd, SB_HORZ, drum.iVelocity, TRUE) ; // Initialize "Tempo" scroll bar SetScrollRange (hwnd, SB_VERT, 0, 100, FALSE) ; SetScrollPos (hwnd, SB_VERT, iTempo, TRUE) ; DoCaption (hwnd, szTitleName) ; return 0 ; case WM_COMMAND: switch (LOWORD (wParam)) { case IDM_FILE_NEW: if ( bNeedSave && IDCANCEL == AskAboutSave (hwnd, szTitleName)) return 0 ; // Clear drum pattern for (i = 0 ; i < NUM_PERC ; i++) { drum.dwSeqPerc [i] = 0 ; drum.dwSeqPian [i] = 0 ; } InvalidateRect (hwnd, NULL, FALSE) ; DrumSetParams (&drum) ; bNeedSave = FALSE ; return 0 ; case IDM_FILE_OPEN: // Save previous file if (bNeedSave && IDCANCEL == AskAboutSave (hwnd, szTitleName)) return 0 ; // Open the selected file if (DrumFileOpenDlg (hwnd, szFileName, szTitleName)) { szError = DrumFileRead (&drum, szFileName) ; if (szError != NULL) { ErrorMessage (hwnd, szError, szTitleName) ; szTitleName [0] = '\0' ; } else { // Set new parameters Tempo = (int) (50 * (log10 (drum.iMsecPerBeat) - 1)) ; SetScrollPos (hwnd, SB_VERT, iTempo, TRUE) ; SetScrollPos (hwnd, SB_HORZ, drum.iVelocity, TRUE) ; DrumSetParams (&drum) ; InvalidateRect (hwnd, NULL, FALSE) ; bNeedSave = FALSE ; } DoCaption (hwnd, szTitleName) ; } return 0 ; case IDM_FILE_SAVE: case IDM_FILE_SAVE_AS: // Save the selected file if ((LOWORD (wParam) == IDM_FILE_SAVE && szTitleName [0]) || DrumFileSaveDlg (hwnd, szFileName, szTitleName)) { szError = DrumFileWrite (&drum, szFileName) ; if (szError != NULL) { ErrorMessage (hwnd, szError, szTitleName) ; szTitleName [0] = '\0' ; } else bNeedSave = FALSE ; DoCaption (hwnd, szTitleName) ; } return 0 ; case IDM_APP_EXIT: SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ; return 0 ; case IDM_SEQUENCE_RUNNING: // Begin sequence if (!DrumBeginSequence (hwnd)) { ErrorMessage (hwnd, TEXT ("Could not start MIDI sequence -- ") TEXT ("MIDI Mapper device is unavailable!"), szTitleName) ; } else { CheckMenuItem (hMenu, IDM_SEQUENCE_RUNNING, MF_CHECKED) ; CheckMenuItem (hMenu, IDM_SEQUENCE_STOPPED, MF_UNCHECKED) ; } return 0 ; case IDM_SEQUENCE_STOPPED: // Finish at end of sequence DrumEndSequence (FALSE) ; return 0 ; case IDM_APP_ABOUT: DialogBox (hInst, TEXT ("AboutBox"), hwnd, AboutProc) ; return 0 ; } return 0 ; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: hdc = GetDC (hwnd) ; // Convert mouse coordinates to grid coordinates x = LOWORD (lParam) / cxChar - 40 ; y = 2 * HIWORD (lParam) / cyChar - 2 ; // Set a new number of beats of sequence if (x > 0 && x <= 32 && y < 0) { SetTextColor (hdc, RGB (255, 255, 255)) ; TextOut (hdc, (40 + drum.iNumBeats) * cxChar, 0, TEXT (":|"), 2); SetTextColor (hdc, RGB (0, 0, 0)) ; if (drum.iNumBeats % 4 == 0) TextOut ( hdc, (40 + drum.iNumBeats) * cxChar, 0, TEXT ("."), 1) ; drum.iNumBeats = x ; TextOut (hdc, (40 + drum.iNumBeats) * cxChar, 0, TEXT (":|"), 2); bNeedSave = TRUE ; } // Set or reset a percussion instrument beat if (x >= 0 && x < 32 && y >= 0 && y < NUM_PERC) { if (message == WM_LBUTTONDOWN) drum.dwSeqPerc[y] ^= (1 << x) ; else drum.dwSeqPian[y] ^= (1 << x) ; DrawRectangle (hdc, x, y, drum.dwSeqPerc, drum.dwSeqPian) ; bNeedSave = TRUE ; } ReleaseDC (hwnd, hdc) ; DrumSetParams (&drum) ; return 0 ; case WM_HSCROLL: // Change the note velocity switch (LOWORD (wParam)) { case SB_LINEUP: drum.iVelocity -= 1 ; break ; case SB_LINEDOWN: drum.iVelocity += 1 ; break ; case SB_PAGEUP: drum.iVelocity -= 8 ; break ; case SB_PAGEDOWN: drum.iVelocity += 8 ; break ; case SB_THUMBPOSITION: drum.iVelocity = HIWORD (wParam) ; break ; default: return 0 ; } drum.iVelocity = max (1, min (drum.iVelocity, 127)) ; SetScrollPos (hwnd, SB_HORZ, drum.iVelocity, TRUE) ; DrumSetParams (&drum) ; bNeedSave = TRUE ; return 0 ; case WM_VSCROLL: // Change the tempo switch (LOWORD (wParam)) { case SB_LINEUP: iTempo -= 1 ; break ; case SB_LINEDOWN: iTempo += 1 ; break ; case SB_PAGEUP: iTempo -= 10 ; break ; case SB_PAGEDOWN: iTempo += 10 ; break ; case SB_THUMBPOSITION: iTempo = HIWORD (wParam) ; break ; default: return 0 ; } iTempo = max (0, min (iTempo, 100)) ; SetScrollPos (hwnd, SB_VERT, iTempo, TRUE) ; drum.iMsecPerBeat = (WORD) (10 * pow (100, iTempo / 100.0)) ; DrumSetParams (&drum) ; bNeedSave = TRUE ; return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; SetTextAlign (hdc, TA_UPDATECP) ; SetBkMode (hdc, TRANSPARENT) ; // Draw the text strings and horizontal lines for (i = 0 ; i < NUM_PERC ; i++) { MoveToEx (hdc, i & 1 ? 20 * cxChar : cxChar, (2 * i + 3) * cyChar / 4, NULL) ; TextOut (hdc, 0, 0, szPerc [i], lstrlen (szPerc [i])) ; GetCurrentPositionEx (hdc, &point) ; MoveToEx (hdc, point.x + cxChar, point.y + cyChar / 2, NULL) ; LineTo (hdc, 39 * cxChar, point.y + cyChar / 2) ; } SetTextAlign (hdc, 0) ; // Draw rectangular grid, repeat mark, and beat marks for (x = 0 ; x < 32 ; x++) { for (y = 0 ; y < NUM_PERC ; y++) DrawRectangle (hdc, x, y, drum.dwSeqPerc, drum.dwSeqPian) ; SetTextColor ( hdc, x == drum.iNumBeats - 1 ? RGB (0, 0, 0) : RGB (255, 255, 255)) ; TextOut (hdc, (41 + x) * cxChar, 0, TEXT (":|"), 2) ; SetTextColor (hdc, RGB (0, 0, 0)) ; if (x % 4 == 0) TextOut (hdc, (40 + x) * cxChar, 0, TEXT ("."), 1) ; } EndPaint (hwnd, &ps) ; return 0 ; case WM_USER_NOTIFY: // Draw the "bouncing ball" hdc = GetDC (hwnd) ; SelectObject (hdc, GetStockObject (NULL_PEN)) ; SelectObject (hdc, GetStockObject (WHITE_BRUSH)) ; for (i = 0 ; i < 2 ; i++) { x = iIndexLast ; y = NUM_PERC + 1 ; Ellipse (hdc, (x + 40) * cxChar, (2 * y + 3) * cyChar / 4, (x + 41) * cxChar, (2 * y + 5) * cyChar / 4); iIndexLast = wParam ; SelectObject (hdc, GetStockObject (BLACK_BRUSH)) ; } ReleaseDC (hwnd, hdc) ; return 0 ; case WM_USER_ERROR: ErrorMessage (hwnd, TEXT ("Can't set timer event for tempo"), szTitleName) ; // fall through case WM_USER_FINISHED: DrumEndSequence (TRUE) ; CheckMenuItem (hMenu, IDM_SEQUENCE_RUNNING, MF_UNCHECKED) ; CheckMenuItem (hMenu, IDM_SEQUENCE_STOPPED, MF_CHECKED) ; return 0 ; case WM_CLOSE: if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName)) DestroyWindow (hwnd) ; return 0 ; case WM_QUERYENDSESSION: if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName)) return 1L ; return 0 ; case WM_DESTROY: DrumEndSequence (TRUE) ; PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; } BOOL CALLBACK AboutProc ( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_INITDIALOG: return TRUE ; case WM_COMMAND: switch (LOWORD (wParam)) { case IDOK: EndDialog (hDlg, 0) ; return TRUE ; } break ; } return FALSE ; } void DrawRectangle ( HDC hdc, int x, int y, DWORD * dwSeqPerc, DWORD * dwSeqPian) { int iBrush ; if (dwSeqPerc [y] & dwSeqPian [y] & (1L << x)) iBrush = BLACK_BRUSH ; else if (dwSeqPerc [y] & (1L << x)) iBrush = DKGRAY_BRUSH ; else if (dwSeqPian [y] & (1L << x)) iBrush = LTGRAY_BRUSH ; else iBrush = WHITE_BRUSH ; SelectObject (hdc, GetStockObject (iBrush)) ; Rectangle (hdc, (x + 40) * cxChar , (2 * y + 4) * cyChar / 4, (x + 41) * cxChar + 1, (2 * y + 6) * cyChar / 4 + 1) ; } void ErrorMessage (HWND hwnd, TCHAR * szError, TCHAR * szTitleName) { wsprintf (szBuffer, szError, (LPSTR) (szTitleName [0] ? szTitleName : szUntitled)) ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szBuffer, szAppName, MB_OK | MB_ICONEXCLAMATION) ; } void DoCaption (HWND hwnd, TCHAR * szTitleName) { wsprintf (szBuffer, TEXT ("MIDI Drum Machine - %s"), (LPSTR) (szTitleName [0] ? szTitleName : szUntitled)) ; SetWindowText (hwnd, szBuffer) ; } int AskAboutSave (HWND hwnd, TCHAR * szTitleName) { int iReturn ; wsprintf (szBuffer, TEXT ("Save current changes in %s?"), (LPSTR) (szTitleName [0] ? szTitleName : szUntitled)) ; iReturn = MessageBox ( hwnd, szBuffer, szAppName, MB_YESNOCANCEL | MB_ICONQUESTION) ; if (iReturn == IDYES) if (!SendMessage (hwnd, WM_COMMAND, IDM_FILE_SAVE, 0)) iReturn = IDCANCEL ; return iReturn ; }
DRUMTIME.H /*-------------------------------------------------------------------------- DRUMTIME.H Header File for Time Functions for DRUM Program ----------------------------------------------------------------------------*/ #define NUM_PERC 47 #define WM_USER_NOTIFY (WM_USER + 1) #define WM_USER_FINISHED (WM_USER + 2) #define WM_USER_ERROR (WM_USER + 3) #pragma pack(push, 2) typedef struct { short iMsecPerBeat ; short iVelocity ; short iNumBeats ; DWORD dwSeqPerc [NUM_PERC] ; DWORD dwSeqPian [NUM_PERC] ; } DRUM, * PDRUM ; #pragma pack(pop) void DrumSetParams (PDRUM) ; BOOL DrumBeginSequence (HWND) ; void DrumEndSequence (BOOL) ;
DRUMTIME.C /*----------------------------------------------------------------------------- DRUMFILE.C -- Timer Routines for DRUM (c) Charles Petzold, 1998 -----------------------------------------------------------------------------*/ #include <windows.h> #include "drumtime.h" #define minmax(a,x,b) (min (max (x, a), b)) #define TIMER_RES 5 void CALLBACK DrumTimerFunc (UINT, UINT, DWORD, DWORD, DWORD) ; BOOL bSequenceGoing, bEndSequence ; DRUM drum ; HMIDIOUT hMidiOut ; HWND hwndNotify ; int iIndex ; UINT uTimerRes, uTimerID ; DWORD MidiOutMessage ( HMIDIOUT hMidi, int iStatus, int iChannel, int iData1, int iData2) { DWORD dwMessage ; dwMessage = iStatus | iChannel | (iData1 << 8) | (iData2 << 16) ; return midiOutShortMsg (hMidi, dwMessage) ; } void DrumSetParams (PDRUM pdrum) { CopyMemory (&drum, pdrum, sizeof (DRUM)) ; } BOOL DrumBeginSequence (HWND hwnd) { TIMECAPS tc ; hwndNotify = hwnd ; // Save window handle for notification DrumEndSequence (TRUE) ; // Stop current sequence if running // Open the MIDI Mapper output port if (midiOutOpen (&hMidiOut, MIDIMAPPER, 0, 0, 0)) return FALSE ; // Send Program Change messages for channels 9 and 0 MidiOutMessage (hMidiOut, 0xC0, 9, 0, 0) ; MidiOutMessage (hMidiOut, 0xC0, 0, 0, 0) ; // Begin sequence by setting a timer event timeGetDevCaps (&tc, sizeof (TIMECAPS)) ; uTimerRes = minmax (tc.wPeriodMin, TIMER_RES, tc.wPeriodMax) ; timeBeginPeriod (uTimerRes) ; uTimerID = timeSetEvent(max ((UINT) uTimerRes, (UINT) drum.iMsecPerBeat), uTimerRes, DrumTimerFunc, 0, TIME_ONESHOT) ; if (uTimerID == 0) { timeEndPeriod (uTimerRes) ; midiOutClose (hMidiOut) ; return FALSE ; } iIndex = -1 ; bEndSequence = FALSE ; bSequenceGoing = TRUE ; return TRUE ; } void DrumEndSequence (BOOL bRightAway) { if (bRightAway) { if (bSequenceGoing) { // stop the timer if (uTimerID) timeKillEvent (uTimerID) ; timeEndPeriod (uTimerRes) ; // turn off all notes MidiOutMessage (hMidiOut, 0xB0, 9, 123, 0) ; MidiOutMessage (hMidiOut, 0xB0, 0, 123, 0) ; // close the MIDI port midiOutClose (hMidiOut) ; bSequenceGoing = FALSE ; } } else bEndSequence = TRUE ; } void CALLBACK DrumTimerFunc ( UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { static DWORD dwSeqPercLast [NUM_PERC], dwSeqPianLast [NUM_PERC] ; int i ; // Note Off messages for channels 9 and 0 if (iIndex != -1) { for (i = 0 ; i < NUM_PERC ; i++) { if (dwSeqPercLast[i] & 1 << iIndex) MidiOutMessage (hMidiOut, 0x80, 9, i + 35, 0) ; if (dwSeqPianLast[i] & 1 << iIndex) MidiOutMessage (hMidiOut, 0x80, 0, i + 35, 0) ; } } // Increment index and notify window to advance bouncing ball iIndex = (iIndex + 1) % drum.iNumBeats ; PostMessage (hwndNotify, WM_USER_NOTIFY, iIndex, timeGetTime ()) ; // Check if ending the sequence if (bEndSequence && iIndex == 0) { PostMessage (hwndNotify, WM_USER_FINISHED, 0, 0L) ; return ; } // Note On messages for channels 9 and 0 for (i = 0 ; i < NUM_PERC ; i++) { if (drum.dwSeqPerc[i] & 1 << iIndex) MidiOutMessage (hMidiOut, 0x90, 9, i + 35, drum.iVelocity) ; if (drum.dwSeqPian[i] & 1 << iIndex) MidiOutMessage (hMidiOut, 0x90, 0, i + 35, drum.iVelocity) ; dwSeqPercLast[i] = drum.dwSeqPerc[i] ; dwSeqPianLast[i] = drum.dwSeqPian[i] ; } // Set a new timer event uTimerID = timeSetEvent (max ((int) uTimerRes, drum.iMsecPerBeat), uTimerRes, DrumTimerFunc, 0, TIME_ONESHOT) ; if (uTimerID == 0) { PostMessage (hwndNotify, WM_USER_ERROR, 0, 0) ; } }
DRUMFILE.H /*--------------------------------------------------------------------------- DRUMFILE.H Header File for File I/O Routines for DRUM -----------------------------------------------------------------------------*/ BOOL DrumFileOpenDlg (HWND, TCHAR *, TCHAR *) ; BOOL DrumFileSaveDlg (HWND, TCHAR *, TCHAR *) ; TCHAR * DrumFileWrite (DRUM *, TCHAR *) ; TCHAR * DrumFileRead (DRUM *, TCHAR *) ;
DRUMFILE.C /*---------------------------------------------------------------------------- DRUMFILE.C -- File I/O Routines for DRUM (c) Charles Petzold, 1998 -----------------------------------------------------------------------------*/ #include <windows.h> #include <commdlg.h> #include "drumtime.h" #include "drumfile.h" OPENFILENAME ofn = { sizeof (OPENFILENAME) } ; TCHAR * szFilter[] = { TEXT ("Drum Files (*.DRM)"), TEXT ("*.drm"), TEXT ("") } ; TCHAR szDrumID [] = TEXT ("DRUM") ; TCHAR szListID [] = TEXT ("LIST") ; TCHAR szInfoID [] = TEXT ("INFO") ; TCHAR szSoftID [] = TEXT ("ISFT") ; TCHAR szDateID [] = TEXT ("ISCD") ; TCHAR szFmtID [] = TEXT ("fmt ") ; TCHAR szDataID [] = TEXT ("data") ; char szSoftware [] = "DRUM by Charles Petzold, Programming Windows" ; TCHAR szErrorNoCreate [] = TEXT ("File %s could not be opened for writing."); TCHAR szErrorCannotWrite [] = TEXT ("File %s could not be written to. ") ; TCHAR szErrorNotFound [] = TEXT ("File %s not found or cannot be opened.") ; TCHAR szErrorNotDrum [] = TEXT ("File %s is not a standard DRUM file.") ; TCHAR szErrorUnsupported [] = TEXT ("File %s is not a supported DRUM file.") ; TCHAR szErrorCannotRead [] = TEXT ("File %s cannot be read.") ; BOOL DrumFileOpenDlg (HWND hwnd, TCHAR * szFileName, TCHAR * szTitleName) { ofn.hwndOwner = hwnd ; ofn.lpstrFilter = szFilter [0] ; ofn.lpstrFile = szFileName ; ofn.nMaxFile = MAX_PATH ; ofn.lpstrFileTitle = szTitleName ; ofn.nMaxFileTitle = MAX_PATH ; ofn.Flags = OFN_CREATEPROMPT ; ofn.lpstrDefExt = TEXT ("drm") ; return GetOpenFileName (&ofn) ; } BOOL DrumFileSaveDlg ( HWND hwnd, TCHAR * szFileName, TCHAR * szTitleName) { ofn.hwndOwner = hwnd ; ofn.lpstrFilter = szFilter [0] ; ofn.lpstrFile = szFileName ; ofn.nMaxFile = MAX_PATH ; ofn.lpstrFileTitle = szTitleName ; ofn.nMaxFileTitle = MAX_PATH ; ofn.Flags = OFN_OVERWRITEPROMPT ; ofn.lpstrDefExt = TEXT ("drm") ; return GetSaveFileName (&ofn) ; } TCHAR * DrumFileWrite (DRUM * pdrum, TCHAR * szFileName) { char szDateBuf [16] ; HMMIO hmmio ; int iFormat = 2 ; MMCKINFO mmckinfo [3] ; SYSTEMTIME st ; WORD wError = 0 ; memset (mmckinfo, 0, 3 * sizeof (MMCKINFO)) ; // Recreate the file for writing if ((hmmio = mmioOpen (szFileName, NULL, MMIO_CREATE | MMIO_WRITE | MMIO_ALLOCBUF)) == NULL) return szErrorNoCreate ; // Create a "RIFF" chunk with a "CPDR" type mmckinfo[0].fccType = mmioStringToFOURCC (szDrumID, 0) ; wError |= mmioCreateChunk (hmmio, &mmckinfo[0], MMIO_CREATERIFF) ; // Create "LIST" sub-chunk with an "INFO" type mmckinfo[1].fccType = mmioStringToFOURCC (szInfoID, 0) ; wError |= mmioCreateChunk (hmmio, &mmckinfo[1], MMIO_CREATELIST) ; // Create "ISFT" sub-sub-chunk mmckinfo[2].ckid = mmioStringToFOURCC (szSoftID, 0) ; wError |= mmioCreateChunk (hmmio, &mmckinfo[2], 0) ; wError |= (mmioWrite (hmmio, szSoftware, sizeof (szSoftware)) != sizeof (szSoftware)) ; wError |= mmioAscend (hmmio, &mmckinfo[2], 0) ; // Create a time string GetLocalTime (&st) ; wsprintfA (szDateBuf, "%04d-%02d-%02d", st.wYear, st.wMonth, st.wDay) ; // Create "ISCD" sub-sub-chunk mmckinfo[2].ckid = mmioStringToFOURCC (szDateID, 0) ; wError |= mmioCreateChunk (hmmio, &mmckinfo[2], 0) ; wError |= (mmioWrite (hmmio, szDateBuf, (strlen (szDateBuf) + 1)) != (int) (strlen (szDateBuf) + 1)) ; wError |= mmioAscend (hmmio, &mmckinfo[2], 0) ; wError |= mmioAscend (hmmio, &mmckinfo[1], 0) ; // Create "fmt " sub-chunk mmckinfo[1].ckid = mmioStringToFOURCC (szFmtID, 0) ; wError |= mmioCreateChunk (hmmio, &mmckinfo[1], 0) ; wError |= (mmioWrite (hmmio, (PSTR) &iFormat, sizeof (int)) != sizeof (int)) ; wError |= mmioAscend (hmmio, &mmckinfo[1], 0) ; // Create the "data" sub-chunk mmckinfo[1].ckid = mmioStringToFOURCC (szDataID, 0) ; wError |= mmioCreateChunk (hmmio, &mmckinfo[1], 0) ; wError |= (mmioWrite (hmmio, (PSTR) pdrum, sizeof (DRUM)) != sizeof (DRUM)) ; wError |= mmioAscend (hmmio, &mmckinfo[1], 0) ; wError |= mmioAscend (hmmio, &mmckinfo[0], 0) ; // Clean up and return wError |= mmioClose (hmmio, 0) ; if (wError) { mmioOpen (szFileName, NULL, MMIO_DELETE) ; return szErrorCannotWrite ; } return NULL ; } TCHAR * DrumFileRead (DRUM * pdrum, TCHAR * szFileName) { DRUM drum ; HMMIO hmmio ; int i, iFormat ; MMCKINFO mmckinfo [3] ; ZeroMemory (mmckinfo, 2 * sizeof (MMCKINFO)) ; // Open the file if ((hmmio = mmioOpen (szFileName, NULL, MMIO_READ)) == NULL) return szErrorNotFound ; // Locate a "RIFF" chunk with a "DRUM" form-type mmckinfo[0].ckid = mmioStringToFOURCC (szDrumID, 0) ; if (mmioDescend (hmmio, &mmckinfo[0], NULL, MMIO_FINDRIFF)) { mmioClose (hmmio, 0) ; return szErrorNotDrum ; } // Locate, read, and verify the "fmt " sub-chunk mmckinfo[1].ckid = mmioStringToFOURCC (szFmtID, 0) ; if (mmioDescend (hmmio, &mmckinfo[1], &mmckinfo[0], MMIO_FINDCHUNK)) { mmioClose (hmmio, 0) ; return szErrorNotDrum ; } if (mmckinfo[1].cksize != sizeof (int)) { mmioClose (hmmio, 0) ; return szErrorUnsupported ; } if (mmioRead (hmmio, (PSTR) &iFormat, sizeof (int)) != sizeof (int)) { mmioClose (hmmio, 0) ; return szErrorCannotRead ; } if (iFormat != 1 && iFormat != 2) { mmioClose (hmmio, 0) ; return szErrorUnsupported ; } // Go to end of "fmt " sub-chunk mmioAscend (hmmio, &mmckinfo[1], 0) ; // Locate, read, and verify the "data" sub-chunk mmckinfo[1].ckid = mmioStringToFOURCC (szDataID, 0) ; if (mmioDescend (hmmio, &mmckinfo[1], &mmckinfo[0], MMIO_FINDCHUNK)) { mmioClose (hmmio, 0) ; return szErrorNotDrum ; } if (mmckinfo[1].cksize != sizeof (DRUM)) { mmioClose (hmmio, 0) ; return szErrorUnsupported ; } if (mmioRead (hmmio, (LPSTR) &drum, sizeof (DRUM)) != sizeof (DRUM)) { mmioClose (hmmio, 0) ; return szErrorCannotRead ; } // Close the file mmioClose (hmmio, 0) ; // Convert format 1 to format 2 and copy the DRUM structure data if (iFormat == 1) { for (i = 0 ; i < NUM_PERC ; i++) { drum.dwSeqPerc [i] = drum.dwSeqPian [i] ; drum.dwSeqPian [i] = 0 ; } } memcpy (pdrum, &drum, sizeof (DRUM)) ; return NULL ; }
DRUM.RC ��ժ¼�� //Microsoft Developer Studio generated resource script. #include "resource.h" #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// // Menu DRUM MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&New", IDM_FILE_NEW MENUITEM "&Open...", IDM_FILE_OPEN MENUITEM "&Save", IDM_FILE_SAVE MENUITEM "Save &As...", IDM_FILE_SAVE_AS MENUITEM SEPARATOR MENUITEM "E&xit", IDM_APP_EXIT END POPUP "&Sequence" BEGIN MENUITEM "&Running", IDM_SEQUENCE_RUNNING MENUITEM "&Stopped", IDM_SEQUENCE_STOPPED , CHECKED END POPUP "&Help" BEGIN MENUITEM "&About...", IDM_APP_ABOUT END END ///////////////////////////////////////////////////////////////////////////// // Icon DRUM ICON DISCARDABLE "drum.ico" ///////////////////////////////////////////////////////////////////////////// // Dialog ABOUTBOX DIALOG DISCARDABLE 20, 20, 160, 164 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Dialog" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,54,143,50,14 ICON "DRUM",IDC_STATIC,8,8,21,20 CTEXT "DRUM",IDC_STATIC,34,12,90,8 CTEXT "MIDI Drum Machine",IDC_STATIC,7,36,144,8 CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,8,88,144,46 LTEXT "Left Button:\t\tDrum sounds",IDC_STATIC,12,92,136,8 LTEXT "Right Button:\t\tPiano sounds",IDC_STATIC,12,102,136,8 LTEXT "Horizontal Scroll:\t\tVelocity",IDC_STATIC,12,112,136,8 LTEXT "Vertical Scroll:\t\tTempo",IDC_STATIC,12,122,136,8 CTEXT "Copyright (c) Charles Petzold, 1998",IDC_STATIC,8,48, 144,8 CTEXT """Programming Windows,"" 5th Edition",IDC_STATIC,8,60, 144,8 END
RESOURCE.H ��ժ¼�� // Microsoft Developer Studio generated include file. // Used by Drum.rc #define IDM_FILE_NEW 40001 #define IDM_FILE_OPEN 40002 #define IDM_FILE_SAVE 40003 #define IDM_FILE_SAVE_AS 40004 #define IDM_APP_EXIT 40005 #define IDM_SEQUENCE_RUNNING 40006 #define IDM_SEQUENCE_STOPPED 40007 #define IDM_APP_ABOUT 40008
����һ��ִ��DRUMʱ�������������Ӵ��������У����һ�а������г���47�ֲ�ͬ�Ĵ���������ұߵ������Ǵ��������������ʱ��Ķ�ά���С�ÿһ�����������Ӧ�����е�һ�С�32�о���32�ġ����Ҫ����32�ij�����һ��4/4�ĵ�С���У���ÿС��4���ķ�����������ôÿ1�Ķ�Ӧһ����ʮ����������
�ӡ�Sequence�����ܱ�ѡ��Running��ʱ����ʽ����ͼ��MIDI Mapper�豸�����ʧ�ܣ�өĻ������һ��ѶϢ���顣������������һ����������С��������Ľ���������ײ�������
��������κ�λ�õ���������������ڴ�������������������������ʱ���򽫱�ɰ���ɫ���û����Ҽ����������Ӹ��ٵ����ӣ���ʱ���򽫻�������ɫ�����������������ͬʱ��ֱ𣩣������򽫱�ɺ�ɫ�����ҿ���ͬʱ������������͸��ٵ��������ٴε������е�һ������˫�����رո����е�������
�����ϲ���ÿ4��һ���㡣��Щ��ʹ���Dz��ù���ļ���Ϳ��Ժܼ��׵�ȷ��������λ�á���������Ͻ���һ��ð�ź�һ�����ߣ�:|�������ǿ�������ͳ���ַ����еķ����Ǻš�������ű�ʾ���еij��ȡ�������ͨ�������������������Ǻŷ���������ڵ�����λ�á���������ࣨ����������ֻ�����෴���Ǻ����ڵ����ӡ����Ҫ���������Ƚ��࣬��Ӧ�������Ǻ��趨Ϊ3�ĵ����ɱ���
ˮƽ�����п���MIDI Note OnѶϢ�е�����λԪ�顣����Ȼ�ܸı�һЩ�ϳ��������ʣ���һ���Ӱ����������ʽ��������ʾ������趨���м�λ�á���ֱ�����п������ӡ����Ƕ����̶ȣ���Χ��ÿ��1�루�������ڵײ�����ÿ��10���루�������ڶ���������ʽ����������趨Ϊÿ��100���루1/10�룩����ʱ���������м䡣
��File�����ܱ�����������Ͷ�ȡ������Ϊ.DRM�ĵ����������Ҷ����һ�ָ�ʽ����Щ������С��������RIFF�ĵ�����ʽ������һ�������µĶ�ý�����ϵ����Ƽ�ʹ�õĸ�ʽ����Help�����ܱ��еġ�About��ѡ����ʾһ���Ի����飬�öԻ�������һ�ηdz�������ժҪ��˵�������������е��÷��Լ����������еĹ��ܡ�
���ᣬ��Sequence�����ܱ��еġ�Stopped��ѡ�����Ŀǰ���н�������ֹ�������ر�MIDI Mapper�豸��
��ý��time��ʽ
��
�����ܻ�ע�⵽DRUM.Cû�к����κζ�ý�庯ʽ�������е�ʵ�ʲ�����������DRUMTIMEģ���С�
��Ȼ��ͨ��Windows��ʱ��ʹ�������ܼ򵥣������Լ�ʱʱ��Ӧ��ȴ�������Ե�Ӱ�졣����������BACHTOCC��ʽ����������һ�����������־���������һ�ּ�ʱʱ��Ӧ�ã��Դ�Windows��ʱ���Dz����ʵġ�Ϊ���ṩ��PC������MIDI����Ҫ�ľ�ȷ�ȣ���ý��API������һ���߽����ȵļ�ʱ�����˼�ʱ��ͨ��7��������time�ĺ�ʽʵ������Щ��ʽ��һ���Ƕ���ģ���DRUMTIMEչʾ������6����ʽ����;����ʱ����ʽ������ִ����һ������ִ�����е�callback��ʽ��ϵͳ�����ճ�ʽָ���ļ�ʱ���ӳ�ʱ�������м�ʱ����
������ý���ʱ��ʱ�������ú���ָ�����ֲ�ͬ��ʱ�䡣��һ�����ӳ�ʱ�䣬�ڶ�����Ϊ�����ȡ���������Ϊ���������ݴ������ָ��һ���ӳ�100���룬����������10���룬���ʱ����ʵ���ӳٷ�Χ��90��110����֮�䡣
ʹ�ü�ʱ��֮ǰ��Ӧ��ü�ʱ�����豸������
timeGetDevCaps (&timecaps, uSize) ;
��һ��������TIMECAPS��̬�ṹ��ָ�꣬�ڶ��������Ǵ˽ṹ�Ĵ�С��TIMECAPS�ṹֻ��������λ��wPeriodMin��wPeriodMax�����Ǽ�ʱ��װ��������ʽ��֧Ԯ����С�����Ľ�����ֵ���������timeGetDevCaps���ٲ鿴��Щֵ���ᷢ��wPeriodMin��1��wPeriodMax��65535�����Դ˺�ʽ�����Ǻ���Ҫ���������õ���Щ������ֵ�����������ʱ����ʽ�����Ǹ������⡣
��һ������
timeBeginPeriod (uResolution) ;
��ָ����ʽ����Ҫ�ļ�ʱ�������ȵ����ֵ����ֵӦ��TIMECAPS�ṹ��ȷ���ķ�Χ֮�ڡ��˺�������Ϊ����ʹ�ü�ʱ���Ķ����ʽ�ṩ��õļ�ʱ��װ��������ʽ������timeBeginPeriod��timeEndPeriod����ɶԳ��֣��ҽ��������timeEndPeriod����̵�������
���ڿ��������趨һ����ʱ���¼���
idTimer = timeSetEvent ( uDelay, uResolution, CallBackFunc, dwData, uFlag) ;
����������󣬴Ӻ��д��ص�idTimer����0���ں��е����棬����Windows����uDelay����������CallBackFunc��ʽ�����������������uResolutionָ����uResolutionֵ�����춻��춴��ݸ�timeBeginPeriod�Ľ����ȡ�dwData�dz�ʽ��������ϣ��������ݸ�CallBackFunc������һ������������TIME_ONESHOT��Ҳ������TIME_PERIODIC��ǰ�������uDelay�������л��һ��CallBackFunc���У����������ÿ��uDelay���붼���һ��CallBackFunc���С�
Ҫ�ں���CallBackFunc֮ǰ��ֹֻ����һ�εļ�ʱ���¼���������ͣ�����Եļ�ʱ���¼��������
timeKillEvent (idTimer) ;
����CallBackFunc�᲻��ɾ��ֻ����һ�εļ�ʱ���¼����ڳ�ʽ�������ʱ�����ᣬ�����
timeEndPeriod (wResolution) ;
���еIJ����봫�ݸ�timeBeginPeriod����ͬ��
��������ʽ��������time����ʽ
dwSysTime = timeGetTime () ;
���ش�Windows��һ�����������ڵ�ϵͳʱ�䣬��λ�Ǻ��롣��ʽ
timeGetSystemTime (&mmtime, uSize) ;
��Ҫһ��MMTIME�ṹ��ָ�꣨���һ������һ�������Լ��˽ṹ�Ĵ�С����ڶ�������һ��������ȻMMTIME�ṹ���������������������õ��Ǻ����ʽ��ϵͳʱ�䣬���������������غ���ʱ�䡣����timeGetSystemTime�Ƕ���ġ�
Callback��ʽֻ�������������Windows��ʽ�����С�Callback��ʽ���Ժ���PostMessage��PostMessage�������ĸ���ʱ����ʽ��timeSetEvent��timeKillEvent��timeGetTime�Ͷ����timeGetSystemTime��������MIDI�����ʽ��midiOutShortMsg��midiOutLongMsg���Լ����Ժ�ʽOutputDebugStr��
�����ԣ���ƶ�ý���ʱ����Ҫ�����MIDI���ж���������������档��Ȼ������ʹ��PostMessage��֪ͨ��ʱ���¼����Ӵ�ѶϢ������ʽ�������Ӵ�ѶϢ������ʽ�������κ����������£�ֻ�Dz��ܻ�Ӧ��ʱ��callback������׼ȷ�ԡ�
Callback��ʽ�������������ֻʹ��������������������timeSetEvent���صļ�ʱ��ID�������Ϊ�������ݸ�timeSetEvent��dwDataֵ��
DRUM.Cģ�����DRUMTIME.C�е�DrumSetParams��ʽ�кܶ�Σ�����DRUM�Ӵ�ʱ��ʹ�����������ϵ��������ƶ�������ʱ���Ӵ�Ƭ������.DRM����ʱ�Լ��������ʱ��DrumSetParams��Ψһ�IJ�����ָ��DRUM��̬�ṹ��ָ�꣬�˽ṹ��̬��DRUMTIME.H���塣�ýṹ�Ժ���Ϊ��λ��������ʱ�䡢�ٶȣ�ͨ����Ӧ��������������е������Լ���춴�������Ϊ��������͸������趨��������47��32λԪ�����������Щ32λԪ�����е�ÿһλԪ����Ӧ���е�һ�ġ�DRUM.Cģ�齫�ھ�̬��������ά��һ��DRUM��̬�Ľṹ�����ں���DrumSetParamsʱ��������һ��ָ�ꡣDrumSetParamsֻ�򵥵ظ��ƴ˽ṹ�����ݡ�
Ҫ�������У�DRUM����DRUMTIME�е�DrumBeginSequence��ʽ��Ψһ�IJ��������Ӵ����ţ���������֪ͨ��DrumBeginSequence��MIDI Mapper����豸������ɹ�������Program ChangeѶϢ��ΪMIDIͨ��0��9ѡ��������������Щͨ���ǻ��0�ģ�����9ʵ��ָ����MIDIͨ��10�����������ͨ������һ��ͨ����춸���������DrumBeginSequence͸������timeGetDevCaps��timeBeginPeriod��������������TIMER_RES����������ʱ��������ͨ����5���룬���Ҷ�����һ������minmax�ľ޼��������timeGetDevCaps���ص����Ʒ�Χ���ڵĽ����ȡ�
��һ��������timeSetEvent�����ȷ������ʱ�䣬��������ȡ�callback��ʽDrumTimerFunc�Լ�TIME_ONESHOT������DRUMTIME�õ���ֻ����һ�εļ�ʱ���������������Լ�ʱ���������ٶȿ��������е�ִ�ж���̬�仯��timeSetEvent����֮�ᣬ��ʱ��װ��������ʽ�����ӳ�ʱ������������DrumTimerFunc��
DrumTimerFunccallback��DRUMTIME.C�еĺ�ʽ����DRUMTIME.C����������Ҫ�IJ���������iIndex����������Ŀǰ�����ӡ�Callback��ΪĿǰ�������������MIDI Note OffѶϢ��ʼ��iIndex�ij�ʼֵ-1�Է�ֹ��һ����������ʱ�������������
��������iIndex����������ֵ��ͬʹ���߶����һ��WM_USER_NOTIFYѶϢһ�𴫵ݸ�DRUM�е��Ӵ����š�wParamѶϢ�����趨ΪiIndex���Ա���DRUM.C�У�WndProc�ܹ��ƶ�����ײ��ġ�������С�򡹡�
DrumTimerFunc�������¼���Ϊ��������Note OnѶϢ���͸�ͨ��0��9�ĺϳ����ϣ�����������ֵ�Ա���һ�ο��Թر�������Ȼ��͸������timeSetEvent���趨�µ�ֻ����һ�εļ�ʱ���¼���
Ҫֹͣ���У�DRUM����DrumEndSequence������Ψһ�IJ��������趨ΪTRUE��FALSE�������TRUE����DrumEndSequence������ij��������������У�ɾ�����д����ļ�ʱ���¼�������timeEndPeriod��������MIDIͨ�����͡�all notes off��ѶϢ��Ȼ��ر�MIDI���������ʹ���߾�����ֹ��ʽʱ��DRUM��TRUE��������DrumEndSequence��
Ȼ������ʹ������DRUM��ġ�Sequence�����ܱ���ѡ��Stop��ʱ����ʽ����FALSE��Ϊ��������DrumEndSequence��������������ڽ���֮ǰ���Ŀǰ�Ļ�Ȧ��DrumEndSequence͸����bEndSequence��������趨ΪNULL����Ӧ�˺��С����bEndSequence��TRUE���������ӵ�����ֵ�趨Ϊ0����DrumTimerFunc��ʹ���߶����WM_USER_FINISHEDѶϢ���͸�WndProc��WndProc����ͨ����TRUE��Ϊ��������DrumEndSequence����Ӧ��ѶϢ���Ա���ȷ�ؽ�����ʱ����MIDI����ʹ�á�
RIFF����I/O
��
DRUM��ʽҲ���Դ���ͼ���������DRUM�ṹ����Ѷ�ĵ�������Щ������ʽ����RIFF��Resource Interchange File Format����Դ����������ʽ������һ�㽨��ʹ�õĶ�ý�嵵����̬����Ȼ���������ñ�׼����I/O��ʽ����дRIFF�������������ķ�����ʹ��������mmio���ԡ���ý������/��������ĺ�ʽ��
���.WAV��ʽʱ���Ƿ��֣�RIFF�DZ�ǵ�����ʽ������ζ�������е������ɲ�ͬ���ȵ����Ͽ���ɡ�ÿ�����Ͽ鶼��һ�������ʶ��һ����Ǿ���һ��4λԪ���ASCII�ִ�������32λԪ�����ı���������Ҫ����Щ����ǵ����������Ͽ鳤�ȼ������ϡ���Ϊ�����е���Ѷ����λ춵�����ͷ�̶���ƫ���������ñ�Ƕ��壬���Ա�ǵ�����ʽ��ͨ�õġ�����������͸�����Ӹ��ӱ������ǿ������ʽ���ڶ�����ʱ����ʽ���Ժ����׵��ҵ�����Ҫ�����ϲ���������Ҫ�Ļ��߲�����ı�ǡ�
Windows�е�RIFF�����ɶ��������Ͽ���ɡ�һ�����Ͽ���Է�Ϊ���Ͽ����͡����Ͽ��С�Լ����ϱ��������Ͽ�������4��Ԫ��ASCII���ǣ�����м䲻���пո񣬵�ĩβ�����С����Ͽ��С��һ��4λԪ�飨32λԪ����ֵ�������ʾ���Ͽ�Ĵ�С�����ϱ�������ռ��ż����λԪ�飬��Ҫʱ�����ڽ�β��0�����������Ͽ��ÿ�����ֶ��Ǵӵ�����ͷ�����������˵ġ����Ͽ��С���������Ͽ����ͺ����Ͽ��С����Ҫ��8λԪ�飬���Ҳ���ӳ���ӵ����ϡ�
���һЩ���Ͽ����ͣ����Ͽ��С���ض������޹أ�����ͬ�ġ������Ͽ��ǰ�����Ѷ�Ĺ̶����ȵĽṹʱ�����������������������£����Ͽ��С�����ض������仯��
������������̬�����Ͽ�ֱ��ΪRIFF���Ͽ��LIST���Ͽ顣���У�������һ��4��ԪASCII��ʽ��̬��ʼ��������һ�����������Ͽ顣LIST���Ͽ���RIFF���Ͽ����ƣ�ֻ��������4��Ԫ��ASCII�б���̬��ʼ��RIFF���Ͽ�������е�RIFF��������LIST���Ͽ�ֻ�ڵ����ڲ������ϲ���������Ͽ顣
һ��RIFF��������һ��RIFF���Ͽ顣��ˣ�RIFF�������ִ���RIFF����һ����ʾ�������ȼ�ȥ8λԪ���32λԪֵ��ʼ����ʵ���ϣ������Ҫ���������򵵰����᳤ܻһ��λԪ�顣��
��ý��API����16��������mmio�ĺ�ʽ����Щ��ʽ��ר��ΪRIFF������Ƶġ�DRUMFILE.C���Ѿ��õ����м�����ʽ����дDRUM���ϵ�����
Ҫ��mmio��ʽ�򿪵��������һ���Ǻ���mmioOpen����ʽ����һ���������š�mmioCreateChunk��ʽ�ڵ����н���һ�����Ͽ飬��ʹ��MMCKINFO��������Ͽ����ƺ����硣mmioWrite��ʽд�����Ͽ顣д�����Ͽ����ᣬ����mmioAscend�����ݸ�mmioAscend��MMCKINFO�ṹ������ǰ��ͨ�����ݸ�mmioCreateChunk���������Ͽ��MMCKINFO�ṹ��ͬ��ͨ����Ŀǰ����ָ���м�ȥ�ṹ��dwDataOffset��λ��ִ��mmioAscend��ʽ���˵���ָ������λ����Ͽ�Ľ�β�����Ҵ�ֵ���������ϵ�ǰ�档������Ͽ��ڳ����ϲ���2λԪ��ı�������mmioAscend��ʽҲ����ϡ�
RIFF�����ɳ�״��֯�����Ͽ��׵���ɡ�ΪʹmmioAscend��������������ά�����MMCKINFO�ṹ��ÿ���ṹ�뵵���е�һ����������ϵ��DRUM���ϵ���������������ˣ���DRUMFILE.C�е�DrumFileWrite��ʽ�У���Ϊ����MMCKINFO�ṹ������һ�����У����Էֱ���Ϊmmckinfo[0]��mmckinfo[1]��mmckinfo[2]���ڵ�һ��mmioCreateChunk�����У�mmckinfo[0]�ṹ��DRUM��ʽ��̬һ����춽���RIFF��̬�Ŀ顣�����ǵڶ���mmioCreateChunk���У�����mmckinfo[1]��INFO�б���̬һ����LIST��̬�����Ͽ顣
������mmioCreateChunk������mmckinfo[2]����һ��ISFT��̬�����Ͽ飬�����Ͽ����ʶ�������ϵ��������塣�����mmioWrite�������д�ִ�szSoftware������mmioAscent����mmckinfo[2]���������Ͽ�����Ͽ��С��λ�����ǵ�һ�����������Ͽ顣��һ�����Ͽ�Ҳ��LIST���Ͽ��ڡ���ʽ��������һ��mmioCreateChunk�����н���ISCD��creation data���������ϣ����Ͽ飬���ٴ�ʹ��mmckinfo[2]����mmioWrite������д�����Ͽ����ᣬʹ��mmckinfo[2]����mmioAscend��������Ͽ��С������д���˴����Ͽ�Ľ�β��Ҳ��LIST��Ľ�β�����ԣ�Ҫ���LIST���Ͽ�����Ͽ��С��λ�����ٴκ���mmioAscend�����ʹ��mmckinfo[1]���������춽���LIST���Ͽ顣
Ҫ������fmt���͡�data�����Ͽ飬mmioCreateChunkʹ��mmckinfo[1]��mmioWrite���е�����Ҳʹ��mmckinfo[1]��mmioAscend������һ���ϣ�����RIFF���Ͽ鱾�����⣬���е����Ͽ��С������ˡ�����Ҫ���ʹ��mmckinfo[0]������mmioAscend����Ȼ�ж�κ��У���ֻ����mmioCloseһ�Ρ�
����������mmioAscend���иı���Ŀǰ�ĵ���ָ�꣬��������ȷ��������Ͽ��С�����ں�ʽ����ʱ�������Ͽ������������򲹳����϶�����1λԪ�飩���ᣬ����ָ��ָ�����ǰ��λ�á���Ӧ�õĹ۵����������еĵ���д�붼�ǰ���ͷ��β��˳��
mmioOpen���гɹ��ᣬ���˴ŵ��ռ�ľ�֮�⣬���ᷢ����������ʹ�ñ���wError��mmioCreateChunk��mmioWrite��mmioAscend��mmioClose�����ۼƴ�����룬����ŵ��ռ䲻����ÿ�����ж���ʧ�ܡ���������˴�����mmioOpen��MMIO_DELETE����Ϊ������ɾ�������������ش�����Ѷ��
��RIFF�����뽨��RIFF�������ƣ�ֻ�����Ǻ���mmioRead������mmioWrite������mmioDescend������mmioCreateChunk�����½�����descend����һ�����Ͽ飬��ָ�ҵ����Ͽ�λ�ã����ѵ���ָ���ƶ������Ͽ��С֮�ᣨ������RIFF��LIST���Ͽ����͵���ʽ��̬�����б���̬�����棩�������Ͽ顸������ָ���ǰѵ���ָ���ƶ������Ͽ�Ľ�β��mmioDescend��mmioAscend��ʽ�����ܰѵ���ָ���Ƶ�������ǰһ��λ�á�
DRUM��ǰ�İ汾��1992��ġ�PC Magazine����������ʱ��Windows֧Ԯ������ͬ�ȼ���MIDI�ϳ�������Ϊ�������ġ��͡���չ�ġ������Ǹ���ʽд�ĵ����и�ʽʶ����1�����µ�DRUM��ʽ����ʽʶ�����趨Ϊ2�������������Զ�ȡ��ת�����ڵĸ�ʽ������DrumFileRead��ʽ����ɡ�