DirectSound

xiaoxiao2021-03-06  85

DirectSound documentation when reading college, collect it :)

(Fethual) About DirectSound

DirectSound is one of the DirectX APIs, which offers fast mixing, hardware acceleration feature, and can directly access relevant devices, of course, the most important thing is its functionality and existing (? Future) What?) The device driver maintains compatibility. DirectSound allows capture and revenue of wave versus sound, or more services can be obtained by controlling hardware and corresponding drivers. DirectSound is as best as DirectX's other components, it allows you to use hardware with your maximum efficiency, and have good compatibility (which is not something else to say, you have enough: p). What can I do with DirectSound? 1. It is convenient to understand hardware capabilities, and configure hardware based on the current computer hardware to determine the best solution. 2, make up for the shortcomings of the driver - setting with the attribute setting so that the hardware capabilities can be fully played, even if the driver is not well supported. 3. Mix for short transmission delay time for fast response flow. 4, 3-D Sound 5, the capture of the sound

DirectSound core DirectSound device

This section describes how to enumerate the sound device that can be used, creates a DirectSound object for a device, using the object's method to set the ability to verify the ability, create sound buffers, configure system speakers, and compressed data. In the case where the sound equipment that enumerates can be used, it may not need to enumerate the sound device that can be used. Use the default device not to bring any trouble (believe in the user - God: P), but if you want The program is more "facing object", giving users more better options (many 3D games can make users choose the graphics card, the truth is small), then you need to use the enumerated sound device. . Enumerates the available sound device first want to write a function, call each time you find a available sound device, you can do anything in that function, and it can have any legal name, but You must declare it as DsenumCallback, the callback function must return a BOOL, True Continue list, FALSE exits the enumeration process. And the enumeration of the display device is similar, and below is a few pieces of code contained from DSENUM.C. Since I think there is not much to use it, I have not studied it (in fact, it is very simple: P), so it will not be annoyed, and there is more exciting thing behind! Code as follows: // callback function BOOL CALLBACK DSEnumProc (LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext) {HWND hCombo = * (HWND *) lpContext; LPGUID lpTemp = NULL; if (lpGUID = NULL!) {If (( lpTemp = malloc (sizeof (GUID))) == NULL) return (TRUE); memcpy (lpTemp, lpGUID, sizeof (GUID));} ComboBox_AddString (hCombo, lpszDesc); ComboBox_SetItemData (hCombo, ComboBox_FindString (hCombo, 0, lpszDesc ), lpTemp); // Editor Note: This sentence is incorrectly return (true);} Creating the DirectSound object The easiest way to create the DirectSound object is to call the DirectSoundCreate function. LPDIRECTSOUNDS; HRESULT HR = DirectSoundCreate (NULL, & LPDS, NULL)); The first parameter of this function is the hardware device. NULL represents the use of the default device, the second parameter is the address of the remote pointer LPDirectSound, that is, the created DirectSound The address of the object is placed, the third parameter must be NULL, which is not used for the time being.

