�������� Linux Tags

22. ����������

��Microsoft Windows�У���������������Ѷ���ۺ�������һ����Ҫ�Ľ������Զ�ý���֧Ԯ��Դ�1991����ν��Microsoft Windows��ý�����칦�ܣ�Multimedia Extensions to Microsoft Windows����1992�꣬Windows 3.1�ķ���ʹ�öԶ�ý���֧Ԯ��Ϊ��һ��API��������꣬CD-ROM����������Ч������90������ڻ����ټ����ѳ�Ϊ��PC�ı�׼�䱸�����ڣ��������е����Ƕ����ţ���ý���ںܴ�̶��������Windows���Ӿ���ͼ�Σ��Ӷ�ʹ���԰�������ֻ�Ǵ������ֺ����ֵĻ����Ĵ�ͳ��ɫ��

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������˵��һ��ʵ�����⣭��Щ����������װ���޹صģ���Ϊ���ǵ������ڲ�ͬ�ĺϳ������������Dz�һ���ġ�Ȼ������������꣬��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��ʽ����ɡ