1*c2c66affSColin Finck /* PROJECT:         ReactOS sndrec32
2*c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
3*c2c66affSColin Finck  * FILE:            base/applications/sndrec32/audio_waveout.cpp
4*c2c66affSColin Finck  * PURPOSE:         Sound recording
5*c2c66affSColin Finck  * PROGRAMMERS:     Marco Pagliaricci (irc: rendar)
6*c2c66affSColin Finck  */
7*c2c66affSColin Finck 
8*c2c66affSColin Finck #include "stdafx.h"
9*c2c66affSColin Finck #include "audio_waveout.hpp"
10*c2c66affSColin Finck 
11*c2c66affSColin Finck _AUDIO_NAMESPACE_START_
12*c2c66affSColin Finck 
13*c2c66affSColin Finck void
init_(void)14*c2c66affSColin Finck audio_waveout::init_(void)
15*c2c66affSColin Finck {
16*c2c66affSColin Finck     ZeroMemory((LPVOID)&wave_format, sizeof(WAVEFORMATEX));
17*c2c66affSColin Finck     wave_format.cbSize = sizeof(WAVEFORMATEX);
18*c2c66affSColin Finck     waveout_handle = 0;
19*c2c66affSColin Finck     playthread_id = 0;
20*c2c66affSColin Finck     wakeup_playthread = 0;
21*c2c66affSColin Finck     buf_secs = _AUDIO_DEFAULT_WAVEOUTBUFSECS;
22*c2c66affSColin Finck     status = WAVEOUT_NOTREADY;
23*c2c66affSColin Finck }
24*c2c66affSColin Finck 
25*c2c66affSColin Finck void
alloc_buffers_mem_(unsigned int buffs,float secs)26*c2c66affSColin Finck audio_waveout::alloc_buffers_mem_(unsigned int buffs, float secs)
27*c2c66affSColin Finck {
28*c2c66affSColin Finck     unsigned int onebuf_size = 0, tot_size = 0;
29*c2c66affSColin Finck 
30*c2c66affSColin Finck     /* Release old memory */
31*c2c66affSColin Finck     if (main_buffer)
32*c2c66affSColin Finck         delete[] main_buffer;
33*c2c66affSColin Finck 
34*c2c66affSColin Finck     if (wave_headers)
35*c2c66affSColin Finck         delete[] wave_headers;
36*c2c66affSColin Finck 
37*c2c66affSColin Finck     /* Calcs size of the buffers */
38*c2c66affSColin Finck     onebuf_size = (unsigned int)((float)aud_info.byte_rate() * secs);
39*c2c66affSColin Finck     tot_size = onebuf_size * buffs;
40*c2c66affSColin Finck     /* Allocs memory for the audio buffers */
41*c2c66affSColin Finck     main_buffer = new BYTE[tot_size];
42*c2c66affSColin Finck     /* Allocs memory for the `WAVEHDR' structures */
43*c2c66affSColin Finck     wave_headers = (WAVEHDR *) new BYTE[sizeof(WAVEHDR) * buffs];
44*c2c66affSColin Finck     /* Zeros memory */
45*c2c66affSColin Finck     ZeroMemory(main_buffer, tot_size);
46*c2c66affSColin Finck     ZeroMemory(wave_headers, sizeof(WAVEHDR) * buffs);
47*c2c66affSColin Finck     /* Updates total size of the buffers */
48*c2c66affSColin Finck     mb_size = tot_size;
49*c2c66affSColin Finck }
50*c2c66affSColin Finck 
51*c2c66affSColin Finck void
init_headers_(void)52*c2c66affSColin Finck audio_waveout::init_headers_(void)
53*c2c66affSColin Finck {
54*c2c66affSColin Finck     /* If there is no memory for memory or headers, simply return */
55*c2c66affSColin Finck     if ((!wave_headers) || (!main_buffer))
56*c2c66affSColin Finck         return;
57*c2c66affSColin Finck 
58*c2c66affSColin Finck     /* This is the size for one buffer */
59*c2c66affSColin Finck     DWORD buf_sz = mb_size / buffers;
60*c2c66affSColin Finck     /* This is the base address for one buffer */
61*c2c66affSColin Finck     BYTE *buf_addr = main_buffer;
62*c2c66affSColin Finck 
63*c2c66affSColin Finck     ZeroMemory(wave_headers, sizeof(WAVEHDR) * buffers);
64*c2c66affSColin Finck 
65*c2c66affSColin Finck     /* Initializes headers */
66*c2c66affSColin Finck     for (unsigned int i = 0; i < buffers; ++i)
67*c2c66affSColin Finck     {
68*c2c66affSColin Finck         /* Sets the correct base address and length for the little buffer */
69*c2c66affSColin Finck         wave_headers[i].dwBufferLength = mb_size / buffers;
70*c2c66affSColin Finck         wave_headers[i].lpData = (LPSTR) buf_addr;
71*c2c66affSColin Finck 
72*c2c66affSColin Finck         /* Unsets the WHDR_DONE flag */
73*c2c66affSColin Finck         wave_headers[i].dwFlags &= ~WHDR_DONE;
74*c2c66affSColin Finck 
75*c2c66affSColin Finck         /* Sets the WAVEHDR user data with an unique little buffer ID# */
76*c2c66affSColin Finck         wave_headers[i].dwUser = (unsigned int)i;
77*c2c66affSColin Finck 
78*c2c66affSColin Finck         /* Increments little buffer base address */
79*c2c66affSColin Finck         buf_addr += buf_sz;
80*c2c66affSColin Finck     }
81*c2c66affSColin Finck }
82*c2c66affSColin Finck 
83*c2c66affSColin Finck void
prep_headers_(void)84*c2c66affSColin Finck audio_waveout::prep_headers_(void)
85*c2c66affSColin Finck {
86*c2c66affSColin Finck     MMRESULT err;
87*c2c66affSColin Finck     bool error = false;
88*c2c66affSColin Finck 
89*c2c66affSColin Finck     /* If there is no memory for memory or headers, throw error */
90*c2c66affSColin Finck     if ((!wave_headers) || (!main_buffer) || (!waveout_handle))
91*c2c66affSColin Finck     {
92*c2c66affSColin Finck         /* TODO: throw error! */
93*c2c66affSColin Finck     }
94*c2c66affSColin Finck 
95*c2c66affSColin Finck     for (unsigned int i = 0; i < buffers; ++i)
96*c2c66affSColin Finck     {
97*c2c66affSColin Finck         err = waveOutPrepareHeader(waveout_handle, &wave_headers[i], sizeof(WAVEHDR));
98*c2c66affSColin Finck         if (err != MMSYSERR_NOERROR)
99*c2c66affSColin Finck             error = true;
100*c2c66affSColin Finck     }
101*c2c66affSColin Finck 
102*c2c66affSColin Finck     if (error)
103*c2c66affSColin Finck     {
104*c2c66affSColin Finck         /* TODO: throw error indicating which header i-th is errorneous */
105*c2c66affSColin Finck     }
106*c2c66affSColin Finck }
107*c2c66affSColin Finck 
108*c2c66affSColin Finck void
unprep_headers_(void)109*c2c66affSColin Finck audio_waveout::unprep_headers_(void)
110*c2c66affSColin Finck {
111*c2c66affSColin Finck     MMRESULT err;
112*c2c66affSColin Finck     bool error = false;
113*c2c66affSColin Finck 
114*c2c66affSColin Finck     /* If there is no memory for memory or headers, throw error */
115*c2c66affSColin Finck     if ((!wave_headers) || (!main_buffer) || (!waveout_handle))
116*c2c66affSColin Finck     {
117*c2c66affSColin Finck         /* TODO: throw error! */
118*c2c66affSColin Finck     }
119*c2c66affSColin Finck 
120*c2c66affSColin Finck     for (unsigned int i = 0; i < buffers; ++i)
121*c2c66affSColin Finck     {
122*c2c66affSColin Finck         err = waveOutUnprepareHeader(waveout_handle, &wave_headers[i], sizeof(WAVEHDR));
123*c2c66affSColin Finck         if (err != MMSYSERR_NOERROR)
124*c2c66affSColin Finck             error = true;
125*c2c66affSColin Finck     }
126*c2c66affSColin Finck 
127*c2c66affSColin Finck     if (error)
128*c2c66affSColin Finck     {
129*c2c66affSColin Finck         /* TODO: throw error indicating which header i-th is errorneous */
130*c2c66affSColin Finck     }
131*c2c66affSColin Finck }
132*c2c66affSColin Finck 
133*c2c66affSColin Finck void
free_buffers_mem_(void)134*c2c66affSColin Finck audio_waveout::free_buffers_mem_(void)
135*c2c66affSColin Finck {
136*c2c66affSColin Finck     /* Frees memory */
137*c2c66affSColin Finck     if (main_buffer)
138*c2c66affSColin Finck         delete[] main_buffer;
139*c2c66affSColin Finck 
140*c2c66affSColin Finck     if (wave_headers)
141*c2c66affSColin Finck         delete[] wave_headers;
142*c2c66affSColin Finck 
143*c2c66affSColin Finck     main_buffer = 0;
144*c2c66affSColin Finck     wave_headers = 0;
145*c2c66affSColin Finck }
146*c2c66affSColin Finck 
147*c2c66affSColin Finck void
open(void)148*c2c66affSColin Finck audio_waveout::open(void)
149*c2c66affSColin Finck {
150*c2c66affSColin Finck     MMRESULT err;
151*c2c66affSColin Finck     HANDLE playthread_handle = 0;
152*c2c66affSColin Finck 
153*c2c66affSColin Finck     /* Checkin the status of the object */
154*c2c66affSColin Finck     if (status != WAVEOUT_NOTREADY)
155*c2c66affSColin Finck     {
156*c2c66affSColin Finck         /* TODO: throw error */
157*c2c66affSColin Finck     }
158*c2c66affSColin Finck 
159*c2c66affSColin Finck     /* Creating the EVENT object that will be signaled when
160*c2c66affSColin Finck        the playing thread has to wake up */
161*c2c66affSColin Finck     wakeup_playthread = CreateEvent(0, FALSE, FALSE, 0);
162*c2c66affSColin Finck     if (!wakeup_playthread)
163*c2c66affSColin Finck     {
164*c2c66affSColin Finck         status = WAVEOUT_ERR;
165*c2c66affSColin Finck         /* TODO: throw error */
166*c2c66affSColin Finck     }
167*c2c66affSColin Finck 
168*c2c66affSColin Finck     /* Inialize buffers for recording audio data from the wavein audio line */
169*c2c66affSColin Finck     alloc_buffers_mem_(buffers, buf_secs);
170*c2c66affSColin Finck     init_headers_();
171*c2c66affSColin Finck 
172*c2c66affSColin Finck     /* Sound format that will be captured by wavein */
173*c2c66affSColin Finck     wave_format.wFormatTag = WAVE_FORMAT_PCM;
174*c2c66affSColin Finck     wave_format.nChannels = aud_info.channels();
175*c2c66affSColin Finck     wave_format.nSamplesPerSec = aud_info.sample_rate();
176*c2c66affSColin Finck     wave_format.wBitsPerSample = aud_info.bits();
177*c2c66affSColin Finck     wave_format.nBlockAlign = aud_info.block_align();
178*c2c66affSColin Finck     wave_format.nAvgBytesPerSec = aud_info.byte_rate();
179*c2c66affSColin Finck 
180*c2c66affSColin Finck     /* Creating the recording thread */
181*c2c66affSColin Finck     playthread_handle = CreateThread(NULL,
182*c2c66affSColin Finck                                      0,
183*c2c66affSColin Finck                                      audio_waveout::playing_procedure,
184*c2c66affSColin Finck                                      (PVOID)this,
185*c2c66affSColin Finck                                      0,
186*c2c66affSColin Finck                                      &playthread_id);
187*c2c66affSColin Finck     /* Checking thread handle */
188*c2c66affSColin Finck     if (!playthread_handle)
189*c2c66affSColin Finck     {
190*c2c66affSColin Finck         /* Updating status */
191*c2c66affSColin Finck         status = WAVEOUT_ERR;
192*c2c66affSColin Finck         /* TODO: throw error */
193*c2c66affSColin Finck     }
194*c2c66affSColin Finck 
195*c2c66affSColin Finck     /* We don't need the thread handle anymore, so we can close it from now.
196*c2c66affSColin Finck        (We'll just need the thread ID for the `waveInOpen' API) */
197*c2c66affSColin Finck     CloseHandle(playthread_handle);
198*c2c66affSColin Finck 
199*c2c66affSColin Finck     /* Reset the `audio_source' to the start position */
200*c2c66affSColin Finck     audio_buf.set_position_start();
201*c2c66affSColin Finck     /* Opens the WAVE_OUT device */
202*c2c66affSColin Finck     err = waveOutOpen(&waveout_handle,
203*c2c66affSColin Finck                       WAVE_MAPPER,
204*c2c66affSColin Finck                       &wave_format,
205*c2c66affSColin Finck                       playthread_id,
206*c2c66affSColin Finck                       0,
207*c2c66affSColin Finck                       CALLBACK_THREAD | WAVE_ALLOWSYNC);
208*c2c66affSColin Finck     if (err != MMSYSERR_NOERROR)
209*c2c66affSColin Finck     {
210*c2c66affSColin Finck         MessageBox(0, _T("waveOutOpen Error"), 0, 0);
211*c2c66affSColin Finck         /* TODO: throw error */
212*c2c66affSColin Finck     }
213*c2c66affSColin Finck 
214*c2c66affSColin Finck     status = WAVEOUT_READY;
215*c2c66affSColin Finck }
216*c2c66affSColin Finck 
217*c2c66affSColin Finck void
play(void)218*c2c66affSColin Finck audio_waveout::play(void)
219*c2c66affSColin Finck {
220*c2c66affSColin Finck     MMRESULT err;
221*c2c66affSColin Finck     unsigned int i;
222*c2c66affSColin Finck 
223*c2c66affSColin Finck     if (!main_buffer)
224*c2c66affSColin Finck     {
225*c2c66affSColin Finck         /* TODO; throw error, or assert */
226*c2c66affSColin Finck         return;
227*c2c66affSColin Finck     }
228*c2c66affSColin Finck 
229*c2c66affSColin Finck     /* If the status is PAUSED, we have to resume the audio playing */
230*c2c66affSColin Finck     if (status == WAVEOUT_PAUSED)
231*c2c66affSColin Finck     {
232*c2c66affSColin Finck         /* Updates status */
233*c2c66affSColin Finck         status = WAVEOUT_PLAYING;
234*c2c66affSColin Finck         /* Tells to the driver to resume audio playing */
235*c2c66affSColin Finck         waveOutRestart(waveout_handle);
236*c2c66affSColin Finck         /* Wakeup playing thread */
237*c2c66affSColin Finck         SetEvent(wakeup_playthread);
238*c2c66affSColin Finck         return;
239*c2c66affSColin Finck     } /* if status == WAVEOUT_PAUSED */
240*c2c66affSColin Finck 
241*c2c66affSColin Finck     if (status != WAVEOUT_READY)
242*c2c66affSColin Finck         return;
243*c2c66affSColin Finck 
244*c2c66affSColin Finck     /* Prepares WAVEHDR structures */
245*c2c66affSColin Finck     prep_headers_();
246*c2c66affSColin Finck     /* Sets correct status */
247*c2c66affSColin Finck     status = WAVEOUT_PLAYING;
248*c2c66affSColin Finck     /* Reads the audio from the start */
249*c2c66affSColin Finck     //audio_buf.set_position_start();
250*c2c66affSColin Finck 
251*c2c66affSColin Finck     /* Reads the first N bytes from the audio buffer, where N = the total
252*c2c66affSColin Finck        size of all little buffers */
253*c2c66affSColin Finck     audio_buf.read(main_buffer, mb_size);
254*c2c66affSColin Finck 
255*c2c66affSColin Finck     /* Wakeup the playing thread */
256*c2c66affSColin Finck     SetEvent(wakeup_playthread);
257*c2c66affSColin Finck 
258*c2c66affSColin Finck     /* Sends all the little buffers to the audio driver, so it can play
259*c2c66affSColin Finck        the sound data */
260*c2c66affSColin Finck     for (i = 0; i < buffers; ++i)
261*c2c66affSColin Finck     {
262*c2c66affSColin Finck         err = waveOutWrite(waveout_handle, &wave_headers[i], sizeof(WAVEHDR));
263*c2c66affSColin Finck         if (err != MMSYSERR_NOERROR)
264*c2c66affSColin Finck         {
265*c2c66affSColin Finck             MessageBox(0, _T("waveOutWrite Error"), 0, 0);
266*c2c66affSColin Finck             /* TODO: throw error */
267*c2c66affSColin Finck         }
268*c2c66affSColin Finck     }
269*c2c66affSColin Finck }
270*c2c66affSColin Finck 
271*c2c66affSColin Finck void
pause(void)272*c2c66affSColin Finck audio_waveout::pause(void)
273*c2c66affSColin Finck {
274*c2c66affSColin Finck     MMRESULT err;
275*c2c66affSColin Finck 
276*c2c66affSColin Finck     /* If the waveout object is not playing audio, do nothing */
277*c2c66affSColin Finck     if (status == WAVEOUT_PLAYING)
278*c2c66affSColin Finck     {
279*c2c66affSColin Finck         /* Updating status */
280*c2c66affSColin Finck         status = WAVEOUT_PAUSED;
281*c2c66affSColin Finck         /* Tells to audio driver to pause audio */
282*c2c66affSColin Finck         err = waveOutPause(waveout_handle);
283*c2c66affSColin Finck         if (err != MMSYSERR_NOERROR)
284*c2c66affSColin Finck         {
285*c2c66affSColin Finck             MessageBox(0, _T("waveOutPause Error"), 0, 0);
286*c2c66affSColin Finck             /* TODO: throw error */
287*c2c66affSColin Finck         }
288*c2c66affSColin Finck     }
289*c2c66affSColin Finck }
290*c2c66affSColin Finck 
291*c2c66affSColin Finck void
stop(void)292*c2c66affSColin Finck audio_waveout::stop(void)
293*c2c66affSColin Finck {
294*c2c66affSColin Finck     MMRESULT err;
295*c2c66affSColin Finck 
296*c2c66affSColin Finck     /* Checks the current status */
297*c2c66affSColin Finck     if ((status != WAVEOUT_PLAYING) &&
298*c2c66affSColin Finck         (status != WAVEOUT_FLUSHING) &&
299*c2c66affSColin Finck         (status != WAVEOUT_PAUSED))
300*c2c66affSColin Finck     {
301*c2c66affSColin Finck         /* Do nothing */
302*c2c66affSColin Finck         return;
303*c2c66affSColin Finck     }
304*c2c66affSColin Finck 
305*c2c66affSColin Finck     /* Sets a new status */
306*c2c66affSColin Finck     status = WAVEOUT_STOP;
307*c2c66affSColin Finck     /* Flushes pending audio datas */
308*c2c66affSColin Finck     err = waveOutReset( waveout_handle );
309*c2c66affSColin Finck     if (err != MMSYSERR_NOERROR)
310*c2c66affSColin Finck     {
311*c2c66affSColin Finck         MessageBox(0, _T("err WaveOutReset.\n"),_T("ERROR"), 0);
312*c2c66affSColin Finck         /* TODO: throw error */
313*c2c66affSColin Finck     }
314*c2c66affSColin Finck 
315*c2c66affSColin Finck     /* Sets the start position of the audio buffer */
316*c2c66affSColin Finck     audio_buf.set_position_start();
317*c2c66affSColin Finck     /* Cleans little buffers */
318*c2c66affSColin Finck     unprep_headers_();
319*c2c66affSColin Finck     init_headers_();
320*c2c66affSColin Finck     /* Refreshes the status */
321*c2c66affSColin Finck     status = WAVEOUT_READY;
322*c2c66affSColin Finck }
323*c2c66affSColin Finck 
324*c2c66affSColin Finck void
close(void)325*c2c66affSColin Finck audio_waveout::close(void)
326*c2c66affSColin Finck {
327*c2c66affSColin Finck     MMRESULT err;
328*c2c66affSColin Finck 
329*c2c66affSColin Finck     /* If the `wave_out' object is playing audio, or it is in paused state,
330*c2c66affSColin Finck        we have to call the `stop' member function, to flush pending buffers */
331*c2c66affSColin Finck     if ((status == WAVEOUT_PLAYING) || (status== WAVEOUT_PAUSED))
332*c2c66affSColin Finck     {
333*c2c66affSColin Finck         stop();
334*c2c66affSColin Finck     }
335*c2c66affSColin Finck 
336*c2c66affSColin Finck     /* When we have flushed all pending buffers, the wave out handle can be successfully closed */
337*c2c66affSColin Finck     err = waveOutClose(waveout_handle);
338*c2c66affSColin Finck     if (err != MMSYSERR_NOERROR)
339*c2c66affSColin Finck     {
340*c2c66affSColin Finck         MessageBox(0, _T("waveOutClose Error"), 0, 0);
341*c2c66affSColin Finck         /* TODO: throw error */
342*c2c66affSColin Finck     }
343*c2c66affSColin Finck 
344*c2c66affSColin Finck     free_buffers_mem_();
345*c2c66affSColin Finck }
346*c2c66affSColin Finck 
347*c2c66affSColin Finck DWORD WINAPI
playing_procedure(LPVOID arg)348*c2c66affSColin Finck audio_waveout::playing_procedure(LPVOID arg)
349*c2c66affSColin Finck {
350*c2c66affSColin Finck     MSG msg;
351*c2c66affSColin Finck     WAVEHDR *phdr;
352*c2c66affSColin Finck     MMRESULT err;
353*c2c66affSColin Finck     audio_waveout *_this = (audio_waveout *)arg;
354*c2c66affSColin Finck     unsigned int read_size;
355*c2c66affSColin Finck 
356*c2c66affSColin Finck     /* Check the arg pointer */
357*c2c66affSColin Finck     if (_this == 0)
358*c2c66affSColin Finck         return 0;
359*c2c66affSColin Finck 
360*c2c66affSColin Finck     /* The thread can go to sleep for now. It will be wake up only when
361*c2c66affSColin Finck        there is audio data to be recorded */
362*c2c66affSColin Finck     if (_this->wakeup_playthread)
363*c2c66affSColin Finck         WaitForSingleObject(_this->wakeup_playthread, INFINITE);
364*c2c66affSColin Finck 
365*c2c66affSColin Finck     /* Entering main polling loop */
366*c2c66affSColin Finck     while (GetMessage(&msg, 0, 0, 0))
367*c2c66affSColin Finck     {
368*c2c66affSColin Finck         switch (msg.message)
369*c2c66affSColin Finck         {
370*c2c66affSColin Finck             case MM_WOM_DONE:
371*c2c66affSColin Finck                 phdr = (WAVEHDR *)msg.lParam;
372*c2c66affSColin Finck 
373*c2c66affSColin Finck                 /* If the status of the `wave_out' object is different
374*c2c66affSColin Finck                    than playing, then the thread can go to sleep */
375*c2c66affSColin Finck                 if ((_this->status != WAVEOUT_PLAYING) &&
376*c2c66affSColin Finck                     (_this->status != WAVEOUT_FLUSHING) &&
377*c2c66affSColin Finck                     (_this->wakeup_playthread))
378*c2c66affSColin Finck                 {
379*c2c66affSColin Finck                     WaitForSingleObject(_this->wakeup_playthread, INFINITE);
380*c2c66affSColin Finck                 }
381*c2c66affSColin Finck 
382*c2c66affSColin Finck                 /* The playing thread doesn't have to sleep, so let's checking
383*c2c66affSColin Finck                    first if the little buffer has been sent to the audio driver
384*c2c66affSColin Finck                    (it has the WHDR_DONE flag). If it is, we can read new audio
385*c2c66affSColin Finck                    datas from the `audio_producer' object, refill the little buffer,
386*c2c66affSColin Finck                    and resend it to the driver with waveOutWrite( ) API */
387*c2c66affSColin Finck                 if (phdr->dwFlags & WHDR_DONE)
388*c2c66affSColin Finck                 {
389*c2c66affSColin Finck                     if (_this->status == WAVEOUT_PLAYING)
390*c2c66affSColin Finck                     {
391*c2c66affSColin Finck                         /* Here the thread is still playing a sound, so it can
392*c2c66affSColin Finck                            read new audio data from the `audio_producer' object */
393*c2c66affSColin Finck                         read_size = _this->audio_buf.read((BYTE *)phdr->lpData,
394*c2c66affSColin Finck                                                           phdr->dwBufferLength);
395*c2c66affSColin Finck                     } else
396*c2c66affSColin Finck                         read_size = 0;
397*c2c66affSColin Finck 
398*c2c66affSColin Finck                     /* If the `audio_producer' object, has produced some
399*c2c66affSColin Finck                        audio data, so `read_size' will be > 0 */
400*c2c66affSColin Finck                     if (read_size)
401*c2c66affSColin Finck                     {
402*c2c66affSColin Finck                         /* Adjusts the correct effectively read size */
403*c2c66affSColin Finck                         phdr->dwBufferLength = read_size;
404*c2c66affSColin Finck 
405*c2c66affSColin Finck                         /* Before sending the little buffer to the driver,
406*c2c66affSColin Finck                            we have to remove the `WHDR_DONE' flag, because
407*c2c66affSColin Finck                            the little buffer now contain new audio data that have to be played */
408*c2c66affSColin Finck                         phdr->dwFlags &= ~WHDR_DONE;
409*c2c66affSColin Finck 
410*c2c66affSColin Finck                         /* Plays the sound of the little buffer */
411*c2c66affSColin Finck                         err = waveOutWrite(_this->waveout_handle,
412*c2c66affSColin Finck                                            phdr,
413*c2c66affSColin Finck                                            sizeof(WAVEHDR));
414*c2c66affSColin Finck 
415*c2c66affSColin Finck                         /* Checking if any error has occured */
416*c2c66affSColin Finck                         if (err != MMSYSERR_NOERROR)
417*c2c66affSColin Finck                         {
418*c2c66affSColin Finck                             MessageBox(0, _T("waveOutWrite Error"), 0, 0);
419*c2c66affSColin Finck                             /* TODO: throw error */
420*c2c66affSColin Finck                         }
421*c2c66affSColin Finck                     }
422*c2c66affSColin Finck                     else
423*c2c66affSColin Finck                     {
424*c2c66affSColin Finck                         /* Here `read_size' is 0, so the `audio_producer' object,
425*c2c66affSColin Finck                            doesn't have any sound data to produce anymore. So,
426*c2c66affSColin Finck                            now we have to see the little buffer #ID to establishing what to do */
427*c2c66affSColin Finck                         if (phdr->dwUser == 0)
428*c2c66affSColin Finck                         {
429*c2c66affSColin Finck                             /* Here `read_size' is 0, and the buffer user data
430*c2c66affSColin Finck                                contain 0, so this is the first of N little
431*c2c66affSColin Finck                                buffers that came back with `WHDR_DONE' flag;
432*c2c66affSColin Finck                                this means that this is the last little buffer
433*c2c66affSColin Finck                                in which we have to read data to; so we can
434*c2c66affSColin Finck                                _STOP_ reading data from the `audio_producer'
435*c2c66affSColin Finck                                object: doing this is accomplished just setting
436*c2c66affSColin Finck                                the current status as "WAVEOUT_FLUSHING" */
437*c2c66affSColin Finck                             _this->status = WAVEOUT_FLUSHING;
438*c2c66affSColin Finck                         }
439*c2c66affSColin Finck                         else if (phdr->dwUser == (_this->buffers - 1))
440*c2c66affSColin Finck                         {
441*c2c66affSColin Finck                             /* Here `read_size' and the buffer user data, that
442*c2c66affSColin Finck                                contain a buffer ID#, is equal to the number of
443*c2c66affSColin Finck                                the total buffers - 1. This means that this is
444*c2c66affSColin Finck                                the _LAST_ little buffer that has been played by
445*c2c66affSColin Finck                                the audio driver. We can STOP the `wave_out'
446*c2c66affSColin Finck                                object now, or restart the sound playing, if we have a infinite loop */
447*c2c66affSColin Finck                             _this->stop();
448*c2c66affSColin Finck 
449*c2c66affSColin Finck                             /* Let the thread go to sleep */
450*c2c66affSColin Finck                             if (_this->audio_buf.play_finished)
451*c2c66affSColin Finck                                 _this->audio_buf.play_finished();
452*c2c66affSColin Finck 
453*c2c66affSColin Finck                             if (_this->wakeup_playthread)
454*c2c66affSColin Finck                                 WaitForSingleObject(_this->wakeup_playthread,
455*c2c66affSColin Finck                                                     INFINITE);
456*c2c66affSColin Finck 
457*c2c66affSColin Finck                         } /* if (phdr->dwUser == (_this->buffers - 1)) */
458*c2c66affSColin Finck                     } /* if read_size != 0 */
459*c2c66affSColin Finck                 } /* (phdr->dwFlags & WHDR_DONE) */
460*c2c66affSColin Finck                 break; /* end case */
461*c2c66affSColin Finck             case MM_WOM_CLOSE:
462*c2c66affSColin Finck                 /* The thread can exit now */
463*c2c66affSColin Finck                 return 0;
464*c2c66affSColin Finck                 break;
465*c2c66affSColin Finck             case MM_WOM_OPEN:
466*c2c66affSColin Finck                 /* Do nothing */
467*c2c66affSColin Finck                 break;
468*c2c66affSColin Finck         } /* end switch(msg.message) */
469*c2c66affSColin Finck     } /* end while(GetMessage(...)) */
470*c2c66affSColin Finck 
471*c2c66affSColin Finck     return 0;
472*c2c66affSColin Finck }
473*c2c66affSColin Finck 
474*c2c66affSColin Finck _AUDIO_NAMESPACE_END_
475