When there is no corresponding device or device in the control of other programs, the function returns an error. At this time, if your program continues to work, all the operations related to the DirectSound object will not be available! Setting a collaboration because Windows is a multi-task environment, you can allow multiple applications to work simultaneously, of course, multiple programs are generated in the same way using the same device in the same, through the collaboration level, DirectX can guarantee all the programs in use There is no conflict when the device (everyone is not a pleasure), so each of each of the procedures using DirectSound should have a partner level to determine the device to be accessed. DirectSound has four collaboration levels: standard-level, priority, exclusive and write main bursts (Write-primary, write is the main action), where the game generally uses priority this level to make the program under the same sampling conditions The most flexible output (MS's document is also very literary!). The example of // c will be changed to C ? Will n't say no! HRESULT HR = LPDIRECTSOOPERATIVELEVEL (LPDIRECTSOUND, HWND, DSSCL_PRIORITY); standard grade (DSSCL_NORMAL): This level can only use 22kHz, stereo (Stereo), 8-bit music, and cannot directly write main buffer, also Can't use a compressed sound. Priority (DSSCL_Paiority): Hardware Mixing can be implemented, you can set up the sound format of the main buffer (you can use different quality music as needed) and compressed music. Orddle (DSSCL_EXCLUSIVE): Other programs cannot be used when the application works at the front desk. Write a main buffer level (DSSCL_WRITEPRIMARY): The highest level of collaboration, the program can manipulate the main buffer, and the program must write the main buffer (the most basic layer of operation). At this level, the second buffer will not be available. In addition to this level, all the operations that try the Lock main buffer will fail, that is, only this level can write to the main buffer! When using the writer buffer level, the second buffer of all programs in the background will stop and lose, and if the program that uses the write main buffer level to work to the background, its main buffer will also be lost and It should be restored again when it goes to the front desk. More information will be elaborated in buffer management (now there is still not translated: p But after using DDRAW, these things should be familiar with it). If you want to set a write back-level, you should first determine if you can use this level - use the iDirectSound :: getCaps function, check if there is a DSCAPS_EMULDRIVER flag in the DSCAPS structure. Search hardware information DirectSound allows the application to retrieve hardware information, of course, in general, this is unnecessary, because DirectSound can automatically use hardware acceleration, we can completely do not have to take hardware to have certain capabilities, but Improve the efficiency of the program, which is still useful.

Hardware information retrieval method using IDirectSound :: GetCaps, for example: DSCAPS dscaps; dscaps.dwSize = sizeof (DSCAPS); HRESULT hr = lpDirectSound-> lpVtbl-> GetCaps (lpDirectSound, & dscaps); provided DirectSound speaker speaker setup can be used Adjust the size of the output volume and optimize 3D effect. In WIN98 and WIN2000, can be obtained by IDirectSound :: GetSpeakerConfig the current setting of the speaker, and to change the speaker setup by IDirectSound :: SetSpeakerConfig; and in the WIN95 in IDirectSound :: GetSpeakerConfig simply return a value or return to using the default IDirectSound: : SetspeakerConfig Set the value. Compressed applications can get the most available memory through iDirectSound :: Compact, of course, from the previous discussion, we can find that the premise of using compression is that the program's partnership should be at least priority. DirectSound buffer foundation (but also a fee)

When initializing DirectSound, it automatically creates a main buffer for your program, the role of this main buffer is mixed and sent to the output device. In addition to the main buffer, the program should also create a secondary buffer, the role of the auxiliary buffer is to save the sound to be used, which can be released when not in use, but this is implied that our main buffer is irreremented) . You can create two or more auxiliary buffers on the same physical memory (using the iDirectSound :: DuplicatesoundBuffer method), but if the hardware memory resources where the original buffer (original) does not support multi-buffered, then this call will fail end. DirectSound can also play multiple sounds at the same time, of course, their big prerequisites are hardware allows. DirectSound playing only a short time delay, if you play the movie while playing the sound, you will feel the delay, but if DirectSound needs to complete this action through software simulation, then the delay time will extend 5-8 Multiplier. Normally, you don't need to deal with the main buffer. DirectSound will manage it yourself, unless you want to use your own mixed mixed part, DirectSound will make you manage the main buffer, more detailed explanation The main buffer access section. Static buffer and stream buffer in the application, the auxiliary buffer can have two - static buffers (a complete sound of a memory space; the advantage is that all sounds can be stored in a buffer) and stream buffer (not all Data read into buffer, but in playing the sound, it is dynamically read; its advantage is that the space is small, which can adapt to different program requirements, respectively. Generally, if the sound is needed to play again, and the capacity is limited (better than the game sound effect), then the use of static buffers more helpful to improve the efficiency of the program. Conversely, if it is a very lengthy music, or use a stream buffer .

