Can any one tell me how to play sound using WaveOutWrite-Buffered output.
I always gets clicks in playing buffered sound.
Posted on 2002-05-11 00:55:36 by makola
Hi,

the first thing you'll need is a proc (or signal as well) as callback which fills one of the buffers if it receives a WOM_DONE message.

second and very important is to call the waveOutProc() two times by yourself just to start the playback. This ensures that both buffers are filled with playback data.
this avoids the blips when toggling the buffers usually.


Bye Miracle
Posted on 2002-05-13 03:53:13 by miracle
When I try to play 2 back to back waveoutwrite I get the following error.Using my error report function it shows the following Error 'MMSYSTEM033 media data is still playing. Reset the device, or wait until the data is finishwd playing.' Could some one point me to a url or post a code snippet about playing wave file.
Posted on 2002-05-14 07:09:50 by makola
Hi,

there is a snippet attached which works well on all windows. It's part of my own media player so don't be surprised because of some overhead.
In addition some of the structure defnitions are different to the masm stuff because I use WASM and hate the assume esi:XXX :tongue:

Hope this helps :)

Bye Miracle
Posted on 2002-05-15 03:49:42 by miracle
Thank you for your code. But I was unable to find the difference
between your code and mine.
So I am pasting stripped down portion of my code. If you find where my error is please tell me.
(This code is now working.)

.DATA

DblBuffFlag DD 1
FileNm DB "c:\soho.wav",0
.DATA?
wavHnd DD ?
wFlHnd DD ?
aWavBuff DD ?
WavHdr WAVEHDR <?>
WavHdr2 WAVEHDR <?>
rf1 DD ?
WOpenHnd DD ?
WavErrBuff DB 128 DUP (?)

.CODE

;######################################################################

Play Macro
.If eax!=0
Invoke GetProcessHeap
Invoke HeapAlloc,eax,HEAP_ZERO_MEMORY,1024*1024*6
mov aWavBuff,eax
Invoke CreateFile,Addr FileNm,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,NULL
mov wFlHnd,eax
Invoke ReadFile,eax,aWavBuff,1024*1024*6,Addr rf1,NULL
WavOutOpen
WavIntHdr Offset WavHdr,aWavBuff,1024*102,1,0 ;,WHDR_BEGINLOOP ;or WHDR_ENDLOOP
add aWavBuff,1024*102
WavIntHdr Offset WavHdr2,aWavBuff,1024*102,1,0 ;,WHDR_BEGINLOOP ;or WHDR_ENDLOOP

WavPlay WavHdr
WavPlay WavHdr2
Invoke CloseHandle,wFlHnd
.EndIf
EndM

;######################################################################

WavOutClose Macro
Invoke waveOutClose,WOpenHnd
EndM

;######################################################################

WavOutOpen Macro Wfmt:=<WAVE_FORMAT_PCM>,nChnls:=<2>,SmplRate:=<44100>,BtsPrSmpl:=<16>
.DATA
Align 4
pWavFmt WAVEFORMATEX <?>
.DATA?
.CODE
mov eax,Offset pWavFmt
mov [eax].WAVEFORMATEX.wFormatTag,Wfmt
mov [eax].WAVEFORMATEX.nChannels,nChnls
mov [eax].WAVEFORMATEX.nSamplesPerSec,SmplRate
mov [eax].WAVEFORMATEX.nAvgBytesPerSec,SmplRate*((nChnls*BtsPrSmpl)/8)
mov [eax].WAVEFORMATEX.nBlockAlign,(nChnls*BtsPrSmpl)/8
mov [eax].WAVEFORMATEX.wBitsPerSample,BtsPrSmpl
mov [eax].WAVEFORMATEX.cbSize,0
Invoke waveOutOpen,Addr WOpenHnd,WAVE_MAPPER,Addr pWavFmt,Offset WavProc,NULL,CALLBACK_FUNCTION ;or WAVE_ALLOWSYNC
EndM

;######################################################################

WavIntHdr Macro pWavHdr:req,nmWavBuf:req,BufSize:req,nLoops,Flags
.CODE
mov ebx,nmWavBuf
mov eax,pWavHdr
mov nmHdrWav,eax
mov ecx,BufSize
add ebx,40h ;100
xor edx,edx
IFNB <nLoops>
mov [eax].WAVEHDR.dwLoops,edx ;nLoops
ENDIF
mov [eax].WAVEHDR.lpData,ebx
mov [eax].WAVEHDR.dwBufferLength,ecx
IFNB <Flags>
mov [eax].WAVEHDR.dwFlags,edx ; Flags ;WHDR_BEGINLOOP or WHDR_ENDLOOP

