]> git.saurik.com Git - wxWidgets.git/blob - utils/wxMMedia/sndwin.cpp
* Stream: update in doc, fix in code.
[wxWidgets.git] / utils / wxMMedia / sndwin.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2 // Name: sndwin.cpp
3 // Purpose: wxMMedia
4 // Author: Guilhem Lavaux
5 // Created: 1997
6 // Updated: 1998
7 // Copyright: (C) 1997, 1998, Guilhem Lavaux
8 // License: wxWindows license
9 ////////////////////////////////////////////////////////////////////////////////
10 #ifdef WX_PRECOMP
11 #include "wx/wxprec.h"
12 #else
13 #include "wx/wx.h"
14 #endif
15 #include <wx/msw/private.h>
16
17 #define WXMMEDIA_INTERNAL
18 #include "sndwin.h"
19
20 #define MMD_WIN_IO_BSIZE 16384
21
22 #include <mmsystem.h>
23
24 #ifdef __BORLANDC__
25 #pragma hdrstop
26 #endif
27
28 wxSndWinFragment::wxSndWinFragment(wxSound& io_drv)
29 : wxFragmentBuffer(io_drv)
30 {
31 }
32
33 wxSndWinFragment::~wxSndWinFragment(void)
34 {
35 }
36
37 void wxSndWinFragment::AllocIOBuffer(void)
38 {
39 wxWinSound *w_snd = (wxWinSound *) m_iodrv;
40 wxUint8 i;
41
42 m_maxoq = 5;
43 m_maxiq = 5;
44
45 m_lstoptrs = new wxFragBufPtr[m_maxoq];
46 m_lstiptrs = new wxFragBufPtr[m_maxiq];
47
48 for (i=0;i<m_maxoq;i++) {
49 m_lstoptrs[i].buffers = new wxList();
50 m_lstoptrs[i].state = wxBUFFER_FREE;
51
52 w_snd->PrepareHeader(m_lstoptrs[i], wxSND_OUTPUT);
53 }
54
55 for (i=0;i<m_maxiq;i++) {
56 m_lstiptrs[i].size = MMD_WIN_IO_BSIZE;
57 m_lstiptrs[i].ptr = 0;
58 m_lstiptrs[i].buffers = new wxList();
59 m_lstiptrs[i].state = wxBUFFER_FREE;
60
61 w_snd->PrepareHeader(m_lstiptrs[i], wxSND_INPUT);
62 }
63 }
64
65 void wxSndWinFragment::FreeIOBuffer(void)
66 {
67 wxWinSound *w_snd = (wxWinSound *)m_iodrv;
68 wxUint8 i;
69
70 if (!m_lstoptrs && !m_lstiptrs)
71 return;
72
73 for (i=0;i<m_maxoq;i++) {
74 w_snd->UnprepareHeader(m_lstoptrs[i], wxSND_OUTPUT);
75 delete m_lstoptrs[i].buffers;
76 }
77
78 for (i=0;i<m_maxiq;i++) {
79 w_snd->UnprepareHeader(m_lstiptrs[i], wxSND_INPUT);
80 delete m_lstiptrs[i].buffers;
81 }
82
83 delete[] m_lstoptrs;
84 delete[] m_lstiptrs;
85
86 m_lstoptrs = m_lstiptrs = NULL;
87 m_maxoq = m_maxiq = 0;
88 }
89
90 void wxSndWinFragment::WaitForAll()
91 {
92 bool buf_busy = TRUE;
93 int i;
94
95 m_dontq = TRUE;
96
97 while (buf_busy) {
98 buf_busy = FALSE;
99
100 for (i=0;i<m_maxoq;i++) {
101 if (m_lstoptrs[i].state == wxBUFFER_FFILLED) {
102 buf_busy = TRUE;
103 break;
104 }
105 }
106 wxYield();
107 }
108
109 m_dontq = FALSE;
110 FreeBufToFree(TRUE);
111 }
112
113 bool wxSndWinFragment::OnBufferFilled(wxFragBufPtr *ptr, wxSndMode mode)
114 {
115 wxSndWinInfo *info = (wxSndWinInfo *)ptr->user_data;
116 wxWinSound *w_snd = (wxWinSound *)m_iodrv;
117 MMRESULT result;
118
119 switch (mode) {
120 case wxSND_INPUT:
121 result = waveInAddBuffer(w_snd->internal->devin_id, info->hdr,
122 sizeof(WAVEHDR));
123 break;
124 case wxSND_OUTPUT:
125 result = waveOutWrite(w_snd->internal->devout_id, info->hdr,
126 sizeof(WAVEHDR));
127 printf("WINOUT: result=%d\n", result);
128 break;
129 }
130 return TRUE;
131 }
132
133 wxWinSound::wxWinSound(void)
134 : wxSound(),
135 fragments(*this)
136 {
137 internal = new wxWinSoundInternal;
138 internal->devout_id = 0;
139 internal->devin_id = 0;
140 internal->sndWin = 0;
141
142 wout_opened = FALSE;
143 win_opened = FALSE;
144 curr_o_srate = (wxUint32)-1;
145 curr_o_bps = (wxUint8)-1;
146 curr_o_stereo = (bool)-1;
147 curr_i_srate = (wxUint32)-1;
148 curr_i_bps = (wxUint8)-1;
149 curr_i_stereo = (bool)-1;
150 }
151
152 wxWinSound::~wxWinSound(void)
153 {
154 int i;
155
156 fragments.WaitForAll();
157
158 if (wout_opened)
159 waveOutReset(internal->devout_id);
160 if (win_opened)
161 waveInReset(internal->devout_id);
162
163 fragments.FreeIOBuffer();
164
165 if (wout_opened)
166 waveOutClose(internal->devout_id);
167 if (win_opened)
168 waveInClose(internal->devin_id);
169
170 if (internal->sndWin)
171 ::DestroyWindow(internal->sndWin);
172
173 delete internal;
174 }
175
176 bool wxWinSound::Wakeup(wxSndBuffer& buf)
177 {
178 if (!Reopen(buf, FALSE)) {
179 buf.Clear(wxSND_BUFLOCKED);
180 return FALSE;
181 }
182
183 fragments.OnBufferFinished(NULL);
184 return TRUE;
185 }
186
187 void wxWinSound::PrepareHeader(wxFragmentBuffer::wxFragBufPtr& frag,
188 wxSndMode mode)
189 {
190 wxSndWinInfo *info;
191 WAVEHDR *hdr;
192
193 if ((mode == wxSND_INPUT && !win_opened) ||
194 (mode == wxSND_OUTPUT && !wout_opened))
195 return;
196
197 info = new wxSndWinInfo;
198
199 info->h_data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, MMD_WIN_IO_BSIZE);
200 info->h_hdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
201
202 info->data = (char *)GlobalLock(info->h_data);
203 hdr = info->hdr = (WAVEHDR *)GlobalLock(info->h_hdr);
204
205 memset(hdr, 0, sizeof(*hdr));
206 hdr->lpData = info->data;
207 hdr->dwBufferLength = frag.size;
208 hdr->dwUser = (DWORD)&frag;
209 hdr->dwFlags = WHDR_DONE;
210
211 if (mode == wxSND_INPUT) {
212 MMRESULT result = waveInPrepareHeader(internal->devin_id, hdr,
213 sizeof(WAVEHDR));
214
215 if (result != MMSYSERR_NOERROR)
216 wxExit();
217 } else {
218 MMRESULT result = waveOutPrepareHeader(internal->devout_id, hdr,
219 sizeof(WAVEHDR));
220 if (result != MMSYSERR_NOERROR)
221 wxExit();
222 }
223
224 frag.sndbuf = new wxStreamBuffer();
225 frag.sndbuf->SetBufferIO(info->data, info->data + MMD_WIN_IO_BSIZE);
226 frag.user_data = (char *)info;
227 }
228
229 void wxWinSound::UnprepareHeader(wxFragmentBuffer::wxFragBufPtr& frag,
230 wxSndMode mode)
231 {
232 wxSndWinInfo *info = (wxSndWinInfo *)frag.user_data;
233
234 if ((mode == wxSND_INPUT && !win_opened) ||
235 (mode == wxSND_OUTPUT && !wout_opened))
236 return;
237
238 MMRESULT result;
239
240 if (mode == wxSND_INPUT) {
241 result = waveInUnprepareHeader(internal->devin_id, info->hdr, sizeof(*info->hdr));
242 } else {
243 result = waveOutUnprepareHeader(internal->devout_id, info->hdr, sizeof(*info->hdr));
244 }
245
246 delete frag.sndbuf;
247
248 printf("unprepare = %d\n", result);
249
250 GlobalUnlock(info->h_hdr);
251 GlobalUnlock(info->h_data);
252
253 GlobalFree(info->h_hdr);
254 GlobalFree(info->h_data);
255
256 delete info;
257 }
258
259 extern char wxCanvasClassName[];
260
261 LRESULT APIENTRY _EXPORT wxSoundHandlerWndProc(HWND hWnd, UINT message,
262 WPARAM wParam, LPARAM lParam)
263 {
264 switch (message) {
265 case MM_WOM_DONE: {
266 wxWinSound *snd_drv = (wxWinSound *)GetWindowLong(hWnd, GWL_USERDATA);
267 WAVEHDR *hdr = (WAVEHDR *)lParam;
268 wxFragmentBuffer::wxFragBufPtr *buf =
269 (wxFragmentBuffer::wxFragBufPtr *)hdr->dwUser;
270
271 // To be sure ...
272 hdr->dwFlags |= WHDR_DONE;
273
274 snd_drv->fragments.OnBufferFinished(buf);
275 break;
276 }
277 case MM_WOM_OPEN:
278 printf("wave Open ack\n");
279 break;
280 case MM_WOM_CLOSE:
281 printf("wave Close ack\n");
282 break;
283 default:
284 // TODO: Useful ?
285 return DefWindowProc(hWnd, message, wParam, lParam);
286 }
287 return (LRESULT)0;
288 }
289
290 void wxWinSound::StopBuffer(wxSndBuffer& buf)
291 {
292 buf.HardLock();
293 buf.Set(wxSND_BUFSTOP);
294 fragments.AbortBuffer(buf);
295 buf.HardUnlock();
296
297 while (buf.IsSet(wxSND_BUFSTOP))
298 wxYield();
299 }
300
301 bool wxWinSound::Reopen(wxSndBuffer& buf, bool force)
302 {
303 WAVEFORMATEX wformat;
304
305 if ((buf.GetSampleRate() != curr_o_srate) ||
306 (buf.GetBps() != curr_o_bps) ||
307 (buf.GetStereo() != curr_o_stereo) ||
308 (buf.GetMode() != curr_mode))
309 force = TRUE;
310
311 if (force) {
312 wxUint32 *curr_srate =
313 (buf.GetMode() == wxSND_OUTPUT) ? &curr_o_srate : &curr_i_srate;
314 wxUint8 *curr_bps =
315 (buf.GetMode() == wxSND_OUTPUT) ? &curr_o_bps : &curr_i_bps;
316 bool *curr_stereo =
317 (buf.GetMode() == wxSND_OUTPUT) ? &curr_o_stereo : &curr_i_stereo;
318
319 fragments.WaitForAll();
320 fragments.FreeIOBuffer();
321
322 if (!internal->sndWin) {
323 FARPROC proc = MakeProcInstance((FARPROC)wxSoundHandlerWndProc, wxGetInstance());
324
325 internal->sndWin = ::CreateWindow(wxCanvasClassName, NULL, 0,
326 0, 0, 0, 0, NULL, (HMENU) NULL,
327 wxGetInstance(), 0);
328
329 ::SetWindowLong(internal->sndWin, GWL_WNDPROC,
330 (LONG)proc);
331 ::SetWindowLong(internal->sndWin, GWL_USERDATA, (LONG) this);
332 }
333
334 if (wout_opened) {
335 waveOutClose(internal->devout_id);
336 wout_opened = FALSE;
337 }
338 if (win_opened) {
339 waveInClose(internal->devin_id);
340 win_opened = FALSE;
341 }
342
343 *curr_srate = buf.GetSampleRate();
344 *curr_bps = buf.GetBps();
345 *curr_stereo = buf.GetStereo();
346 wformat.wFormatTag = WAVE_FORMAT_PCM;
347 wformat.nChannels = curr_o_stereo+1;
348
349 wformat.nSamplesPerSec = curr_o_srate;
350 wformat.nBlockAlign = curr_o_bps / 8 * wformat.nChannels;
351 wformat.nAvgBytesPerSec =
352 wformat.nSamplesPerSec * wformat.nBlockAlign;
353 wformat.wBitsPerSample = curr_o_bps;
354 wformat.cbSize = 0;
355
356 if (buf.GetMode() == wxSND_OUTPUT) {
357 MMRESULT result = waveOutOpen(&internal->devout_id,
358 WAVE_MAPPER, &wformat,
359 (DWORD)internal->sndWin, (DWORD)this,
360 CALLBACK_WINDOW);
361 if (result != MMSYSERR_NOERROR)
362 return FALSE;
363 internal->devin_id = 0;
364 wout_opened = TRUE;
365 curr_mode = wxSND_OUTPUT;
366
367 fragments.AllocIOBuffer();
368 }
369 else {
370 MMRESULT result = waveInOpen(&internal->devin_id,
371 WAVE_MAPPER, &wformat,
372 (DWORD)internal->sndWin, (DWORD)this,
373 CALLBACK_FUNCTION);
374 if (result != MMSYSERR_NOERROR)
375 return FALSE;
376 internal->devout_id = 0;
377 win_opened = TRUE;
378 curr_mode = wxSND_INPUT;
379
380 fragments.AllocIOBuffer();
381 }
382 }
383 return TRUE;
384 }