// create a secondary buffer to create a secondary buffer examples BOOL AppCreateBasicBuffer (LPDIRECTSOUND lpDirectSound, LPDIRECTSOUNDBUFFER * lplpDsb) {PCMWAVEFORMAT pcmwf; DSBUFFERDESC dsbdesc; HRESULT hr; // set PCMWAVEFORMAT structure memset (& pcmwf, 0, sizeof (PCMWAVEFORMAT)); pcmwf.wf .wFormatTag = WAVE_FORMAT_PCM; pcmwf.wf.nChannels = 2; pcmwf.wf.nSamplesPerSec = 22050; pcmwf.wf.nBlockAlign = 4; pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign; pcmwf.wBitsPerSample = 16; // Set the DSBufferDesc structure MEMSET (& DSBDESC, 0, SIZEOF (DSBufferDesc)); // Set the structure 0. DSBDesc.dwsize = sizeof (dsbufferDesc); // Using the default settings (Volumes) DSBDesc.dwflags = DSBCAPS_CTRLDEFAULT; // buffer (3-second buffer) dsbdesc.dwBufferBytes = 3 * pcmwf.wf.nAvgBytesPerSec 3 seconds length; dsbdesc.lpwfxFormat = (LPWAVEFORMATEX) & pcmwf; // Create a buffer hr = lpDirectSound-> lpVtbl-> CreatesoundBuffer (LPDIRECTSOUND, & DSBDESC, LPLPDSB, NULL); if succeeded (hr) {// Success Return True;} else {// failed * LPL PDSB = NULL; RETURN FALSE;}} is very simple, just fill two structs. Because DirectSound is all created, you should create important buffers first. If you declare a hardware buffer (similar to the surface in the memory), you should set the DSBCAPS_LOCHARDWARE flag in the DSBufferDesc structure, but if you don't have enough hardware resources (hardware memory or mixed capacity Hardware Memory OR) Mixing Capacity will not be able to create buffers. When creating a buffer, you can also declare a static buffer (setting the DSBCAPS_STATIC flag) or the stream buffer; the default value is the stream buffer (the default value used above). The buffer is associated with the DirectSound object. If the DirectSound object is released, all of its buffers will be released. Buffer Control Options You have created a helper buffer, and the control options that need to be used by the buffer should be declared. This work requires your DSBufferDesc structure to set the flag headed by DSBCAPS_CTRL (these flags can be used separately, or several).

Available control has 3-D attribute, frequency, PAN (difference value of the left and right forwardline), volume, position notification (may refer to progress when playback). In order to get a good effect on all sound cards, it is best to set only the required control options. If a sound card supports hardware buffering but does not support chassis control (PAN Control), Diractsound will only use hardware acceleration when the DSBCAPS_CTRLPAN flag is not declared. This means that DirectSound determines how to assign hardware resources to buffering by control options. If you use a buffer unsupported control, such as a buffer call IDirectSoundBuffer :: setVolume method that does not declares the DSBCAPS_CTRLVOLUME flag, it is impossible to succeed. The main buffer access If you are not satisfied with the work of DirectSound, you can directly manipulate the master sound buffer, or it can be said to be a direct manipulation hardware, but this will mean that the part of the DirectSound is not available, including auxiliary buffer mixing and Hardware acceleration is accelerated. The main buffer is actually hardware buffer, and its size is determined by hardware, and this value is usually very small, so you should use the data stream to access the buffer. And if the hardware does not provide a main buffer, you can't access it directly (it is a main buffer to access the DX software simulation); you should call the iDirectSoundBuffer :: getCaps method to check if there is a DSBCAPS_LOCHARDWARE flag in the DSBCAPS_lochardware flag, can set it The DSSCL_WRITEPRIMARY level is level to access the main buffer.