mov [eax].WAVEHDR.dwBytesRecorded,edx
mov [eax].WAVEHDR.dwUser,edx
mov [eax].WAVEHDR.lpNext,edx
mov [eax].WAVEHDR.Reserved,edx
ENDIF
Invoke waveOutPrepareHeader,WOpenHnd,pWavHdr,Sizeof WAVEHDR
EndM

;######################################################################

WavPlay Macro pWavHdr:req
Invoke waveOutWrite,WOpenHnd,Addr pWavHdr,Sizeof WAVEHDR
EndM

;######################################################################

WavProc Proc hWnd:HWND,uMsg:UINT,UserData:Dword,Param1:Dword,Param2:Dword
.If uMsg==WOM_DONE
.If DblBuffFlag==1
add aWavBuff,1024*102
;WavPlay WavHdr2 ----> error 1
Invoke waveOutUnprepareHeader,WOpenHnd, Offset WavHdr,Sizeof WavHdr
WavIntHdr Offset WavHdr,aWavBuff,1024*102,1
mov DblBuffFlag,0
WavPlay WavHdr ;----> correction
.Else
add aWavBuff,1024*102
Invoke waveOutUnprepareHeader,WOpenHnd, Offset WavHdr2,Sizeof WavHdr
WavIntHdr Offset WavHdr2,aWavBuff,1024*102,1
WavPlay WavHdr2 ;----> correction
mov DblBuffFlag,1
.EndIf
.EndIf
xor eax,eax
ret
WavProc EndP


Posted on 2002-05-15 10:23:40 by makola
Hi miracle,
I found out the problem in my code. It is due to my careless mistake. I thank you again for your code without it I would not have found the error. Now my code is working. Keep up the good work.
Regards,
Markola.:stupid:
Posted on 2002-05-15 22:43:41 by makola
Just out of curiosity, what are you building anyways?

Just currious why you want to manually play a wave rather than use the API's to do this?

:NaN:
Posted on 2002-05-15 23:12:32 by NaN
Hi NaN,
My final goal is to write a good software wavetable synthesizer.
Regards,
Markola.
Posted on 2002-05-16 07:19:41 by makola
Gotcha.. well good luck! ;)

If you make good progress, come back and tell us ;)

:alright:
NaN
Posted on 2002-05-16 12:39:15 by NaN
Hello again,

Im piddling in these areas now, and have to ask:

Why again should we "play twice" a wav file, when using microsoft API's??

I know its to avoid "blips" from above, but this seems like a 'hack' solution, rather than the proper way. I have a hard time believing M$ would walk away from the api development with this left uncared for??

Or perhaps im just giveing them too much credit?

:NaN:
Posted on 2002-05-19 22:19:12 by NaN
I stand corrected:

I put sometime into reseaching the entire waveout multimedia api's, and now fully understand why you need to double buffer.

And also now truely understand what you are doing above.

I managed to wip this example together, that is a little different from your above post, and has alot of commenting (which helps me understand all this ;) )

It simply loads and plays a wave file from disk, and creates a double buffering system. This example is different in many ways, but its mainly cause i've been doing alot of reading on the net for examples and idea's on what all this is about.

It uses Virtual Alloc to build the double buffers, and its not static (as your is), but rather, it makes each buffer 2 seconds of playback each. (so it queue's the next buffer every 2 seconds).

As well, it uses a semiphore event to wait until the playback is finished, while not stalling the OS.

It also uses the mmioOpen/Read to get the wave data to play, rather than using CreateFile...

Anywho.. Check it out, its an ASM source for info on this stuff, cause after searchin the board the before i wrote this, i realized there isnt alot of ASM material on this topic.

Hope you like. (Works well on 50MB wav's, ie. MP3->WAV songs)
:alright:
NaN
Posted on 2002-05-20 03:55:30 by NaN
Here is more info on this: (just found it on the web)

Nice little lecture slide ~ which graphically shows what im doing to get the wav loaded.
Posted on 2002-05-20 05:10:05 by NaN
Hi NaN,
Thanks for the code :alright:
Regards,
Makola
Posted on 2002-05-21 14:05:35 by makola
And i thought this thread when unnoticed. ;)

NaN
Posted on 2002-05-21 14:10:08 by NaN