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