]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/mmedia/sndwin.cpp
Added accidentally omitted license to match source files
[wxWidgets.git] / contrib / src / mmedia / sndwin.cpp
1 // --------------------------------------------------------------------------
2 // Name: sndwin.cpp
3 // Purpose:
4 // Date: 08/11/1999
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
6 // CVSID: $Id$
7 // --------------------------------------------------------------------------
8 #ifdef __GNUG__
9 #pragma implementation "sndwin.cpp"
10 #endif
11
12 #include "wx/wxprec.h"
13
14 #ifdef __WINDOWS__
15
16 #ifndef WX_PRECOMP
17 #include "wx/defs.h"
18 #include "wx/app.h"
19 #include "wx/string.h"
20 #endif
21
22 #include "wx/module.h"
23 #include "wx/msw/private.h"
24
25 // -------------------------------------------------------------------------
26 // MMedia headers
27 // -------------------------------------------------------------------------
28
29 #include "wx/mmedia/sndbase.h"
30 #include "wx/mmedia/sndwin.h"
31 #include "wx/mmedia/sndpcm.h"
32
33 // -------------------------------------------------------------------------
34 // System headers
35 // -------------------------------------------------------------------------
36
37 #include <windows.h>
38 #include <mmsystem.h>
39
40 // -------------------------------------------------------------------------
41 // External definitions, forward, ...
42 // -------------------------------------------------------------------------
43
44 typedef struct _wxSoundInternal wxSoundInternal;
45 typedef struct _wxSoundInfoHeader wxSoundInfoHeader;
46
47 extern const wxChar *wxCanvasClassName;
48
49 wxList *wxSoundHandleList = NULL;
50
51 static inline wxSoundStreamWin *wxFindSoundFromHandle(WXHWND hWnd)
52 {
53 wxObjectList::compatibility_iterator node = wxSoundHandleList->Find((long)hWnd);
54 if (!node)
55 return NULL;
56 return (wxSoundStreamWin *)node->GetData();
57 }
58
59 struct _wxSoundInternal {
60 HWND m_sndWin;
61 HWAVEIN m_devin;
62 HWAVEOUT m_devout;
63 bool m_output_enabled, m_input_enabled;
64 };
65
66 struct _wxSoundInfoHeader {
67 HGLOBAL m_h_header, m_h_data;
68 char *m_data;
69 WAVEHDR *m_header;
70 int m_mode;
71 bool m_playing, m_recording;
72 wxUint32 m_position, m_size;
73
74 wxSoundStreamWin *m_driver;
75 };
76
77 #define WXSOUND_MAX_QUEUE 10
78
79 wxSoundStreamWin::wxSoundStreamWin()
80 {
81 wxSoundFormatPcm pcm;
82
83 m_production_started = false;
84 m_internal = new wxSoundInternal;
85 if (!m_internal) {
86 m_snderror = wxSOUND_MEMERROR;
87 m_internal = NULL;
88 return;
89 }
90 m_snderror = wxSOUND_NOERROR;
91
92 // Setup defaults
93 CreateSndWindow();
94 SetSoundFormat(pcm);
95
96 m_internal->m_input_enabled = false;
97 m_internal->m_output_enabled = false;
98
99 m_waiting_for = false;
100
101 if (!OpenDevice(wxSOUND_OUTPUT)) {
102 m_snderror = wxSOUND_NOERROR; //next call to OpenDevice won't do this
103 if (!OpenDevice(wxSOUND_INPUT))
104 return;
105 }
106
107 CloseDevice();
108 }
109
110 wxSoundStreamWin::~wxSoundStreamWin()
111 {
112 if (m_internal) {
113 if (m_production_started)
114 StopProduction();
115 DestroySndWindow();
116
117 delete m_internal;
118 }
119 }
120
121 // -----------------------------------------------------------------------
122 // _wxSoundHandlerWndProc: Window callback to handle buffer completion
123 // -----------------------------------------------------------------------
124 LRESULT APIENTRY _EXPORT
125
126 _wxSoundHandlerWndProc(HWND hWnd, UINT message,
127 WPARAM wParam, LPARAM WXUNUSED(lParam))
128 {
129 wxSoundStreamWin *sndwin;
130
131 sndwin = wxFindSoundFromHandle((WXHWND)hWnd);
132 if (!sndwin)
133 return (LRESULT)0;
134
135 switch (message) {
136 case MM_WOM_DONE:
137 sndwin->NotifyDoneBuffer(wParam, wxSOUND_OUTPUT);
138 break;
139 case MM_WIM_DATA:
140 sndwin->NotifyDoneBuffer(wParam, wxSOUND_INPUT);
141 break;
142 default:
143 break;
144 }
145 return (LRESULT)0;
146 }
147
148 // -----------------------------------------------------------------------
149 // CreateSndWindow() creates an hidden window which will receive the sound
150 // events
151 // -----------------------------------------------------------------------
152
153 void wxSoundStreamWin::CreateSndWindow()
154 {
155 FARPROC proc = MakeProcInstance((FARPROC)_wxSoundHandlerWndProc,
156 wxGetInstance());
157 // NB: class name must be kept in sync with wxCanvasClassName in
158 // src/msw/app.cpp!
159 m_internal->m_sndWin = ::CreateWindow(wxT("wxWindowClass"), NULL, 0,
160 0, 0, 0, 0, NULL, (HMENU) NULL,
161 wxGetInstance(), NULL);
162
163 GetLastError();
164
165 ::SetWindowLong(m_internal->m_sndWin, GWL_WNDPROC, (LONG)proc);
166
167 // Add this window to the sound handle list so we'll be able to redecode
168 // the "magic" number.
169 wxSoundHandleList->Append((long)m_internal->m_sndWin, (wxObject *)this);
170 }
171
172 // -----------------------------------------------------------------------
173 // DestroySndWindow() destroys the hidden window
174 // -----------------------------------------------------------------------
175
176 void wxSoundStreamWin::DestroySndWindow()
177 {
178 if (m_internal->m_sndWin) {
179 ::DestroyWindow(m_internal->m_sndWin);
180 wxSoundHandleList->DeleteObject((wxObject *)this);
181 }
182 }
183
184 // -------------------------------------------------------------------------
185 // OpenDevice(int mode) initializes the windows driver for a "mode"
186 // operation. mode is a bit mask: if the bit "wxSOUND_OUTPUT" is set,
187 // the driver is opened for output operation, and if the bit "wxSOUND_INPUT"
188 // is set, then the driver is opened for input operation. The two modes
189 // aren't exclusive.
190 // The initialization parameters (sample rate, ...) are taken from the
191 // m_sndformat object.
192 // At the end, OpenDevice() calls AllocHeaders() to initialize the Sound IO
193 // queue.
194 // -------------------------------------------------------------------------
195 bool wxSoundStreamWin::OpenDevice(int mode)
196 {
197 wxSoundFormatPcm *pcm;
198 WAVEFORMATEX wformat;
199
200 if (!m_sndformat) {
201 m_snderror = wxSOUND_INVFRMT;
202 return false;
203 }
204
205 pcm = (wxSoundFormatPcm *)m_sndformat;
206
207 wformat.wFormatTag = WAVE_FORMAT_PCM;
208 wformat.nChannels = pcm->GetChannels();
209 wformat.nBlockAlign = wformat.nChannels * pcm->GetBPS() / 8;
210 wformat.nSamplesPerSec = pcm->GetSampleRate();
211 wformat.nAvgBytesPerSec = wformat.nSamplesPerSec * wformat.nBlockAlign;
212 wformat.wBitsPerSample = pcm->GetBPS();
213 wformat.cbSize = 0;
214
215 // -----------------------------------
216 // Open the driver for Output operation
217 // -----------------------------------
218 if (mode & wxSOUND_OUTPUT) {
219 MMRESULT result;
220
221 result = waveOutOpen(&m_internal->m_devout,
222 WAVE_MAPPER, &wformat,
223 (DWORD)m_internal->m_sndWin, 0,
224 CALLBACK_WINDOW);
225
226 if (result != MMSYSERR_NOERROR) {
227 m_snderror = wxSOUND_INVDEV;
228 return false;
229 }
230
231 m_output_frag_out = WXSOUND_MAX_QUEUE-1;
232 m_current_frag_out = 0;
233
234 m_internal->m_output_enabled = true;
235 }
236 // -----------------------------------
237 // Open the driver for Input operation
238 // -----------------------------------
239 if (mode & wxSOUND_INPUT) {
240 MMRESULT result;
241
242 result = waveInOpen(&m_internal->m_devin,
243 WAVE_MAPPER, &wformat,
244 (DWORD)m_internal->m_sndWin, 0,
245 CALLBACK_WINDOW);
246
247 if (result != MMSYSERR_NOERROR) {
248 m_snderror = wxSOUND_INVDEV;
249 return false;
250 }
251
252 m_current_frag_in = WXSOUND_MAX_QUEUE-1;
253 m_input_frag_in = 0;
254
255 m_internal->m_input_enabled = true;
256 }
257
258 if (mode & wxSOUND_OUTPUT) {
259 if (!AllocHeaders(wxSOUND_OUTPUT)) {
260 CloseDevice();
261 return false;
262 }
263 }
264 if (mode & wxSOUND_INPUT) {
265 if (!AllocHeaders(wxSOUND_INPUT)) {
266 CloseDevice();
267 return false;
268 }
269 }
270
271 return true;
272 }
273
274 // -------------------------------------------------------------------------
275 // CloseDevice() closes the driver handles and frees memory allocated for
276 // IO queues.
277 // -------------------------------------------------------------------------
278 void wxSoundStreamWin::CloseDevice()
279 {
280 if (m_internal->m_output_enabled) {
281 FreeHeaders(wxSOUND_OUTPUT);
282 m_internal->m_output_enabled = false;
283 waveOutClose(m_internal->m_devout);
284 }
285
286 if (m_internal->m_input_enabled) {
287 FreeHeaders(wxSOUND_INPUT);
288 m_internal->m_input_enabled = false;
289 waveInClose(m_internal->m_devin);
290 }
291 }
292
293 // -------------------------------------------------------------------------
294 // AllocHeader(int mode)
295 //
296 // mode has the same mean as in OpenDevice() except that here the two flags
297 // must be exclusive.
298 // AllocHeader() initializes an element of an operation (this can be input
299 // or output). It means it allocates the sound header's memory block
300 // and "prepares" it (It is needed by Windows). At the same time, it sets
301 // private datas so we can the header's owner (See callback).
302 //
303 // It returns the new allocated block or NULL.
304 // -------------------------------------------------------------------------
305 wxSoundInfoHeader *wxSoundStreamWin::AllocHeader(int mode)
306 {
307 wxSoundInfoHeader *info;
308 WAVEHDR *header;
309
310 // Some memory allocation
311 info = new wxSoundInfoHeader;
312 info->m_h_data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, GetBestSize());
313 info->m_h_header = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
314 if (!info->m_h_data || !info->m_h_header) {
315 delete info;
316 m_snderror = wxSOUND_MEMERROR;
317 return NULL;
318 }
319
320 // Get the two pointers from the system
321 info->m_data = (char *)GlobalLock(info->m_h_data);
322 info->m_header = (WAVEHDR *)GlobalLock(info->m_h_header);
323 // Set the header's mode
324 info->m_mode = mode;
325 // Set the parent of the header
326 info->m_driver = this;
327 // Clean it up
328 ClearHeader(info);
329
330 header = info->m_header;
331 // Initialize Windows variables
332 header->lpData = info->m_data;
333 header->dwBufferLength = GetBestSize();
334 header->dwUser = (DWORD)info;
335 header->dwFlags = WHDR_DONE;
336
337 // "Prepare" the header
338 if (mode == wxSOUND_INPUT) {
339 MMRESULT result;
340
341 result = waveInPrepareHeader(m_internal->m_devin, header,
342 sizeof(WAVEHDR));
343
344 if (result != MMSYSERR_NOERROR) {
345 // If something goes wrong, free everything.
346 GlobalUnlock(info->m_data);
347 GlobalUnlock(info->m_header);
348 GlobalFree(info->m_h_data);
349 GlobalFree(info->m_h_header);
350 delete info;
351
352 m_snderror = wxSOUND_IOERROR;
353 return NULL;
354 }
355 } else if (mode == wxSOUND_OUTPUT) {
356 MMRESULT result;
357
358 result = waveOutPrepareHeader(m_internal->m_devout, header,
359 sizeof(WAVEHDR));
360
361 if (result != MMSYSERR_NOERROR) {
362 // If something goes wrong, free everything.
363 GlobalUnlock(info->m_data);
364 GlobalUnlock(info->m_header);
365 GlobalFree(info->m_h_data);
366 GlobalFree(info->m_h_header);
367 delete info;
368
369 m_snderror = wxSOUND_IOERROR;
370 return NULL;
371 }
372 }
373 return info;
374 }
375
376 // -------------------------------------------------------------------------
377 // AllocHeaders(int mode)
378 //
379 // "mode" has the same mean as for OpenDevice() except that the two flags must
380 // be exclusive.
381 // AllocHeaders() allocates WXSOUND_MAX_QUEUE (= 128) blocks for an operation
382 // queue. It uses AllocHeader() for each element.
383 //
384 // Once it has allocated all blocks, it returns true and if an error occured
385 // it returns false.
386 // -------------------------------------------------------------------------
387 bool wxSoundStreamWin::AllocHeaders(int mode)
388 {
389 int i;
390 wxSoundInfoHeader **headers;
391
392 if (mode == wxSOUND_OUTPUT)
393 headers = m_headers_play = new wxSoundInfoHeader *[WXSOUND_MAX_QUEUE];
394 else
395 headers = m_headers_rec = new wxSoundInfoHeader *[WXSOUND_MAX_QUEUE];
396
397 memset(headers, 0, WXSOUND_MAX_QUEUE*sizeof(wxSoundInfoHeader *));
398
399 for (i=0;i<WXSOUND_MAX_QUEUE;i++) {
400 headers[i] = AllocHeader(mode);
401 if (!headers[i]) {
402 FreeHeaders(mode);
403 return false;
404 }
405 }
406 return true;
407 }
408
409 // -------------------------------------------------------------------------
410 // FreeHeader(int mode)
411 //
412 // "mode" has the same mean as for OpenDevice() except that the two flags must
413 // be exclusive.
414 // FreeHeader() frees a memory block and "unprepares" it.
415 // -------------------------------------------------------------------------
416 void wxSoundStreamWin::FreeHeader(wxSoundInfoHeader *header, int mode)
417 {
418 if (mode == wxSOUND_OUTPUT)
419 waveOutUnprepareHeader(m_internal->m_devout, header->m_header, sizeof(WAVEHDR));
420 else
421 waveInUnprepareHeader(m_internal->m_devin, header->m_header, sizeof(WAVEHDR));
422
423 GlobalUnlock(header->m_data);
424 GlobalUnlock(header->m_header);
425 GlobalFree(header->m_h_header);
426 GlobalFree(header->m_h_data);
427 delete header;
428 }
429
430 // -------------------------------------------------------------------------
431 // FreeHeaders(int mode)
432 //
433 // "mode" has the same mean as for OpenDevice() except that the two flags must
434 // be exclusive.
435 // FreeHeaders() frees all an operation queue once it has checked that
436 // all buffers have been terminated.
437 // -------------------------------------------------------------------------
438 void wxSoundStreamWin::FreeHeaders(int mode)
439 {
440 int i;
441 wxSoundInfoHeader ***headers;
442
443 if (mode == wxSOUND_OUTPUT)
444 headers = &m_headers_play;
445 else
446 headers = &m_headers_rec;
447
448 for (i=0;i<WXSOUND_MAX_QUEUE;i++) {
449 if ((*headers)[i]) {
450 // We wait for the end of the buffer
451 WaitFor((*headers)[i]);
452 // Then, we free the header
453 FreeHeader((*headers)[i], mode);
454 }
455 }
456 delete[] (*headers);
457 (*headers) = NULL;
458 }
459
460 // -------------------------------------------------------------------------
461 // WaitFor(wxSoundInfoHeader *info)
462 //
463 // "info" is one element of an IO queue
464 // WaitFor() checks whether the specified block has been terminated.
465 // If it hasn't been terminated, it waits for its termination.
466 //
467 // NB: if it's a partially filled buffer it adds it to the Windows queue
468 // -------------------------------------------------------------------------
469 void wxSoundStreamWin::WaitFor(wxSoundInfoHeader *info)
470 {
471 // If the buffer is finished, we return immediately
472 if (!info->m_playing) {
473
474 // We begun filling it: we must send it to the Windows queue
475 if (info->m_position != 0) {
476 memset(info->m_data + info->m_position, 0, info->m_size);
477 AddToQueue(info);
478 }
479 }
480
481 if (m_waiting_for) {
482 // PROBLEM //
483 return;
484 }
485 m_waiting_for = true;
486 // Else, we wait for its termination
487 while (info->m_playing || info->m_recording)
488 wxYield();
489 m_waiting_for = false;
490 }
491
492 // -------------------------------------------------------------------------
493 // AddToQueue(wxSoundInfoHeader *info)
494 //
495 // For "info", see WaitFor()
496 // AddToQueue() sends the IO queue element to the Windows queue.
497 //
498 // Warning: in the current implementation, it partially assume we send the
499 // element in the right order. This is true in that implementation but if
500 // you use it elsewhere, be careful: it may shuffle all your sound datas.
501 // -------------------------------------------------------------------------
502 bool wxSoundStreamWin::AddToQueue(wxSoundInfoHeader *info)
503 {
504 MMRESULT result;
505
506 if (info->m_mode == wxSOUND_INPUT) {
507 // Increment the input fragment pointer
508 result = waveInAddBuffer(m_internal->m_devin,
509 info->m_header, sizeof(WAVEHDR));
510 if (result == MMSYSERR_NOERROR)
511 info->m_recording = true;
512 else
513 return false;
514 } else if (info->m_mode == wxSOUND_OUTPUT) {
515 result = waveOutWrite(m_internal->m_devout,
516 info->m_header, sizeof(WAVEHDR));
517 if (result == MMSYSERR_NOERROR)
518 info->m_playing = true;
519 else
520 return false;
521 }
522 return true;
523 }
524
525 // -------------------------------------------------------------------------
526 // ClearHeader(wxSoundInfoHeader *info)
527 //
528 // ClearHeader() reinitializes the parameters of "info" to their default
529 // value.
530 // -------------------------------------------------------------------------
531 void wxSoundStreamWin::ClearHeader(wxSoundInfoHeader *info)
532 {
533 info->m_playing = false;
534 info->m_recording = false;
535 info->m_position = 0;
536 info->m_size = GetBestSize();
537 }
538
539 // -------------------------------------------------------------------------
540 // wxSoundInfoHeader *NextFragmentOutput()
541 //
542 // NextFragmentOutput() looks for a free output block. It will always
543 // return you a non-NULL pointer but it may waits for an empty buffer a long
544 // time.
545 // -------------------------------------------------------------------------
546 wxSoundInfoHeader *wxSoundStreamWin::NextFragmentOutput()
547 {
548 if (m_headers_play[m_current_frag_out]->m_playing) {
549 m_current_frag_out = (m_current_frag_out + 1) % WXSOUND_MAX_QUEUE;
550
551 if (m_headers_play[m_current_frag_out]->m_playing)
552 WaitFor(m_headers_play[m_current_frag_out]);
553 }
554 if (m_current_frag_out == m_output_frag_out)
555 m_queue_filled = true;
556 return m_headers_play[m_current_frag_out];
557 }
558
559 // -------------------------------------------------------------------------
560 // The behaviour of Write is documented in the global documentation.
561 // -------------------------------------------------------------------------
562 wxSoundStream& wxSoundStreamWin::Write(const void *buffer, wxUint32 len)
563 {
564 m_lastcount = 0;
565 if (!m_internal->m_output_enabled) {
566 m_snderror = wxSOUND_NOTSTARTED;
567 return *this;
568 }
569
570
571 while (len > 0) {
572 wxSoundInfoHeader *header;
573 wxUint32 to_copy;
574
575 // Get a new output fragment
576 header = NextFragmentOutput();
577
578 to_copy = (len > header->m_size) ? header->m_size : len;
579 memcpy(header->m_data + header->m_position, buffer, to_copy);
580
581 header->m_position += to_copy;
582 header->m_size -= to_copy;
583 buffer = (((const char *)buffer) + to_copy);
584 len -= to_copy;
585 m_lastcount += to_copy;
586
587 // If the fragment is full, we send it to the Windows queue.
588 if (header->m_size == 0)
589 if (!AddToQueue(header)) {
590 m_snderror = wxSOUND_IOERROR;
591 return *this;
592 }
593 }
594 return *this;
595 }
596
597 // -------------------------------------------------------------------------
598 // NextFragmentInput is not functional.
599 // -------------------------------------------------------------------------
600 wxSoundInfoHeader *wxSoundStreamWin::NextFragmentInput()
601 {
602 wxSoundInfoHeader *header;
603
604 // Queue pointer: reader
605 m_current_frag_in = (m_current_frag_in + 1) % WXSOUND_MAX_QUEUE;
606
607 header = m_headers_rec[m_current_frag_in];
608 // If the current buffer is in recording mode, we must wait for its
609 // completion.
610 if (header->m_recording)
611 WaitFor(header);
612
613 // We reached the writer position: the queue is full.
614 if (m_current_frag_in == m_input_frag_in)
615 m_queue_filled = true;
616
617 return header;
618 }
619
620 // -------------------------------------------------------------------------
621 // The behaviour of Read is documented in the global documentation.
622 // -------------------------------------------------------------------------
623 wxSoundStream& wxSoundStreamWin::Read(void *buffer, wxUint32 len)
624 {
625 wxSoundInfoHeader *header;
626 wxUint32 to_copy;
627
628 m_lastcount = 0;
629 if (!m_internal->m_input_enabled)
630 return *this;
631
632 while (len > 0) {
633 header = NextFragmentInput();
634
635 to_copy = (len > header->m_size) ? header->m_size : len;
636 memcpy(buffer, header->m_data + header->m_position, to_copy);
637
638 header->m_position += to_copy;
639 header->m_size -= to_copy;
640 buffer = (((char *)buffer) + to_copy);
641 len -= to_copy;
642 m_lastcount += to_copy;
643
644 if (header->m_size == 0) {
645 ClearHeader(header);
646 if (!AddToQueue(header)) {
647 m_snderror = wxSOUND_IOERROR;
648 return *this;
649 }
650 }
651 }
652 return *this;
653 }
654
655 // -------------------------------------------------------------------------
656 // NotifyDoneBuffer(wxUint32 dev_handle)
657 //
658 // NotifyDoneBuffer() is called by wxSoundHandlerProc each time a sound
659 // fragment finished. It reinitializes the parameters of the fragment and
660 // sends an event to the clients.
661 // -------------------------------------------------------------------------
662 void wxSoundStreamWin::NotifyDoneBuffer(wxUint32 WXUNUSED(dev_handle), int flag)
663 {
664 wxSoundInfoHeader *info;
665
666 if (flag == wxSOUND_OUTPUT) {
667 if (!m_internal->m_output_enabled)
668 return;
669
670 // Queue pointer: reader
671 m_output_frag_out = (m_output_frag_out + 1) % WXSOUND_MAX_QUEUE;
672 info = m_headers_play[m_output_frag_out];
673 // Clear header to tell the system the buffer is free now
674 ClearHeader(info);
675 m_queue_filled = false;
676 if (!m_waiting_for)
677 // Try to requeue a new buffer.
678 OnSoundEvent(wxSOUND_OUTPUT);
679 } else {
680 if (!m_internal->m_input_enabled)
681 return;
682
683 // Recording completed
684 m_headers_rec[m_input_frag_in]->m_recording = false;
685 // Queue pointer: writer
686 m_input_frag_in = (m_input_frag_in + 1) % WXSOUND_MAX_QUEUE;
687 if (!m_waiting_for)
688 OnSoundEvent(wxSOUND_INPUT);
689 m_queue_filled = false;
690 }
691 }
692
693 // -------------------------------------------------------------------------
694 // SetSoundFormat()
695 // -------------------------------------------------------------------------
696 bool wxSoundStreamWin::SetSoundFormat(const wxSoundFormatBase& base)
697 {
698 // TODO: detect best format
699 return wxSoundStream::SetSoundFormat(base);
700 }
701
702 // -------------------------------------------------------------------------
703 // StartProduction()
704 // -------------------------------------------------------------------------
705 bool wxSoundStreamWin::StartProduction(int evt)
706 {
707 if (!m_internal)
708 return false;
709
710 if ((m_internal->m_output_enabled && (evt & wxSOUND_OUTPUT)) ||
711 (m_internal->m_input_enabled && (evt & wxSOUND_INPUT)))
712 CloseDevice();
713
714 if (!OpenDevice(evt))
715 return false;
716
717 m_production_started = true;
718 m_queue_filled = false;
719 // Send a dummy event to start.
720 if (evt & wxSOUND_OUTPUT)
721 OnSoundEvent(wxSOUND_OUTPUT);
722
723 if (evt & wxSOUND_INPUT) {
724 int i;
725 for (i=0;i<WXSOUND_MAX_QUEUE;i++)
726 AddToQueue(m_headers_rec[i]);
727
728 waveInStart(m_internal->m_devin);
729 }
730
731 return true;
732 }
733
734 // -------------------------------------------------------------------------
735 // StopProduction()
736 // ------------------------------------------------------------------------
737 bool wxSoundStreamWin::StopProduction()
738 {
739 if (!m_production_started) {
740 m_snderror = wxSOUND_NOTSTARTED;
741 return false;
742 }
743
744 m_snderror = wxSOUND_NOERROR;
745 m_production_started = false;
746 CloseDevice();
747 return true;
748 }
749
750 // -------------------------------------------------------------------------
751 // QueueFilled()
752 // -------------------------------------------------------------------------
753 bool wxSoundStreamWin::QueueFilled() const
754 {
755 return (!m_production_started || m_queue_filled);
756 }
757
758
759 // --------------------------------------------------------------------------
760 // wxSoundWinModule
761 // --------------------------------------------------------------------------
762
763 class wxSoundWinModule : public wxModule {
764 DECLARE_DYNAMIC_CLASS(wxSoundWinModule)
765 public:
766 bool OnInit();
767 void OnExit();
768 };
769
770 IMPLEMENT_DYNAMIC_CLASS(wxSoundWinModule, wxModule)
771
772 bool wxSoundWinModule::OnInit() {
773 wxSoundHandleList = new wxList(wxKEY_INTEGER);
774 return true;
775 }
776
777 void wxSoundWinModule::OnExit() {
778 delete wxSoundHandleList;
779 }
780
781 #endif
782 // __WINDOWS__