Click here to Skip to main content
15,881,882 members
Articles / Multimedia / DirectX
Article

Playing Wave Files using Streaming Buffers

Rate me:
Please Sign up or sign in to vote.
2.89/5 (6 votes)
26 Jul 20033 min read 81.6K   3.4K   29   7
An article on Streaming buffers

Introduction

This project uses DirectSound to play wave files, but using a single static buffer it takes a lot of time and CPU cycles to load sound to buffer. But using streaming buffers is one way to copy data in blocks and playing the same block, also updating the same block from time to time. Thus it is a better way of playing large sound files.

Using the code

This project uses DirectSound in an easy way and most of the manipulation of wave file is done in wavefile class. The most important feature of it is that it uses Streaming Buffers. If you want to play a large wave file, loading it completely into the buffer would take up a lot of time to initialize. A better way would be to load it step by step into a circular buffer in a timely manner. I have used mmio functions defined in mmsystem.h. In this class, simple way of parsing wave header is done by finding the RIFF chunk by setting its type as mmioFOURCC('W','A','V','E') and descending into it to find its FMT chunk. Then wave format is read from this FMT chunk and stored in WAVEFORMATEX structure. After this I dived into data chunk. Data chunk is not read in one go. This is where all the importance comes in. A ServiceBuffer is used to service primary buffer to keep it full most of the time. This is called by timer proc through AudioStream member function TimerCallback. A primary buffer can be used of any size, but it must be serviced quite a number of times while playing one full buffer length. The main aim is to keep this buffer as much full as possible.

class Timer { public: Timer(); ~Timer(); 
BOOL Create (UINT nPeriod, UINT nRes, 
         DWORD dwUser, int (pfnCallback)(DWORD)); 
public: static void CALLBACK TimeProc(UINT uID, 
         UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); 
int (*m_pfnCallback)(DWORD);
DWORD m_dwUser; UINT m_nPeriod;
UINT m_nRes;
UINT m_nIDTimer;
UINT UID;
void TimerStop(void); };
// Save current time (for elapsed time calculation) 
// This is a part of play function that initialises the timer
m_nTimeStarted = timeGetTime (); // Kick off timer to service buffer 
m_ptimer = new Timer (); 
if (m_ptimer) {
   m_ptimer->
   Create (m_nBufService, m_nBufService, DWORD(this), TimerCallback); 
}

This TimerCallback function calls the service buffer at specified intervals. There are play cursors and write cursors at 15 millisecond difference. DirectSound does not allow you to write data in that position. So better maintain your own variable to keep information about the buffer memory played and to be played.

BOOl AudioStream::SereviceBuffer() { 
//not to disturb while being serviced 
if (InterlockedExchange (&lInService, TRUE) == FALSE) 

{ . . . . . . . . . 
. . . . . . . 
DWORD dwFreeSpace = GetMaxWriteSize(); 
dwDataremaining=m_pwavefile-> GetNumbBytesRemaining(); 
//there will be three cases 
//i)enough data to fill free space;
//ii)data to fill is less than buffer size;
//iii)all data has been send to buffer and are being played.
//Fill free space with silence data.Deal with them accordingly.
Write wave data;
. . . . . . . . .
else fRtn=FALSE; }
else { // Service routine reentered. Do nothing, just return
fRtn = FALSE; } 
return (fRtn); }
<![if !supportEmptyParas]> <![endif]>

Problems I faced

The main problems I faced while making this project was reading the wave files. There was always an error while copying the contents of PCMWAVEFORMAT (16 Bytes) structure to WAVEFORMATEX (18 Bytes) structure. The worst thing that happened was I compiled this part of program in another file and memcpy was working quite well but not here. So I had to allocate 18 bytes to WAVEFORMATEX structure variable and then fill up the structure one by one.

One more strange effect I noticed, when I had put the dsound.h header file before mmsystem.h. So if you get syntax error in header file, try putting mmsystem.h before dsound.h. The original idea I got from the MSDN web site in a tutorial about streaming buffers. There I could not use the TIMERCALLBACK, so I used old C style function passing to another function.

History

  • Version 1.0

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
India India
I am 20 yrs old and a student at Institute of Technology and Management College (www.itmindia.edu) in India.I am doing electronics and communication engineering. My main interests are in computer programming (DirectX,voice,internet srevers and client. Apart from these I have also interest in electronics. I recently made a project using microcontroller(PSoC) and data transfer mechanism using transistor and also in DTMF. I would like to make projects that use electronics as well as computer programming.

Comments and Discussions

 
Generalplaying Waves through PSoC Pin
Jagadeesha l19-Jun-07 1:24
Jagadeesha l19-Jun-07 1:24 
Generalproblem Pin
earslan23-Mar-04 22:20
earslan23-Mar-04 22:20 
GeneralRe: problem Pin
omershakeel7-Jun-04 20:58
omershakeel7-Jun-04 20:58 
GeneralAuthor's reply Pin
xsamar1-Nov-04 6:22
xsamar1-Nov-04 6:22 
GeneralRead from Primary Buffer Pin
FritzR27-Feb-04 7:43
FritzR27-Feb-04 7:43 
Generalhelp for gettinf sound from MIC and displaying in speaker Pin
Ainee19-Jan-04 19:27
Ainee19-Jan-04 19:27 
GeneralRe: help for gettinf sound from MIC and displaying in speaker Pin
mohsen nourian4-Jul-04 0:55
mohsen nourian4-Jul-04 0:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.