Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 128 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
128
Dung lượng
417,42 KB
Nội dung
as recording voice rather than music. Halving the sampling rate to 22.05 kHz reduces the upper range of reproducible sound by one octave to 10 kHz. Halving it again to 11.025 kHz gives us a frequency range to 5 kHz. Sampling rates of 44.1 kHz, 22.05 kHz, and 11.025 kHz, as well as 8 kHz, are the standards commonly supported by waveform audio devices. You might think that a sampling rate of 11.025 kHz is adequate for recording a piano because the highest frequency of a piano is 4186 Hz. However, 4186 Hz is the highest fundamental of a piano. Cutting off all sine waves above 5000 Hz reduces the overtones that can be reproduced and will not accurately capture and reproduce the piano sound. The Sample Size The second parameter in pulse code modulation is the sample size measured in bits. The sample size determines the difference between the softest sound and loudest sound that can be recorded and played back. This is known as the dynamic range. Sound intensity is the square of the waveform amplitude (that is, the composite of the maximum amplitudes that each sine wave reaches over the course of one cycle). As is the case with frequency, human perception of sound intensity is logarithmic. The difference in intensity between two sounds is measured in bels (named after Alexander Graham Bell, the inventor of the telephone) and decibels (dB). A bel is a tenfold increase in sound intensity. One dB is one tenth of a bel in equal multiplicative steps. Hence, one dB is an increase in sound intensity of 1.26 (that is, the 10th root of 10), or an increase in waveform amplitude of 1.12 (the 20th root of 10). A decibel is about the lowest increase in sound intensity that the ear can perceive. The difference in intensity between sounds at the threshold of hearing and sounds at the threshold of pain is about 100 dB. You can calculate the dynamic range in decibels between two sounds with the following formula: where A1 and A2 are the amplitudes of the two sounds. With a sample size of 1 bit, the dynamic range is zero, because only one amplitude is possible. With a sample size of 8 bits, the ratio of the largest amplitude to the smallest amplitude is 256. Thus, the dynamic range is or 48 decibels. A 48-dB dynamic range is about the difference between a quiet room and a power lawn mower. Doubling the sample size to 16 bits yields a dynamic range of or 96 decibels. This is very nearly the difference between the threshold of hearing and the threshold of pain and is considered just about ideal for the reproduction of music. Both 8-bit and 16-bit sample sizes are supported under Windows. When storing 8-bit samples, the samples are treated as unsigned bytes. Silence would be stored as a string of 0x80 values. The 16-bit samples are treated as signed integers, so silence would be stored as a string of zeros. To calculate the storage space required for uncompressed audio, multiply the duration of the sound in seconds by the This document is created with the unregistered version of CHM2PDF Pilot Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com sampling rate. Double that if you're using 16-bit samples rather than 8-bit samples. Double that again if you're recording in stereo. For example, an hour of CD-quality sound (or 3600 seconds at 44,100 samples per second with 2 bytes per sample in stereo) requires 635 megabytes, not coincidentally very close to the storage capability of CD ROM. Generating Sine Waves in Software For our first exercise in waveform audio, we're not going to save sounds to files or play back recorded sounds. We're going to use the low-level waveform audio APIs (that is, the functions beginning with the prefix waveOut) to create an audio sine wave generator called SINEWAVE. This program generates sine waves from 20 Hz (the bottom of human perception) to 5,000 Hz (two octaves short of the top of human perception) in 1 Hz increments. As you know, the standard C run-time library includes a function called sin that returns the sine of an angle given in radians. (Two (2 times pi) radians equals 360 degrees.) The sin function returns a value ranging from 1 to 1. (We used this function in another program called SINEWAVE way back in Chapter 5.) Thus, it should be easy to use the sin function to generate sine wave data to output to the waveform audio hardware. Basically, you fill a buffer up with data representing the waveform (in this case, a sine wave) and pass it to the API. (It's a little more complicated than that, but I'll get to the details shortly.) When the waveform audio hardware finishes playing the buffer, you pass it a second buffer, and so forth. When first considering this problem (and not knowing anything about PCM), you might think it reasonable to divide one cycle of the sine wave into a fixed number of samples for example, 360. For a 20-Hz sine wave, you output 7200 samples every second. For a 200-Hz sine wave, you output 72,000 samples per second. That might work, but it's not the way to do it. For a 5000-Hz sine wave, you'd need to output 1,800,000 samples per second, which would surely tax the DAC! Moreover, for the higher frequencies, this is much more precision than is needed. With pulse code modulation, the sample rate is a constant. Let's assume the sample rate is 11,025 Hz because that's what I use in the SINEWAVE program. If you wish to generate a sine wave of 2,756.25 Hz (exactly one-quarter the sample rate), each cycle of the sine wave is just 4 samples. For a sine wave of 25 Hz, each cycle requires 441 samples. In general, the number of samples per cycle is the sample rate divided by the desired sine wave frequency. Once you know the number of samples per cycle, you can divide 2 (2 times pi) radians by that number and use the sin function to get the samples for one cycle. Then just repeat the samples for one cycle over and over again to create a continuous waveform. The problem is the number of samples per cycle may well be fractional, so this approach won't work well either. You'd get a discontinuity at the end of each cycle. The key to making this work correctly is to maintain a static "phase angle" variable. This angle is initialized at 0. The first sample is the sine of 0 degrees. The phase angle is then incremented by 2 (2 times pi) times the frequency, divided by the sample rate. Use this phase angle for the second sample, and continue in this way. Whenever the phase angle gets above 2 (2 times pi) radians, subtract 2 (2 times pi) radians from it. But don't ever reinitialize it to 0. For example, suppose you want to generate a sine wave of 1000 Hz with a sample rate of 11,025 Hz. That's about 11 samples per cycle. The phase angles and here I'll give them in degrees to make this a little more comprehensible for approximately the first cycle and a half are 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, and so forth. The waveform data you put in the buffer are the sines of these angles, scaled to the number of bits per sample. When creating the data for a subsequent buffer, you keep incrementing the last phase angle value without reinitializing it to zero. A function called FillBuffer that does this along with the rest of the SINEWAVE program is shown in Figure 22-2. Figure 22-2. The SINEWAVE program. This document is created with the unregistered version of CHM2PDF Pilot Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 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 ; This document is created with the unregistered version of CHM2PDF Pilot Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 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 ; } Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com // 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 ; Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com // 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 ; } Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com SINEWAVE.RC (excerpts) //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 (excerpts) // 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 Note that the OUT_BUFFER_SIZE, SAMPLE_RATE, and PI identifiers used in the FillBuffer routine are defined at the top of the program. The iFreq argument to FillBuffer is the desired frequency in Hz. Notice that the result of the sin function is scaled to range between 0 and 254. For each sample, the fAngle argument to the sin function is increased by 2 (2 times pi) radians times the desired frequency divided by the sample rate. SINEWAVE's window contains three controls: a horizontal scroll bar used for selecting the frequency, a static text field that indicates the currently selected frequency, and a push button labeled "Turn On." When you press the button, you should hear a sine wave from the speakers connected to your sound board and the button text will change to "Turn Off." You can change the frequency by moving the scroll bar with the keyboard or mouse. To turn off the sound, push the button again. The SINEWAVE code initializes the scroll bar so that the minimum frequency is 20 Hz and the maximum frequency is 5000 Hz during the WM_INITDIALOG message. Initially, the scroll bar is set to 440 Hz. In musical terms, this is the A above middle C, the note used for tuning an orchestra. DlgProc alters the static variable iFreq on receipt of WM_HSCROLL messages. Notice that Page Left and Page Right cause DlgProc to decrease or increase the frequency by one octave. This document is created with the unregistered version of CHM2PDF Pilot Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com When DlgProc receives a WM_COMMAND message from the button, it first allocates 4 blocks of memory 2 for WAVEHDR structures, discussed shortly, and two for buffers, called pBuffer1 and pBuffer2, to hold the waveform data. SINEWAVE opens the waveform audio device for output by calling the waveOutOpen function, which uses the following arguments: waveOutOpen (&hWaveOut, wDeviceID, &waveformat, dwCallBack, dwCallBackData, dwFlags) ; You set the first argument to point to a variable of type HWAVEOUT ("handle to waveform audio output"). On return from the function, this variable will be set to a handle used in subsequent waveform output calls. The second argument to waveOutOpen is a device ID. This allows the function to be used on machines that have multiple sound boards installed. The argument can range from 0 to one less than the number of waveform output devices installed in the system. You can get the number of waveform output devices by calling waveOutGetNumDevs and find out about each of them by calling waveOutGetDevCaps. If you wish to avoid this device interrogation, you can use the constant WAVE_MAPPER (defined as equalling 1) to select the device the user as indicated as the Preferred Device in the Audio tab of the Multimedia applet of the Control Panel. Or the system could select another device if the preferred device can't handle what you need to do and another device can. The third argument is a pointer to a WAVEFORMATEX structure. (More about this shortly.) The fourth argument is either a window handle or a pointer to a callback function in a dynamic-link library. This argument indicates the window or callback function that receives the waveform output messages. If you use a callback function, you can specify program-defined data in the fifth argument. The dwFlags argument can be set to either CALLBACK_WINDOW or CALLBACK_FUNCTION to indicate what the fourth argument is. You can also use the flag WAVE_FORMAT_QUERY to check whether the device can be opened without actually opening it. A few other flags are available. The third argument to waveOutOpen is defined as a pointer to a structure of type WAVEFORMATEX, defined in MMSYSTEM.H as shown below: 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 ; This is the structure you use to specify the sample rate (nSamplesPerSec), the sample size (wBitsPerSample), and whether you want monophonic or stereophonic sound (nChannels). Some of the information in this structure may seem redundant, but the structure is designed for sampling methods other than PCM, in which case the last field is set to a nonzero value and other information follows. For PCM, set nBlockAlign field to the product of nChannels and wBitsPerSample, divided by 8. This is the total number of bytes per sample. Set the nAvgBytesPerSec field to the product of nSamplesPerSec and nBlockAlign. SINEWAVE initializes the fields of the WAVEFORMATEX structure and calls waveOutOpen like this: This document is created with the unregistered version of CHM2PDF Pilot Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com waveOutOpen (&hWaveOut, WAVE_MAPPER, &waveformat, (DWORD) hwnd, 0, CALLBACK_WINDOW) The waveOutOpen function returns MMSYSERR_NOERROR(defined as 0) if the function is successful and a nonzero error code otherwise. If waveOutOpen returns nonzero, SINEWAVE cleans up and displays a message box indicating an error. Now that the device is open, SINEWAVE continues by initializing the fields of the two WAVEHDR structures, which are used to pass buffers through the API. WAVEHDR is defined like so: 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 sets the lpData field to the address at the buffer that will contain the data, dwBufferLength to the size of this buffer, and dwLoops to 1. All other fields can be set to 0 or NULL. If you want to play a repeated loop of sound, you can specify that with the dwFlags and dwLoops fields. Next SINEWAVE calls waveOutPrepareHeader for the two headers. Calling this function prevents the structure and buffer from being swapped to disk. So far, all of this preparation has been in response to the button click to turn on the sound. But a message is waiting in the program's message queue. Because we specified in waveOutOpen that we wish to use a window procedure for receiving waveform output messages, the waveOutOpen function posted a MM_WOM_OPEN message to the program's message queue. The wParam message parameter is set to the waveform output handle. To process the MM_WOM_OPEN message, SINEWAVE twice calls FillBuffer to fill the pBuffer buffer with sinewave data. SINEWAVE then passes the two WAVEHDR structures to waveOutWrite. This is the function that actually starts the sound playing by passing the data to the waveform output hardware. When the waveform hardware is finished playing the data passed to it in the waveOutWrite function, the window is posted an MM_WOM_DONE message. The wParam parameter is the waveform output handle, and lParam is a pointer to the WAVEHDR structure. SINEWAVE processes this message by calculating new values for the buffer and resubmitting the buffer by calling waveOutWrite. SINEWAVE could have been written using just one WAVEHDR structure and one buffer. However, there would be a slight delay between the time the waveform hardware finished playing the data and the program processed the MM_WOM_DONE message to submit a new buffer. The "double-buffering" technique that SINEWAVE uses prevents gaps in the sound. When the user clicks the "Turn Off" button to turn off the sound, DlgProc receives another WM_COMMAND message. For this message, DlgProc sets the bShutOff variable to TRUE and calls waveOutReset. The waveOutReset function stops sound processing and generates a MM_WOM_DONE message. When bShutOff is TRUE, SINEWAVE processes MM_WOM_DONE by calling waveOutClose. This in turn generates an This document is created with the unregistered version of CHM2PDF Pilot Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com MM_WOM_CLOSE message. Processing of MM_WOM_CLOSE mostly involves cleaning up. SINEWAVE calls waveOutUnprepareHeader for the two WAVEHDR structures, frees all the memory blocks, and sets the text of the button back to "Turn On." If the waveform hardware is still playing a buffer, calling waveOutClose by itself will have no effect. You must call waveOutReset first to halt the playing and to generate an MM_WOM_DONE message. DlgProc also processes the WM_SYSCOMMAND message when wParam is SC_CLOSE. This results from the user selecting "Close" from the system menu. If waveform audio is still playing, DlgProc calls waveOutReset. Regardless, EndDialog is eventually called to close the dialog box and end the program. A Digital Sound Recorder Windows includes a program called Sound Recorder that lets you digitally record and playback sounds. The program shown in Figure 22-3 (RECORD1) is not quite as sophisticated as Sound Recorder because it doesn't do any file I/O or allow sound editing. However, it does show the basics of using the low-level waveform audio API for both recording and playing back sounds. Figure 22-3. The RECORD1 program. This document is created with the unregistered version of CHM2PDF Pilot Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... PUSHBUTTON "Speedup",IDC_PLAY_SPEED ,104 ,52,40,14,WS_DISABLED END RESOURCE.H (excerpts) // Microsoft Developer Studio generated include file // Used by Record.rc #define #define #define #define #define #define #define #define IDC_RECORD_BEG IDC_RECORD_END IDC_PLAY_BEG IDC_PLAY_PAUSE IDC_PLAY_END IDC_PLAY_REV IDC_PLAY_REP IDC_PLAY_SPEED 100 0 100 1 100 2 100 3 100 4 100 5 100 6 100 7 The RECORD.RC and RESOURCE.H... 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... for output waveform.wFormatTag waveform.nChannels waveform.nSamplesPerSec waveform.nAvgBytesPerSec waveform.nBlockAlign waveform.wBitsPerSample waveform.cbSize = = = = = = = WAVE_FORMAT_PCM ; 1 ; 1102 5 ; 1102 5 ; 1 ; 8 ; 0 ; if (waveOutOpen (&hWaveOut, WAVE_MAPPER, &waveform, (DWORD) hwnd, 0, CALLBACK_WINDOW)) { MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION... */ #include #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,... for input waveform.wFormatTag waveform.nChannels waveform.nSamplesPerSec waveform.nAvgBytesPerSec waveform.nBlockAlign waveform.wBitsPerSample waveform.cbSize = = = = = = = WAVE_FORMAT_PCM ; 1 ; 1102 5 ; 1102 5 ; 1 ; 8 ; 0 ; if (waveInOpen (&hWaveIn, WAVE_MAPPER, &waveform, (DWORD) hwnd, 0, CALLBACK_WINDOW)) { free (pBuffer1) ; free (pBuffer2) ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szOpenError,... than 1102 5 The MCI Alternative You may find, as I do, that RECORD1 seems inordinately complex It is particularly tricky to deal with the interaction between the waveform audio function calls and the messages they generate, and then in the midst of all this, to deal with possible memory shortages as well But maybe that's why it's called the "low-level" interface As I noted earlier in this chapter, Windows. .. */ #include #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,... */ #include #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,... that includes a WAVEFORMAT structure The nChannels field is either 1 or 2, for monaural or stereo sound The nSamplesPerSec field is the number of samples per second; the standard values are 1102 5, 22050, and 4 4100 samples per second The nAvgBytesPerSec field is the sample rate in samples per second times the number of channels times the size of each sample in bits, divided by 8 and rounded up The standard... 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 [102 4] ; mciGetErrorString (dwError, szErrorStr, sizeof (szErrorStr) / sizeof (TCHAR)) ; MessageBeep (MB_ICONEXCLAMATION) ; MessageBox (hwnd, szErrorStr, szAppName, MB_OK | MB_ICONEXCLAMATION) ; } BOOL . IDC_RECORD_END 100 1 #define IDC_PLAY_BEG 100 2 #define IDC_PLAY_PAUSE 100 3 #define IDC_PLAY_END 100 4 #define IDC_PLAY_REV 100 5 #define IDC_PLAY_REP 100 6 #define IDC_PLAY_SPEED 100 7 The RECORD.RC and RESOURCE.H. SINEWAVE.C Multimedia Windows Sine Wave Generator (c) Charles Petzold, 1998 */ #include < ;windows. h> #include <math.h> #include "resource.h" #define SAMPLE_RATE 1102 5 #define FREQ_MIN. include file. // Used by SineWave.rc #define IDC_STATIC -1 #define IDC_SCROLL 100 0 #define IDC_TEXT 100 1 #define IDC_ONOFF 100 2 Note that the OUT_BUFFER_SIZE, SAMPLE_RATE, and PI identifiers used