BOOL AppCreateWritePrimaryBuffer during initialization // write the main buffer (LPDIRECTSOUND lpDirectSound, LPDIRECTSOUNDBUFFER * lplpDsb, LPDWORD lpdwBufferSize, HWND hwnd) {DSBUFFERDESC dsbdesc; DSBCAPS dsbcaps; HRESULT hr; WAVEFORMATEX wf; // initialize WAVEFORMATEX structure memset (& wf, 0, sizeof (WAVEFORMATEX)); wf.wFormatTag = WAVE_FORMAT_PCM; wf.nChannels = 2; wf.nSamplesPerSec = 22050; wf.nBlockAlign = 4; wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign; wf.wBitsPerSample = 16; // initialize DSBUFFERDESC structure memset (& dsbdesc, 0, sizeof (DSBUFFERDESC)); dsbdesc.dwSize = sizeof (DSBUFFERDESC); dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbdesc.dwBufferBytes // buffer size is determined by the hardware = 0; dsbdesc.lpwfxFormat = NULL ; // this field must be set to NULL // set the cooperation level hr = lpDirectSound-> lpVtbl-> SetCooperativeLevel (lpDirectSound, hwnd, DSSCL_WRITEPRIMARY); if SUCCEEDED (hr) {// create a buffer hr = lpDirectSound-> lpVtbl-> CreateSoundBuffer ( LPDIRECTSOUND, & DSBDESC, LPLPDSB, NULL; if succeeded (HR) {// Set the format hr = (* lplpdsb) required for the main buffer -> lpvtbl-> setformat (* lplpdsb, & wf); if successded (hr) {// Get the size of the main buffer DSBCaps.dwsize = SizeOf (DSBCAPS); (* lplpDsb) -> lpVtbl-> GetCaps (* lplpDsb, & dsbcaps); * lpdwBufferSize = dsbcaps.dwBufferBytes; return TRUE;}}} // if it fails * lplpDsb = NULL; * lpdwBufferSize = 0; return FALSE;} play sounds Play sound To lock a partial buffer of the part of the buffer you need by locking the sound. 2, write data to the buffer. 3, unlock. 4. Play the sound using the iDirectSoundBuffer :: Play method. If you are using the stream buffer, you will also need to perform repeated execution 1-3 steps.

Because stream buffering is usually looped (like loop queue), DirectSound will return 2 pointers when you lock buffer. For example, you start locking 3,000 bytes long data from a buffer midpoint of only 4,000 bytes, then the first pointer returned by DirectSound is the 2,000 byte starting from the midpoint, while the second pointer It is the 1,000 byte of the buffer. Of course, if this happens, the second pointer is NULL. If you set the dsbplay_looping flag, then music will continue to play unless you use iDirectSoundBuffer :: Stop to stop it. The part of the stream buffer will also discuss in detail in the subsequent chapter. Below is an example of a C language: // Write auxiliary buffer BOOL AppWriteDataTobuffer (LPDIRECTSOUFFER LPDSB, / / ​​Buffer DWORD DWOFFSET, // To write data buffer allocation address lpbyte lpbsounddata, // To write data DWSOUNDBYTES / / One write block size {LPVOID LPVPTR1; DWORD DWBYTES1; LPVOID LPVPTR2; DWORD DWBYTES2; HRESULT HR; // Get the address of the block to be written HR = LPDSB-> LPVTBL-> LOCK (LPDSB, DWOFFSET, DWSOUNDBYTES, & LPVPTR1 , & dwbytes1, & lpvptr2, & dwbytes2, 0); // If you return DSERR_BUFFERLOST, restore and reslock if (DSERR_BUFFERLOST == HR) {lpdsb-> lpvtbl-> restore (lpdsb); hr = lpdsb-> lpvtbl-> lock (LPDSB , dwOffset, dwSoundBytes, & lpvPtr1, & dwAudio1, & lpvPtr2, & dwAudio2, 0);} if SUCCEEDED (hr) {// copy data CopyMemory (lpvPtr1, lpbSoundData, dwBytes1);! if (NULL = lpvPtr2) {CopyMemory (lpvPtr2, lpbSoundData DWBYTES1, DWBYTES2);} // Unlock HR = LPDSB-> LPVTBL-> UNLOCK (LPDSB, LPVPTR1, DWBYTES1, LPVPTR2, DWBYTES2); if succeeded (hr) {// Success Return True; }} // Failed Return False;} Playback control You can get or set the buffer volume via IDirectSoundBuffer :: getVolume and idirectSoundBuffer :: setVolume, setting the volume of the primary buffer to change the setting of the sound card.

