]>
Commit | Line | Data |
---|---|---|
4d6306eb GL |
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 | ||
9fc0fe37 GL |
45 | m_lstoptrs = new wxFragBufPtr[m_maxoq]; |
46 | m_lstiptrs = new wxFragBufPtr[m_maxiq]; | |
4d6306eb GL |
47 | |
48 | for (i=0;i<m_maxoq;i++) { | |
4d6306eb GL |
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 | ||
9fc0fe37 | 199 | info->h_data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, MMD_WIN_IO_BSIZE); |
4d6306eb GL |
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 | ||
4d6306eb GL |
215 | if (result != MMSYSERR_NOERROR) |
216 | wxExit(); | |
217 | } else { | |
218 | MMRESULT result = waveOutPrepareHeader(internal->devout_id, hdr, | |
219 | sizeof(WAVEHDR)); | |
4d6306eb GL |
220 | if (result != MMSYSERR_NOERROR) |
221 | wxExit(); | |
222 | } | |
223 | ||
9fc0fe37 GL |
224 | frag.sndbuf = new wxStreamBuffer(); |
225 | frag.sndbuf->SetBufferIO(info->data, info->data + MMD_WIN_IO_BSIZE); | |
4d6306eb | 226 | frag.user_data = (char *)info; |
4d6306eb GL |
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 | ||
9fc0fe37 GL |
246 | delete frag.sndbuf; |
247 | ||
4d6306eb GL |
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: | |
9fc0fe37 | 284 | // TODO: Useful ? |
4d6306eb GL |
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 | } |