]>
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 | ||
45 | m_lstoptrs = m_optrs = new wxFragBufPtr[m_maxoq]; | |
46 | m_lstiptrs = m_iptrs = new wxFragBufPtr[m_maxiq]; | |
47 | ||
48 | for (i=0;i<m_maxoq;i++) { | |
49 | m_lstoptrs[i].size = MMD_WIN_IO_BSIZE; | |
50 | m_lstoptrs[i].ptr = 0; | |
51 | m_lstoptrs[i].buffers = new wxList(); | |
52 | m_lstoptrs[i].state = wxBUFFER_FREE; | |
53 | ||
54 | w_snd->PrepareHeader(m_lstoptrs[i], wxSND_OUTPUT); | |
55 | } | |
56 | ||
57 | for (i=0;i<m_maxiq;i++) { | |
58 | m_lstiptrs[i].size = MMD_WIN_IO_BSIZE; | |
59 | m_lstiptrs[i].ptr = 0; | |
60 | m_lstiptrs[i].buffers = new wxList(); | |
61 | m_lstiptrs[i].state = wxBUFFER_FREE; | |
62 | ||
63 | w_snd->PrepareHeader(m_lstiptrs[i], wxSND_INPUT); | |
64 | } | |
65 | } | |
66 | ||
67 | void wxSndWinFragment::FreeIOBuffer(void) | |
68 | { | |
69 | wxWinSound *w_snd = (wxWinSound *)m_iodrv; | |
70 | wxUint8 i; | |
71 | ||
72 | if (!m_lstoptrs && !m_lstiptrs) | |
73 | return; | |
74 | ||
75 | for (i=0;i<m_maxoq;i++) { | |
76 | w_snd->UnprepareHeader(m_lstoptrs[i], wxSND_OUTPUT); | |
77 | delete m_lstoptrs[i].buffers; | |
78 | } | |
79 | ||
80 | for (i=0;i<m_maxiq;i++) { | |
81 | w_snd->UnprepareHeader(m_lstiptrs[i], wxSND_INPUT); | |
82 | delete m_lstiptrs[i].buffers; | |
83 | } | |
84 | ||
85 | delete[] m_lstoptrs; | |
86 | delete[] m_lstiptrs; | |
87 | ||
88 | m_lstoptrs = m_lstiptrs = NULL; | |
89 | m_maxoq = m_maxiq = 0; | |
90 | } | |
91 | ||
92 | void wxSndWinFragment::WaitForAll() | |
93 | { | |
94 | bool buf_busy = TRUE; | |
95 | int i; | |
96 | ||
97 | m_dontq = TRUE; | |
98 | ||
99 | while (buf_busy) { | |
100 | buf_busy = FALSE; | |
101 | ||
102 | for (i=0;i<m_maxoq;i++) { | |
103 | if (m_lstoptrs[i].state == wxBUFFER_FFILLED) { | |
104 | buf_busy = TRUE; | |
105 | break; | |
106 | } | |
107 | } | |
108 | wxYield(); | |
109 | } | |
110 | ||
111 | m_dontq = FALSE; | |
112 | FreeBufToFree(TRUE); | |
113 | } | |
114 | ||
115 | bool wxSndWinFragment::OnBufferFilled(wxFragBufPtr *ptr, wxSndMode mode) | |
116 | { | |
117 | wxSndWinInfo *info = (wxSndWinInfo *)ptr->user_data; | |
118 | wxWinSound *w_snd = (wxWinSound *)m_iodrv; | |
119 | MMRESULT result; | |
120 | ||
121 | switch (mode) { | |
122 | case wxSND_INPUT: | |
123 | result = waveInAddBuffer(w_snd->internal->devin_id, info->hdr, | |
124 | sizeof(WAVEHDR)); | |
125 | break; | |
126 | case wxSND_OUTPUT: | |
127 | result = waveOutWrite(w_snd->internal->devout_id, info->hdr, | |
128 | sizeof(WAVEHDR)); | |
129 | printf("WINOUT: result=%d\n", result); | |
130 | break; | |
131 | } | |
132 | return TRUE; | |
133 | } | |
134 | ||
135 | wxWinSound::wxWinSound(void) | |
136 | : wxSound(), | |
137 | fragments(*this) | |
138 | { | |
139 | internal = new wxWinSoundInternal; | |
140 | internal->devout_id = 0; | |
141 | internal->devin_id = 0; | |
142 | internal->sndWin = 0; | |
143 | ||
144 | wout_opened = FALSE; | |
145 | win_opened = FALSE; | |
146 | curr_o_srate = (wxUint32)-1; | |
147 | curr_o_bps = (wxUint8)-1; | |
148 | curr_o_stereo = (bool)-1; | |
149 | curr_i_srate = (wxUint32)-1; | |
150 | curr_i_bps = (wxUint8)-1; | |
151 | curr_i_stereo = (bool)-1; | |
152 | } | |
153 | ||
154 | wxWinSound::~wxWinSound(void) | |
155 | { | |
156 | int i; | |
157 | ||
158 | fragments.WaitForAll(); | |
159 | ||
160 | if (wout_opened) | |
161 | waveOutReset(internal->devout_id); | |
162 | if (win_opened) | |
163 | waveInReset(internal->devout_id); | |
164 | ||
165 | fragments.FreeIOBuffer(); | |
166 | ||
167 | if (wout_opened) | |
168 | waveOutClose(internal->devout_id); | |
169 | if (win_opened) | |
170 | waveInClose(internal->devin_id); | |
171 | ||
172 | if (internal->sndWin) | |
173 | ::DestroyWindow(internal->sndWin); | |
174 | ||
175 | delete internal; | |
176 | } | |
177 | ||
178 | bool wxWinSound::Wakeup(wxSndBuffer& buf) | |
179 | { | |
180 | if (!Reopen(buf, FALSE)) { | |
181 | buf.Clear(wxSND_BUFLOCKED); | |
182 | return FALSE; | |
183 | } | |
184 | ||
185 | fragments.OnBufferFinished(NULL); | |
186 | return TRUE; | |
187 | } | |
188 | ||
189 | void wxWinSound::PrepareHeader(wxFragmentBuffer::wxFragBufPtr& frag, | |
190 | wxSndMode mode) | |
191 | { | |
192 | wxSndWinInfo *info; | |
193 | WAVEHDR *hdr; | |
194 | ||
195 | if ((mode == wxSND_INPUT && !win_opened) || | |
196 | (mode == wxSND_OUTPUT && !wout_opened)) | |
197 | return; | |
198 | ||
199 | info = new wxSndWinInfo; | |
200 | ||
201 | info->h_data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, frag.size); | |
202 | info->h_hdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR)); | |
203 | ||
204 | info->data = (char *)GlobalLock(info->h_data); | |
205 | hdr = info->hdr = (WAVEHDR *)GlobalLock(info->h_hdr); | |
206 | ||
207 | memset(hdr, 0, sizeof(*hdr)); | |
208 | hdr->lpData = info->data; | |
209 | hdr->dwBufferLength = frag.size; | |
210 | hdr->dwUser = (DWORD)&frag; | |
211 | hdr->dwFlags = WHDR_DONE; | |
212 | ||
213 | if (mode == wxSND_INPUT) { | |
214 | MMRESULT result = waveInPrepareHeader(internal->devin_id, hdr, | |
215 | sizeof(WAVEHDR)); | |
216 | ||
217 | printf("prepareIn = %d\n", result); | |
218 | if (result != MMSYSERR_NOERROR) | |
219 | wxExit(); | |
220 | } else { | |
221 | MMRESULT result = waveOutPrepareHeader(internal->devout_id, hdr, | |
222 | sizeof(WAVEHDR)); | |
223 | printf("prepareOut = %d\n", result); | |
224 | if (result != MMSYSERR_NOERROR) | |
225 | wxExit(); | |
226 | } | |
227 | ||
228 | frag.user_data = (char *)info; | |
229 | frag.data = info->data; | |
230 | } | |
231 | ||
232 | void wxWinSound::UnprepareHeader(wxFragmentBuffer::wxFragBufPtr& frag, | |
233 | wxSndMode mode) | |
234 | { | |
235 | wxSndWinInfo *info = (wxSndWinInfo *)frag.user_data; | |
236 | ||
237 | if ((mode == wxSND_INPUT && !win_opened) || | |
238 | (mode == wxSND_OUTPUT && !wout_opened)) | |
239 | return; | |
240 | ||
241 | MMRESULT result; | |
242 | ||
243 | if (mode == wxSND_INPUT) { | |
244 | result = waveInUnprepareHeader(internal->devin_id, info->hdr, sizeof(*info->hdr)); | |
245 | } else { | |
246 | result = waveOutUnprepareHeader(internal->devout_id, info->hdr, sizeof(*info->hdr)); | |
247 | } | |
248 | ||
249 | printf("unprepare = %d\n", result); | |
250 | ||
251 | GlobalUnlock(info->h_hdr); | |
252 | GlobalUnlock(info->h_data); | |
253 | ||
254 | GlobalFree(info->h_hdr); | |
255 | GlobalFree(info->h_data); | |
256 | ||
257 | delete info; | |
258 | } | |
259 | ||
260 | extern char wxCanvasClassName[]; | |
261 | ||
262 | LRESULT APIENTRY _EXPORT wxSoundHandlerWndProc(HWND hWnd, UINT message, | |
263 | WPARAM wParam, LPARAM lParam) | |
264 | { | |
265 | switch (message) { | |
266 | case MM_WOM_DONE: { | |
267 | wxWinSound *snd_drv = (wxWinSound *)GetWindowLong(hWnd, GWL_USERDATA); | |
268 | WAVEHDR *hdr = (WAVEHDR *)lParam; | |
269 | wxFragmentBuffer::wxFragBufPtr *buf = | |
270 | (wxFragmentBuffer::wxFragBufPtr *)hdr->dwUser; | |
271 | ||
272 | // To be sure ... | |
273 | hdr->dwFlags |= WHDR_DONE; | |
274 | ||
275 | snd_drv->fragments.OnBufferFinished(buf); | |
276 | break; | |
277 | } | |
278 | case MM_WOM_OPEN: | |
279 | printf("wave Open ack\n"); | |
280 | break; | |
281 | case MM_WOM_CLOSE: | |
282 | printf("wave Close ack\n"); | |
283 | break; | |
284 | default: | |
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 | } |