1 // --------------------------------------------------------------------------
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
7 // --------------------------------------------------------------------------
10 #include <wx/msw/private.h>
11 #include <wx/module.h>
20 typedef struct _wxSoundInternal wxSoundInternal
;
21 typedef struct _wxSoundInfoHeader wxSoundInfoHeader
;
23 extern char wxCanvasClassName
[];
25 wxList
*wxSoundHandleList
= NULL
;
27 static inline wxSoundStreamWin
*wxFindSoundFromHandle(WXHWND hWnd
)
29 wxNode
*node
= wxSoundHandleList
->Find((long)hWnd
);
32 return (wxSoundStreamWin
*)node
->Data();
35 struct _wxSoundInternal
{
39 bool m_output_enabled
, m_input_enabled
;
42 struct _wxSoundInfoHeader
{
43 HGLOBAL m_h_header
, m_h_data
;
47 bool m_playing
, m_recording
;
48 wxUint32 m_position
, m_size
;
50 wxSoundStreamWin
*m_driver
;
53 #define WXSOUND_MAX_QUEUE 128
55 wxSoundStreamWin::wxSoundStreamWin()
59 m_production_started
= FALSE
;
60 m_internal
= new wxSoundInternal
;
61 m_snderror
= wxSOUND_NOERR
;
67 if (!OpenDevice(wxSOUND_OUTPUT
))
73 wxSoundStreamWin::~wxSoundStreamWin()
75 if (m_production_started
)
82 LRESULT APIENTRY _EXPORT
_wxSoundHandlerWndProc(HWND hWnd
, UINT message
,
83 WPARAM wParam
, LPARAM lParam
)
87 wxFindSoundFromHandle((WXHWND
)hWnd
)->NotifyDoneBuffer(wParam
);
96 void wxSoundStreamWin::CreateSndWindow()
98 FARPROC proc
= MakeProcInstance((FARPROC
)_wxSoundHandlerWndProc
,
102 m_internal
->m_sndWin
= ::CreateWindow(wxCanvasClassName
, NULL
, 0,
103 0, 0, 0, 0, NULL
, (HMENU
) NULL
,
104 wxGetInstance(), NULL
);
106 error
= GetLastError();
107 wxPrintf("%d\n", error
);
109 ::SetWindowLong(m_internal
->m_sndWin
, GWL_WNDPROC
, (LONG
)proc
);
111 wxSoundHandleList
->Append((long)m_internal
->m_sndWin
, (wxObject
*)this);
114 void wxSoundStreamWin::DestroySndWindow()
116 if (m_internal
->m_sndWin
) {
117 ::DestroyWindow(m_internal
->m_sndWin
);
118 wxSoundHandleList
->DeleteObject((wxObject
*)this);
122 bool wxSoundStreamWin::OpenDevice(int mode
)
124 wxSoundFormatPcm
*pcm
;
125 WAVEFORMATEX wformat
;
128 m_snderror
= wxSOUND_INVFRMT
;
132 pcm
= (wxSoundFormatPcm
*)m_sndformat
;
134 wformat
.wFormatTag
= WAVE_FORMAT_PCM
;
135 wformat
.nChannels
= pcm
->GetChannels();
136 wformat
.nBlockAlign
= pcm
->GetBPS() / 8 * wformat
.nChannels
;
137 wformat
.nAvgBytesPerSec
= pcm
->GetBytesFromTime(1);
138 wformat
.nSamplesPerSec
= pcm
->GetSampleRate();
139 wformat
.wBitsPerSample
= pcm
->GetBPS();
142 if (mode
& wxSOUND_OUTPUT
) {
145 result
= waveOutOpen(&m_internal
->m_devout
,
146 WAVE_MAPPER
, &wformat
,
147 (DWORD
)m_internal
->m_sndWin
, 0,
150 if (result
!= MMSYSERR_NOERROR
) {
151 m_snderror
= wxSOUND_INVDEV
;
155 m_output_frag_out
= WXSOUND_MAX_QUEUE
-1;
156 m_current_frag_out
= 0;
158 m_internal
->m_output_enabled
= TRUE
;
160 if (mode
& wxSOUND_INPUT
) {
163 result
= waveInOpen(&m_internal
->m_devin
,
164 WAVE_MAPPER
, &wformat
,
165 (DWORD
)m_internal
->m_sndWin
, 0,
168 if (result
!= MMSYSERR_NOERROR
) {
169 m_snderror
= wxSOUND_INVDEV
;
173 m_input_frag_in
= WXSOUND_MAX_QUEUE
-1;
174 m_current_frag_in
= 0;
176 m_internal
->m_input_enabled
= TRUE
;
179 if (!AllocHeaders(mode
)) {
187 void wxSoundStreamWin::CloseDevice()
189 if (m_internal
->m_output_enabled
) {
190 FreeHeaders(wxSOUND_OUTPUT
);
191 waveOutReset(m_internal
->m_devout
);
192 waveOutClose(m_internal
->m_devout
);
195 if (m_internal
->m_input_enabled
) {
196 FreeHeaders(wxSOUND_INPUT
);
197 waveInReset(m_internal
->m_devin
);
198 waveInClose(m_internal
->m_devin
);
201 m_internal
->m_output_enabled
= FALSE
;
202 m_internal
->m_input_enabled
= FALSE
;
205 wxSoundInfoHeader
*wxSoundStreamWin::AllocHeader(int mode
)
207 wxSoundInfoHeader
*info
;
210 info
= new wxSoundInfoHeader
;
211 info
->m_h_data
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_SHARE
, GetBestSize());
212 info
->m_h_header
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_SHARE
, sizeof(WAVEHDR
));
213 if (!info
->m_h_data
|| !info
->m_h_header
) {
215 m_snderror
= wxSOUND_MEMERR
;
219 info
->m_data
= (char *)GlobalLock(info
->m_h_data
);
220 info
->m_header
= (WAVEHDR
*)GlobalLock(info
->m_h_header
);
222 info
->m_driver
= this;
225 header
= info
->m_header
;
227 header
->lpData
= info
->m_data
;
228 header
->dwBufferLength
= GetBestSize();
229 header
->dwUser
= (DWORD
)info
;
230 header
->dwFlags
= WHDR_DONE
;
232 if (mode
== wxSOUND_INPUT
) {
235 result
= waveInPrepareHeader(m_internal
->m_devin
, header
,
238 if (result
!= MMSYSERR_NOERROR
) {
239 GlobalUnlock(info
->m_data
);
240 GlobalUnlock(info
->m_header
);
241 GlobalFree(info
->m_h_data
);
242 GlobalFree(info
->m_h_header
);
245 m_snderror
= wxSOUND_IOERR
;
248 } else if (mode
== wxSOUND_OUTPUT
) {
251 result
= waveOutPrepareHeader(m_internal
->m_devout
, header
,
254 if (result
!= MMSYSERR_NOERROR
) {
255 GlobalUnlock(info
->m_data
);
256 GlobalUnlock(info
->m_header
);
257 GlobalFree(info
->m_h_data
);
258 GlobalFree(info
->m_h_header
);
261 m_snderror
= wxSOUND_IOERR
;
268 bool wxSoundStreamWin::AllocHeaders(int mode
)
271 wxSoundInfoHeader
**headers
;
273 if (mode
== wxSOUND_OUTPUT
)
274 headers
= m_headers_play
= new wxSoundInfoHeader
*[WXSOUND_MAX_QUEUE
];
276 headers
= m_headers_rec
= new wxSoundInfoHeader
*[WXSOUND_MAX_QUEUE
];
278 memset(headers
, 0, WXSOUND_MAX_QUEUE
*sizeof(wxSoundInfoHeader
*));
280 for (i
=0;i
<WXSOUND_MAX_QUEUE
;i
++) {
281 headers
[i
] = AllocHeader(mode
);
290 void wxSoundStreamWin::FreeHeader(wxSoundInfoHeader
*header
, int mode
)
292 if (mode
== wxSOUND_OUTPUT
)
293 waveOutUnprepareHeader(m_internal
->m_devout
, header
->m_header
, sizeof(WAVEHDR
));
295 waveInUnprepareHeader(m_internal
->m_devin
, header
->m_header
, sizeof(WAVEHDR
));
297 GlobalUnlock(header
->m_data
);
298 GlobalUnlock(header
->m_header
);
299 GlobalFree(header
->m_h_header
);
300 GlobalFree(header
->m_h_data
);
304 void wxSoundStreamWin::FreeHeaders(int mode
)
307 wxSoundInfoHeader
***headers
;
309 if (mode
== wxSOUND_OUTPUT
)
310 headers
= &m_headers_play
;
312 headers
= &m_headers_rec
;
314 for (i
=0;i
<WXSOUND_MAX_QUEUE
;i
++) {
316 WaitFor((*headers
)[i
]);
317 FreeHeader((*headers
)[i
], mode
);
324 void wxSoundStreamWin::WaitFor(wxSoundInfoHeader
*info
)
326 if (info
->m_position
!= 0) {
327 memset(info
->m_data
+ info
->m_position
, 0, info
->m_size
);
331 if (!info
->m_playing
&& !info
->m_recording
)
334 while (info
->m_playing
|| info
->m_recording
)
338 bool wxSoundStreamWin::AddToQueue(wxSoundInfoHeader
*info
)
342 if (info
->m_mode
== wxSOUND_INPUT
) {
343 m_current_frag_in
= (m_current_frag_in
+ 1) % WXSOUND_MAX_QUEUE
;
344 result
= waveInAddBuffer(m_internal
->m_devin
,
345 info
->m_header
, sizeof(WAVEHDR
));
346 if (result
== MMSYSERR_NOERROR
)
347 info
->m_recording
= TRUE
;
350 } else if (info
->m_mode
== wxSOUND_OUTPUT
) {
351 result
= waveOutWrite(m_internal
->m_devout
,
352 info
->m_header
, sizeof(WAVEHDR
));
353 if (result
== MMSYSERR_NOERROR
)
354 info
->m_playing
= TRUE
;
361 void wxSoundStreamWin::ClearHeader(wxSoundInfoHeader
*info
)
363 info
->m_playing
= FALSE
;
364 info
->m_recording
= FALSE
;
365 info
->m_position
= 0;
366 info
->m_size
= GetBestSize();
369 wxSoundInfoHeader
*wxSoundStreamWin::NextFragmentOutput()
371 if (m_headers_play
[m_current_frag_out
]->m_playing
) {
372 m_current_frag_out
= (m_current_frag_out
+ 1) % WXSOUND_MAX_QUEUE
;
374 if (m_headers_play
[m_current_frag_out
]->m_playing
)
375 WaitFor(m_headers_play
[m_current_frag_out
]);
377 if (m_current_frag_out
== m_output_frag_out
)
378 m_queue_filled
= TRUE
;
379 return m_headers_play
[m_current_frag_out
];
382 wxSoundStream
& wxSoundStreamWin::Write(const void *buffer
, size_t len
)
385 if (!m_internal
->m_output_enabled
)
389 wxSoundInfoHeader
*header
;
392 header
= NextFragmentOutput();
394 to_copy
= (len
> header
->m_size
) ? header
->m_size
: len
;
395 memcpy(header
->m_data
+ header
->m_position
, buffer
, to_copy
);
397 header
->m_position
+= to_copy
;
398 header
->m_size
-= to_copy
;
399 buffer
= (((const char *)buffer
) + to_copy
);
401 m_lastcount
+= to_copy
;
403 if (header
->m_size
== 0)
404 if (!AddToQueue(header
)) {
405 m_snderror
= wxSOUND_IOERR
;
412 wxSoundInfoHeader
*wxSoundStreamWin::NextFragmentInput()
414 wxSoundInfoHeader
*header
;
417 header
= m_headers_rec
[m_current_frag_in
];
420 if (m_current_frag_in
== m_input_frag_in
)
421 m_queue_filled
= TRUE
;
426 wxSoundStream
& wxSoundStreamWin::Read(void *buffer
, size_t len
)
428 wxSoundInfoHeader
*header
;
432 if (!m_internal
->m_input_enabled
)
436 header
= NextFragmentInput();
438 to_copy
= (len
> header
->m_size
) ? header
->m_size
: len
;
439 memcpy(buffer
, header
->m_data
+ header
->m_position
, to_copy
);
441 header
->m_position
+= to_copy
;
442 header
->m_size
-= to_copy
;
443 buffer
= (((char *)buffer
) + to_copy
);
445 m_lastcount
+= to_copy
;
447 if (header
->m_size
== 0) {
449 if (!AddToQueue(header
)) {
450 m_snderror
= wxSOUND_IOERR
;
458 void wxSoundStreamWin::NotifyDoneBuffer(wxUint32 dev_handle
)
460 wxSoundInfoHeader
*info
;
462 if (dev_handle
== (wxUint32
)m_internal
->m_devout
) {
463 m_output_frag_out
= (m_output_frag_out
+ 1) % WXSOUND_MAX_QUEUE
;
464 info
= m_headers_play
[m_output_frag_out
];
466 m_queue_filled
= FALSE
;
467 OnSoundEvent(wxSOUND_OUTPUT
);
469 m_input_frag_in
= (m_input_frag_in
+ 1) % WXSOUND_MAX_QUEUE
;
470 OnSoundEvent(wxSOUND_INPUT
);
471 m_queue_filled
= FALSE
;
475 bool wxSoundStreamWin::SetSoundFormat(wxSoundFormatBase
& base
)
477 return wxSoundStream::SetSoundFormat(base
);
480 bool wxSoundStreamWin::StartProduction(int evt
)
482 if ((m_internal
->m_output_enabled
&& (evt
& wxSOUND_OUTPUT
)) ||
483 (m_internal
->m_input_enabled
&& (evt
& wxSOUND_INPUT
)))
486 if (!OpenDevice(evt
))
489 m_production_started
= TRUE
;
490 m_queue_filled
= FALSE
;
491 // Send a dummy event to start.
492 if (evt
& wxSOUND_OUTPUT
)
495 if (evt
& wxSOUND_INPUT
) {
497 for (i
=0;i
<WXSOUND_MAX_QUEUE
;i
++)
498 AddToQueue(m_headers_rec
[i
]);
504 bool wxSoundStreamWin::StopProduction()
506 m_production_started
= FALSE
;
511 bool wxSoundStreamWin::QueueFilled() const
513 return (!m_production_started
|| m_queue_filled
);
517 // --------------------------------------------------------------------------
519 // --------------------------------------------------------------------------
521 class WXDLLEXPORT wxSoundWinModule
: public wxModule
{
522 DECLARE_DYNAMIC_CLASS(wxSoundWinModule
)
528 IMPLEMENT_DYNAMIC_CLASS(wxSoundWinModule
, wxModule
)
530 bool wxSoundWinModule::OnInit() {
531 wxSoundHandleList
= new wxList(wxKEY_INTEGER
);
535 void wxSoundWinModule::OnExit() {
536 delete wxSoundHandleList
;