]> git.saurik.com Git - wxWidgets.git/blob - utils/wxMMedia/sndwin.cpp
Added test for sprintf and vsnprintf to fix string.cpp for non-GNU systems.
[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 = 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 }