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