Similarly, you can also get the frequency of the sound via iDirectSoundBuffer :: getFrequency and IDirectSoundBuffer :: setfrequency, retrieve or change the relative difference between the left and right channels via iDirectSoundBuffer :: getPan and IDirectSoundBuffer :: setPan, but you can't change The corresponding setting of the main buffer. As mentioned earlier, these buffer controls must be used in the corresponding flag. Play progress and Current Play and Write Positions DirectSound usually guarantees that there are two pointers in the buffer, one is the current play position - the current playback progress, one is the current location where the current writes. These two pointers are only offset by relative buffering. IdirectSoundBuffer :: Play method usually starts music from the current play progress. When the buffering is just established, the play progress is 0, and after a period of music is played, the play progress pointing to the next byte of the end of the music data, the same, when the music is stopped, the play progress also points to the stop position The next byte. We can imagine the buffer as a clock, and the two pointers can be used as two pointers on the clock. If the data is written clockwise, then the location of the data can be written in the current play progress - if the current playback progress is 1, then from 2 is the location of the data; while playback When the progress is 2 this position, it is now possible to write data from 3. It should be noted that if you use a stream buffer, then you should maintain your location you can write data, and this pointer and the parameter in the iDirectsoundbuffer :: Lock DWRITECURSOR is not a matter, that parameter is just what you want to think from? The location starts to write your data (remember is you thinking instead of you can only). Of course, you can also add DSBLOCK_FROMWRITECURSOR flags in the dwflags parameter to enable the function to ignore the DWRITECURSOR parameter to start writing data from the location where you currently write data. You can retrieve or set these two pointers via iDirectSoundBuffer :: getCurrentPosition and IDirectSoundBuffer :: setCurrentPosition, but the location of the current write data cannot be determined by yourself, but should join the DSBCAPS_GetCurrentPosition2 flag when creating a buffer to ensure that you are currently available. The location of the write data is correct. Play Buffer Notifitacion When you use a stream buffer, you are likely to know what location is already in place, or the playback is stopped. You can set a number of notifications in the buffer through the iDirectSoundNotify :: SetNotificationPositionS method, and DirectSound will be notified when the corresponding event occurs when these points occur. But if the music is already playing, it is not allowed to do. First of all you should get a pointer IDirectSoundNotify interface, like the following: // LPDIRECTSOUNDBUFFER lpDsbSecondary; // buffer has been initialized LPDIRECTSOUNDNOTIFY lpDsNotify; // interface pointer HRESULT hr = lpDsbSecondary-> QueryInterface (IID_IDirectSoundNotify, (LPVOID *) & lpDsNotify); if SuCeeded (HR) {// After success, you can use lpdsnotify-> setNotificationPositionPositions.

} Note: The iDirectSoundNotify interface and the auxiliary buffer created to create is associated. Now you can create an event object through the Win32 API CreateEvent (). Then you need to set a handle (CreateEvent () returned) for the DSBPositionNotify structure, and set the offset value of the notification location you want to set to the dwoffset, you can set the notification location. Position setting notification examples are as follows: DSBPOSITIONNOTIFY PositionNotify; PositionNotify.Offset = DSBPN_OFFSETSTOP; PositionNotify.hEventNotify = hMyEvent; // hMyEvent is a () Returns a handle CreateEvent lpDsNotify-> SetNotificationPositions (1, & PositionNotify); if you need to set up more The notification location, you can implement it through the structural array. Mixing Sound is easy to mix for DirectSound, which allows you to play multiple auxiliary buffers simultaneously, which can do these tasks themselves. As long as your program specifies the DSBCAPS_STATIC flag, DirectSound can maximize the use of hardware acceleration, which requires a again to specify once when the static buffer is reused. If all your buffers use the same sound format and the hardware output is also using this format, then DirectSound's mix will not need to convert any work on the format, thus the best effect (everything is the best !: P). We can change the hardware output format by creating a master buffer or calling the IDirectSoundBuffer :: setFormat method, remember that this main buffer is only for control purposes, and the writer buffer is different, and this call must be DSSCL_PRIORITY (priority Levels) or higher levels. Your own mix can only use your own mixed part of the DSSCL_WRITEPRIMARY level. After setting the collaboration level, create a main buffer, then lock it, write data, and then play like other buffers, but you need to set the dsbplay_looping flag.

转载请注明原文地址:https://www.9cbs.com/read-93221.html

New Post(0)