Release 971012
[wine.git] / multimedia / audio.c
blob039521e18516c8fa1e99d4b4c9d4c018d50856e0
1 /*
2 * Sample Wine Driver for Linux
4 * Copyright 1994 Martin Ayotte
5 */
7 #define EMULATE_SB16
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <sys/ioctl.h>
14 #include "windows.h"
15 #include "user.h"
16 #include "driver.h"
17 #include "mmsystem.h"
18 #include "ldt.h"
20 #ifdef linux
21 #include <linux/soundcard.h>
22 #elif __FreeBSD__
23 #include <machine/soundcard.h>
24 #endif
26 #include "stddebug.h"
27 #include "debug.h"
29 #if defined(linux) || defined(__FreeBSD__)
30 #define SOUND_DEV "/dev/dsp"
31 #define MIXER_DEV "/dev/mixer"
33 #ifdef SOUND_VERSION
34 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
35 #else
36 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
37 #endif
39 #define MAX_WAVOUTDRV (1)
40 #define MAX_WAVINDRV (1)
41 #define MAX_MCIWAVDRV (1)
43 typedef struct {
44 int unixdev;
45 int state;
46 DWORD bufsize;
47 WAVEOPENDESC waveDesc;
48 WORD wFlags;
49 PCMWAVEFORMAT Format;
50 SEGPTR lp16QueueHdr; /* Segmented LPWAVEHDR */
51 DWORD dwTotalPlayed;
52 } LINUX_WAVEOUT;
54 typedef struct {
55 int unixdev;
56 int state;
57 DWORD bufsize; /* Linux '/dev/dsp' give us that size */
58 WAVEOPENDESC waveDesc;
59 WORD wFlags;
60 PCMWAVEFORMAT Format;
61 SEGPTR lp16QueueHdr; /* Segmented LPWAVEHDR */
62 DWORD dwTotalRecorded;
63 } LINUX_WAVEIN;
65 typedef struct {
66 int nUseCount; /* Incremented for each shared open */
67 BOOL16 fShareable; /* TRUE if first open was shareable */
68 WORD wNotifyDeviceID; /* MCI device ID with a pending notification */
69 HANDLE16 hCallback; /* Callback handle for pending notification */
70 HMMIO16 hFile; /* mmio file handle open as Element */
71 MCI_WAVE_OPEN_PARMS openParms;
72 PCMWAVEFORMAT WaveFormat;
73 WAVEHDR WaveHdr;
74 BOOL16 fInput; /* FALSE = Output, TRUE = Input */
75 } LINUX_MCIWAVE;
77 static LINUX_WAVEOUT WOutDev[MAX_WAVOUTDRV];
78 static LINUX_WAVEIN WInDev[MAX_WAVOUTDRV];
79 static LINUX_MCIWAVE MCIWavDev[MAX_MCIWAVDRV];
82 /**************************************************************************
83 * WAVE_NotifyClient [internal]
85 static DWORD WAVE_NotifyClient(UINT16 wDevID, WORD wMsg,
86 DWORD dwParam1, DWORD dwParam2)
88 dprintf_mciwave(stddeb,"WAVE_NotifyClient // wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
90 switch (wMsg) {
91 case WOM_OPEN:
92 case WOM_CLOSE:
93 case WOM_DONE:
94 if (wDevID > MAX_WAVOUTDRV) return MCIERR_INTERNAL;
96 if (WOutDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
97 WOutDev[wDevID].waveDesc.dwCallBack,
98 WOutDev[wDevID].wFlags,
99 WOutDev[wDevID].waveDesc.hWave,
100 wMsg,
101 WOutDev[wDevID].waveDesc.dwInstance,
102 dwParam1,
103 dwParam2)) {
104 dprintf_mciwave(stddeb,"WAVE_NotifyClient // can't notify client !\n");
105 return MMSYSERR_NOERROR;
107 break;
109 case WIM_OPEN:
110 case WIM_CLOSE:
111 case WIM_DATA:
112 if (wDevID > MAX_WAVINDRV) return MCIERR_INTERNAL;
114 if (WInDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
115 WInDev[wDevID].waveDesc.dwCallBack, WInDev[wDevID].wFlags,
116 WInDev[wDevID].waveDesc.hWave, wMsg,
117 WInDev[wDevID].waveDesc.dwInstance, dwParam1, dwParam2)) {
118 dprintf_mciwave(stddeb,"WAVE_NotifyClient // can't notify client !\n");
119 return MMSYSERR_NOERROR;
121 break;
123 return 0;
127 /**************************************************************************
128 * WAVE_mciOpen [internal]*/
129 static DWORD WAVE_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMS lpParms)
131 HLOCAL16 hFormat;
132 LPWAVEFORMAT lpFormat;
133 LPPCMWAVEFORMAT lpWaveFormat;
134 HLOCAL16 hDesc;
135 LPWAVEOPENDESC lpDesc;
136 LPSTR lpstrElementName;
137 DWORD dwRet;
138 char str[128];
140 dprintf_mciwave(stddeb,"WAVE_mciOpen(%04X, %08lX, %p)\n",
141 wDevID, dwFlags, lpParms);
142 if (lpParms == NULL) return MCIERR_INTERNAL;
144 if (MCIWavDev[wDevID].nUseCount > 0) {
145 /* The driver already open on this channel */
146 /* If the driver was opened shareable before and this open specifies */
147 /* shareable then increment the use count */
148 if (MCIWavDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
149 ++MCIWavDev[wDevID].nUseCount;
150 else
151 return MCIERR_MUST_USE_SHAREABLE;
153 else {
154 MCIWavDev[wDevID].nUseCount = 1;
155 MCIWavDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
158 MCIWavDev[wDevID].fInput = FALSE;
160 dprintf_mciwave(stddeb,"WAVE_mciOpen // wDevID=%04X\n", wDevID);
161 dprintf_mciwave(stddeb,"WAVE_mciOpen // before OPEN_ELEMENT\n");
162 if (dwFlags & MCI_OPEN_ELEMENT) {
163 lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(lpParms->lpstrElementName);
164 dprintf_mciwave(stddeb,"WAVE_mciOpen // MCI_OPEN_ELEMENT '%s' !\n",
165 lpstrElementName);
166 if ( lpstrElementName && (strlen(lpstrElementName) > 0)) {
167 strcpy(str, lpstrElementName);
168 CharUpper32A(str);
169 MCIWavDev[wDevID].hFile = mmioOpen(str, NULL,
170 MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
171 if (MCIWavDev[wDevID].hFile == 0) {
172 dprintf_mciwave(stddeb,"WAVE_mciOpen // can't find file='%s' !\n", str);
173 return MCIERR_FILE_NOT_FOUND;
176 else
177 MCIWavDev[wDevID].hFile = 0;
179 dprintf_mciwave(stddeb,"WAVE_mciOpen // hFile=%u\n", MCIWavDev[wDevID].hFile);
180 memcpy(&MCIWavDev[wDevID].openParms, lpParms, sizeof(MCI_WAVE_OPEN_PARMS));
181 MCIWavDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
182 lpWaveFormat = &MCIWavDev[wDevID].WaveFormat;
184 hDesc = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
185 if (hDesc == 0) return MCIERR_INTERNAL; /* is this right ? */
186 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hDesc);
187 lpDesc->hWave = 0;
189 lpWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM;
190 lpWaveFormat->wBitsPerSample = 8;
191 lpWaveFormat->wf.nChannels = 1;
192 lpWaveFormat->wf.nSamplesPerSec = 11025;
193 lpWaveFormat->wf.nAvgBytesPerSec = 11025;
194 lpWaveFormat->wf.nBlockAlign = 1;
196 if (MCIWavDev[wDevID].hFile != 0) {
197 MMCKINFO mmckInfo;
198 MMCKINFO ckMainRIFF;
199 if (mmioDescend(MCIWavDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0) {
200 return MCIERR_INTERNAL;
202 dprintf_mciwave(stddeb,
203 "WAVE_mciOpen // ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
204 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
205 ckMainRIFF.cksize);
206 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
207 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) {
208 return MCIERR_INTERNAL;
210 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
211 if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) {
212 return MCIERR_INTERNAL;
214 dprintf_mciwave(stddeb,
215 "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
216 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
217 mmckInfo.cksize);
218 if (mmioRead(MCIWavDev[wDevID].hFile, (HPSTR) lpWaveFormat,
219 (long) sizeof(PCMWAVEFORMAT)) != (long) sizeof(PCMWAVEFORMAT)) {
220 return MCIERR_INTERNAL;
222 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
223 if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) {
224 return MCIERR_INTERNAL;
226 dprintf_mciwave(stddeb,
227 "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
228 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
229 mmckInfo.cksize);
230 dprintf_mciwave(stddeb,
231 "WAVE_mciOpen // nChannels=%d nSamplesPerSec=%ld\n",
232 lpWaveFormat->wf.nChannels, lpWaveFormat->wf.nSamplesPerSec);
233 lpWaveFormat->wBitsPerSample = 0;
236 lpWaveFormat->wf.nAvgBytesPerSec =
237 lpWaveFormat->wf.nSamplesPerSec * lpWaveFormat->wf.nBlockAlign;
238 hFormat = USER_HEAP_ALLOC(sizeof(PCMWAVEFORMAT));
239 lpFormat = (LPWAVEFORMAT) USER_HEAP_LIN_ADDR(hFormat);
240 memcpy(lpFormat, lpWaveFormat, sizeof(PCMWAVEFORMAT));
241 lpDesc->lpFormat = (LPWAVEFORMAT)USER_HEAP_SEG_ADDR(hFormat);
242 lpDesc = (LPWAVEOPENDESC) USER_HEAP_SEG_ADDR(hDesc);
245 By default the device will be opened for output, the MCI_CUE function is there to
246 change from output to input and back
249 dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL);
251 USER_HEAP_FREE(hFormat);
252 USER_HEAP_FREE(hDesc);
253 return 0;
256 /**************************************************************************
257 * WAVE_mciCue [internal]
260 static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
263 FIXME
265 This routine is far from complete. At the moment only a check is done on the
266 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
267 is the default.
269 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
270 are ignored
273 DWORD dwRet;
274 HLOCAL16 hDesc;
275 LPWAVEOPENDESC lpDesc;
277 dprintf_mciwave(stddeb,"WAVE_mciCue(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
279 /* always close elements ? */
281 if (MCIWavDev[wDevID].hFile != 0) {
282 mmioClose(MCIWavDev[wDevID].hFile, 0);
283 MCIWavDev[wDevID].hFile = 0;
286 hDesc = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
287 lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hDesc);
289 dwRet = MMSYSERR_NOERROR; /* assume success */
291 if ((dwParam & MCI_WAVE_INPUT) && !MCIWavDev[wDevID].fInput) {
293 /* FIXME this is just a hack WOutDev should be hidden here */
294 memcpy(lpDesc,&WOutDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
296 dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
297 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
298 dwRet = widMessage(wDevID, WIDM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL);
299 MCIWavDev[wDevID].fInput = TRUE;
301 else if (MCIWavDev[wDevID].fInput) {
302 /* FIXME this is just a hack WInDev should be hidden here */
303 memcpy(lpDesc,&WInDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
305 dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
306 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
307 dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL);
308 MCIWavDev[wDevID].fInput = FALSE;
311 USER_HEAP_FREE(hDesc);
313 return dwRet;
316 /**************************************************************************
317 * WAVE_mciClose [internal]
319 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
321 DWORD dwRet;
323 dprintf_mciwave(stddeb,
324 "WAVE_mciClose(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
325 MCIWavDev[wDevID].nUseCount--;
326 if (MCIWavDev[wDevID].nUseCount == 0) {
327 if (MCIWavDev[wDevID].hFile != 0) {
328 mmioClose(MCIWavDev[wDevID].hFile, 0);
329 MCIWavDev[wDevID].hFile = 0;
331 if (MCIWavDev[wDevID].fInput)
332 dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
333 else
334 dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
336 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
338 return 0;
342 /**************************************************************************
343 * WAVE_mciPlay [internal]
345 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
347 int start, end;
348 LONG bufsize, count;
349 HGLOBAL16 hData;
350 HLOCAL16 hWaveHdr;
351 LPWAVEHDR lpWaveHdr;
352 SEGPTR lp16WaveHdr;
353 DWORD dwRet;
355 dprintf_mciwave(stddeb,
356 "WAVE_mciPlay(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
358 if (MCIWavDev[wDevID].fInput) {
359 dprintf_mciwave(stddeb,"WAVE_mciPlay // cannot play on input device\n");
360 return MCIERR_NONAPPLICABLE_FUNCTION;
363 if (MCIWavDev[wDevID].hFile == 0) {
364 dprintf_mciwave(stddeb,"WAVE_mciPlay // can't find file='%08lx' !\n",
365 MCIWavDev[wDevID].openParms.lpstrElementName);
366 return MCIERR_FILE_NOT_FOUND;
368 start = 1; end = 99999;
369 if (dwFlags & MCI_FROM) {
370 start = lpParms->dwFrom;
371 dprintf_mciwave(stddeb,
372 "WAVE_mciPlay // MCI_FROM=%d \n", start);
374 if (dwFlags & MCI_TO) {
375 end = lpParms->dwTo;
376 dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_TO=%d \n", end);
378 #if 0
379 if (dwFlags & MCI_NOTIFY) {
380 dprintf_mciwave(stddeb,
381 "WAVE_mciPlay // MCI_NOTIFY %08lX !\n", lpParms->dwCallback);
382 switch(fork()) {
383 case -1:
384 dprintf_mciwave(stddeb,
385 "WAVE_mciPlay // Can't 'fork' process !\n");
386 break;
387 case 0:
388 break;
389 default:
390 dprintf_mciwave(stddeb,"WAVE_mciPlay // process started ! return to caller...\n");
391 return 0;
394 #endif
395 bufsize = 64000;
396 lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
397 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
398 lpWaveHdr->lpData = (LPSTR) WIN16_GlobalLock16(hData);
399 lpWaveHdr->dwUser = 0L;
400 lpWaveHdr->dwFlags = 0L;
401 lpWaveHdr->dwLoops = 0L;
402 hWaveHdr = USER_HEAP_ALLOC(sizeof(WAVEHDR));
403 lp16WaveHdr = USER_HEAP_SEG_ADDR(hWaveHdr);
404 memcpy(PTR_SEG_TO_LIN(lp16WaveHdr), lpWaveHdr, sizeof(WAVEHDR));
405 lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr);
406 dwRet = wodMessage(wDevID, WODM_PREPARE, 0, lp16WaveHdr, sizeof(WAVEHDR));
407 while(TRUE) {
408 count = mmioRead(MCIWavDev[wDevID].hFile,
409 PTR_SEG_TO_LIN(lpWaveHdr->lpData), bufsize);
410 dprintf_mciwave(stddeb,"WAVE_mciPlay // mmioRead bufsize=%ld count=%ld\n", bufsize, count);
411 if (count < 1) break;
412 lpWaveHdr->dwBufferLength = count;
413 /* lpWaveHdr->dwBytesRecorded = count; */
414 dprintf_mciwave(stddeb,"WAVE_mciPlay // before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
415 lpWaveHdr, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded);
416 dwRet = wodMessage(wDevID, WODM_WRITE, 0, lp16WaveHdr, sizeof(WAVEHDR));
418 dwRet = wodMessage(wDevID, WODM_UNPREPARE, 0, lp16WaveHdr, sizeof(WAVEHDR));
419 if (lpWaveHdr->lpData != NULL) {
420 GlobalUnlock16(hData);
421 GlobalFree16(hData);
422 lpWaveHdr->lpData = NULL;
424 USER_HEAP_FREE(hWaveHdr);
425 if (dwFlags & MCI_NOTIFY) {
426 dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
427 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
428 MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
430 return 0;
434 /**************************************************************************
435 * WAVE_mciRecord [internal]
437 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
439 int start, end;
440 LONG bufsize;
441 HGLOBAL16 hData;
442 HLOCAL16 hWaveHdr;
443 LPWAVEHDR lpWaveHdr;
444 SEGPTR lp16WaveHdr;
445 DWORD dwRet;
447 dprintf_mciwave(stddeb,
448 "WAVE_mciRecord(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
450 if (!MCIWavDev[wDevID].fInput) {
451 dprintf_mciwave(stddeb,"WAVE_mciPlay // cannot record on output device\n");
452 return MCIERR_NONAPPLICABLE_FUNCTION;
455 if (MCIWavDev[wDevID].hFile == 0) {
456 dprintf_mciwave(stddeb,"WAVE_mciRecord // can't find file='%08lx' !\n",
457 MCIWavDev[wDevID].openParms.lpstrElementName);
458 return MCIERR_FILE_NOT_FOUND;
460 start = 1; end = 99999;
461 if (dwFlags & MCI_FROM) {
462 start = lpParms->dwFrom;
463 dprintf_mciwave(stddeb,
464 "WAVE_mciRecord // MCI_FROM=%d \n", start);
466 if (dwFlags & MCI_TO) {
467 end = lpParms->dwTo;
468 dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_TO=%d \n", end);
470 bufsize = 64000;
471 lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
472 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
473 lpWaveHdr->lpData = (LPSTR) WIN16_GlobalLock16(hData);
474 lpWaveHdr->dwBufferLength = bufsize;
475 lpWaveHdr->dwUser = 0L;
476 lpWaveHdr->dwFlags = 0L;
477 lpWaveHdr->dwLoops = 0L;
478 hWaveHdr = USER_HEAP_ALLOC(sizeof(WAVEHDR));
479 lp16WaveHdr = USER_HEAP_SEG_ADDR(hWaveHdr);
480 memcpy(PTR_SEG_TO_LIN(lp16WaveHdr), lpWaveHdr, sizeof(WAVEHDR));
481 lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr);
482 dwRet = widMessage(wDevID, WIDM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
483 dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_PREPARE \n");
484 while(TRUE) {
485 lpWaveHdr->dwBytesRecorded = 0;
486 dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
487 dprintf_mciwave(stddeb,
488 "WAVE_mciRecord // after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
489 lpWaveHdr, lpWaveHdr->dwBytesRecorded);
490 if (lpWaveHdr->dwBytesRecorded == 0) break;
492 dprintf_mciwave(stddeb,"WAVE_mciRecord // before WIDM_UNPREPARE \n");
493 dwRet = widMessage(wDevID, WIDM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
494 dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_UNPREPARE \n");
495 if (lpWaveHdr->lpData != NULL) {
496 GlobalUnlock16(hData);
497 GlobalFree16(hData);
498 lpWaveHdr->lpData = NULL;
500 USER_HEAP_FREE(hWaveHdr);
501 if (dwFlags & MCI_NOTIFY) {
502 dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
503 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
504 MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
506 return 0;
510 /**************************************************************************
511 * WAVE_mciStop [internal]
513 static DWORD WAVE_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
515 DWORD dwRet;
517 dprintf_mciwave(stddeb,
518 "WAVE_mciStop(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
519 if (lpParms == NULL) return MCIERR_INTERNAL;
520 if (MCIWavDev[wDevID].fInput)
521 dwRet = widMessage(wDevID, WIDM_STOP, 0, dwFlags, (DWORD)lpParms);
522 else
523 dwRet = wodMessage(wDevID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
525 return dwRet;
529 /**************************************************************************
530 * WAVE_mciPause [internal]
532 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
534 DWORD dwRet;
536 dprintf_mciwave(stddeb,
537 "WAVE_mciPause(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
538 if (lpParms == NULL) return MCIERR_INTERNAL;
539 if (MCIWavDev[wDevID].fInput)
540 dwRet = widMessage(wDevID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
541 else
542 dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
544 return dwRet;
548 /**************************************************************************
549 * WAVE_mciResume [internal]
551 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
553 dprintf_mciwave(stddeb,
554 "WAVE_mciResume(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
555 if (lpParms == NULL) return MCIERR_INTERNAL;
556 return 0;
560 /**************************************************************************
561 * WAVE_mciSet [internal]
563 static DWORD WAVE_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
565 dprintf_mciwave(stddeb,
566 "WAVE_mciSet(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
567 if (lpParms == NULL) return MCIERR_INTERNAL;
568 dprintf_mciwave(stddeb,
569 "WAVE_mciSet // dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
570 dprintf_mciwave(stddeb,
571 "WAVE_mciSet // dwAudio=%08lX\n", lpParms->dwAudio);
572 if (dwFlags & MCI_SET_TIME_FORMAT) {
573 switch (lpParms->dwTimeFormat) {
574 case MCI_FORMAT_MILLISECONDS:
575 dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_MILLISECONDS !\n");
576 break;
577 case MCI_FORMAT_BYTES:
578 dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_BYTES !\n");
579 break;
580 case MCI_FORMAT_SAMPLES:
581 dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_SAMPLES !\n");
582 break;
583 default:
584 dprintf_mciwave(stddeb, "WAVE_mciSet // bad time format !\n");
585 return MCIERR_BAD_TIME_FORMAT;
588 if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
589 if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION;
590 if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION;
591 if (dwFlags & MCI_SET_AUDIO)
592 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO !\n");
593 if (dwFlags && MCI_SET_ON) {
594 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_ON !\n");
595 if (dwFlags && MCI_SET_AUDIO_LEFT)
596 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_LEFT !\n");
597 if (dwFlags && MCI_SET_AUDIO_RIGHT)
598 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_RIGHT !\n");
600 if (dwFlags & MCI_SET_OFF)
601 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_OFF !\n");
602 if (dwFlags & MCI_WAVE_INPUT)
603 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_INPUT !\n");
604 if (dwFlags & MCI_WAVE_OUTPUT)
605 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_OUTPUT !\n");
606 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
607 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYINPUT !\n");
608 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
609 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYOUTPUT !\n");
610 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC)
611 dprintf_mciwave(stddeb,
612 "WAVE_mciSet // MCI_WAVE_SET_AVGBYTESPERSEC !\n");
613 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE)
614 dprintf_mciwave(stddeb,
615 "WAVE_mciSet // MCI_WAVE_SET_BITSPERSAMPLE !\n");
616 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN)
617 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_BLOCKALIGN !\n");
618 if (dwFlags & MCI_WAVE_SET_CHANNELS)
619 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_CHANNELS !\n");
620 if (dwFlags & MCI_WAVE_SET_FORMATTAG)
621 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_FORMATTAG !\n");
622 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC)
623 dprintf_mciwave(stddeb,
624 "WAVE_mciSet // MCI_WAVE_SET_SAMPLESPERSEC !\n");
625 return 0;
629 /**************************************************************************
630 * WAVE_mciStatus [internal]
632 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
634 dprintf_mciwave(stddeb,
635 "WAVE_mciStatus(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
636 if (lpParms == NULL) return MCIERR_INTERNAL;
637 if (dwFlags & MCI_STATUS_ITEM) {
638 switch(lpParms->dwItem) {
639 case MCI_STATUS_CURRENT_TRACK:
640 lpParms->dwReturn = 1;
641 break;
642 case MCI_STATUS_LENGTH:
643 lpParms->dwReturn = 5555;
644 if (dwFlags & MCI_TRACK) {
645 lpParms->dwTrack = 1;
646 lpParms->dwReturn = 2222;
648 break;
649 case MCI_STATUS_MODE:
650 lpParms->dwReturn = MCI_MODE_STOP;
651 break;
652 case MCI_STATUS_MEDIA_PRESENT:
653 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_MEDIA_PRESENT !\n");
654 lpParms->dwReturn = TRUE;
655 break;
656 case MCI_STATUS_NUMBER_OF_TRACKS:
657 lpParms->dwReturn = 1;
658 break;
659 case MCI_STATUS_POSITION:
660 lpParms->dwReturn = 3333;
661 if (dwFlags & MCI_STATUS_START) {
662 lpParms->dwItem = 1;
664 if (dwFlags & MCI_TRACK) {
665 lpParms->dwTrack = 1;
666 lpParms->dwReturn = 777;
668 break;
669 case MCI_STATUS_READY:
670 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_READY !\n");
671 lpParms->dwReturn = TRUE;
672 break;
673 case MCI_STATUS_TIME_FORMAT:
674 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_TIME_FORMAT !\n");
675 lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
676 break;
677 case MCI_WAVE_INPUT:
678 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_INPUT !\n");
679 lpParms->dwReturn = 0;
680 break;
681 case MCI_WAVE_OUTPUT:
682 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_OUTPUT !\n");
683 lpParms->dwReturn = 0;
684 break;
685 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
686 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_AVGBYTESPERSEC !\n");
687 lpParms->dwReturn = 22050;
688 break;
689 case MCI_WAVE_STATUS_BITSPERSAMPLE:
690 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BITSPERSAMPLE !\n");
691 lpParms->dwReturn = 8;
692 break;
693 case MCI_WAVE_STATUS_BLOCKALIGN:
694 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BLOCKALIGN !\n");
695 lpParms->dwReturn = 1;
696 break;
697 case MCI_WAVE_STATUS_CHANNELS:
698 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_CHANNELS !\n");
699 lpParms->dwReturn = 1;
700 break;
701 case MCI_WAVE_STATUS_FORMATTAG:
702 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_FORMATTAG !\n");
703 lpParms->dwReturn = WAVE_FORMAT_PCM;
704 break;
705 case MCI_WAVE_STATUS_LEVEL:
706 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_LEVEL !\n");
707 lpParms->dwReturn = 0xAAAA5555;
708 break;
709 case MCI_WAVE_STATUS_SAMPLESPERSEC:
710 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_SAMPLESPERSEC !\n");
711 lpParms->dwReturn = 22050;
712 break;
713 default:
714 dprintf_mciwave(stddeb,"WAVE_mciStatus // unknown command %08lX !\n", lpParms->dwItem);
715 return MCIERR_UNRECOGNIZED_COMMAND;
718 if (dwFlags & MCI_NOTIFY) {
719 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
720 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
721 MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
723 return 0;
726 /**************************************************************************
727 * WAVE_mciGetDevCaps [internal]
729 static DWORD WAVE_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags,
730 LPMCI_GETDEVCAPS_PARMS lpParms)
732 dprintf_mciwave(stddeb,
733 "WAVE_mciGetDevCaps(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
734 if (lpParms == NULL) return MCIERR_INTERNAL;
735 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
736 switch(lpParms->dwItem) {
737 case MCI_GETDEVCAPS_CAN_RECORD:
738 lpParms->dwReturn = TRUE;
739 break;
740 case MCI_GETDEVCAPS_HAS_AUDIO:
741 lpParms->dwReturn = TRUE;
742 break;
743 case MCI_GETDEVCAPS_HAS_VIDEO:
744 lpParms->dwReturn = FALSE;
745 break;
746 case MCI_GETDEVCAPS_DEVICE_TYPE:
747 lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
748 break;
749 case MCI_GETDEVCAPS_USES_FILES:
750 lpParms->dwReturn = TRUE;
751 break;
752 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
753 lpParms->dwReturn = TRUE;
754 break;
755 case MCI_GETDEVCAPS_CAN_EJECT:
756 lpParms->dwReturn = FALSE;
757 break;
758 case MCI_GETDEVCAPS_CAN_PLAY:
759 lpParms->dwReturn = TRUE;
760 break;
761 case MCI_GETDEVCAPS_CAN_SAVE:
762 lpParms->dwReturn = TRUE;
763 break;
764 case MCI_WAVE_GETDEVCAPS_INPUTS:
765 lpParms->dwReturn = 1;
766 break;
767 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
768 lpParms->dwReturn = 1;
769 break;
770 default:
771 return MCIERR_UNRECOGNIZED_COMMAND;
774 return 0;
777 /**************************************************************************
778 * WAVE_mciInfo [internal]
780 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS lpParms)
782 dprintf_mciwave(stddeb,
783 "WAVE_mciInfo(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
784 if (lpParms == NULL) return MCIERR_INTERNAL;
785 lpParms->lpstrReturn = NULL;
786 switch(dwFlags) {
787 case MCI_INFO_PRODUCT:
788 lpParms->lpstrReturn = "Linux Sound System 0.5";
789 break;
790 case MCI_INFO_FILE:
791 lpParms->lpstrReturn =
792 (LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName;
793 break;
794 case MCI_WAVE_INPUT:
795 lpParms->lpstrReturn = "Linux Sound System 0.5";
796 break;
797 case MCI_WAVE_OUTPUT:
798 lpParms->lpstrReturn = "Linux Sound System 0.5";
799 break;
800 default:
801 return MCIERR_UNRECOGNIZED_COMMAND;
803 if (lpParms->lpstrReturn != NULL)
804 lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
805 else
806 lpParms->dwRetSize = 0;
807 return 0;
811 /*-----------------------------------------------------------------------*/
814 /**************************************************************************
815 * wodGetDevCaps [internal]
817 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS lpCaps, DWORD dwSize)
819 int audio;
820 int smplrate;
821 int samplesize = 16;
822 int dsp_stereo = 1;
823 int bytespersmpl;
824 dprintf_mciwave(stddeb,
825 "wodGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
826 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
827 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
828 audio = open (SOUND_DEV, O_WRONLY, 0);
829 if (audio == -1) return MMSYSERR_ALLOCATED ;
830 #ifdef EMULATE_SB16
831 lpCaps->wMid = 0x0002;
832 lpCaps->wPid = 0x0104;
833 strcpy(lpCaps->szPname, "SB16 Wave Out");
834 #else
835 lpCaps->wMid = 0x00FF; /* Manufac ID */
836 lpCaps->wPid = 0x0001; /* Product ID */
837 strcpy(lpCaps->szPname, "Linux WAVOUT Driver");
838 #endif
839 lpCaps->vDriverVersion = 0x0100;
840 lpCaps->dwFormats = 0x00000000;
841 lpCaps->dwSupport = WAVECAPS_VOLUME;
842 lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
843 if (lpCaps->wChannels > 1) lpCaps->dwSupport |= WAVECAPS_LRVOLUME;
844 bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
845 smplrate = 44100;
846 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
847 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
848 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S08;
849 if (bytespersmpl > 1) {
850 lpCaps->dwFormats |= WAVE_FORMAT_4M16;
851 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S16;
854 smplrate = 22050;
855 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
856 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
857 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S08;
858 if (bytespersmpl > 1) {
859 lpCaps->dwFormats |= WAVE_FORMAT_2M16;
860 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S16;
863 smplrate = 11025;
864 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
865 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
866 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S08;
867 if (bytespersmpl > 1) {
868 lpCaps->dwFormats |= WAVE_FORMAT_1M16;
869 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S16;
872 close(audio);
873 dprintf_mciwave(stddeb,
874 "wodGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats);
875 return MMSYSERR_NOERROR;
879 /**************************************************************************
880 * wodOpen [internal]
882 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
884 int audio;
885 int abuf_size;
886 int smplrate;
887 int samplesize;
888 int dsp_stereo;
889 LPWAVEFORMAT lpFormat;
891 dprintf_mciwave(stddeb,
892 "wodOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
893 if (lpDesc == NULL) {
894 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Invalid Parameter !\n");
895 return MMSYSERR_INVALPARAM;
897 if (wDevID >= MAX_WAVOUTDRV) {
898 dprintf_mciwave(stddeb,"Linux 'wodOpen' // MAX_WAVOUTDRV reached !\n");
899 return MMSYSERR_ALLOCATED;
901 WOutDev[wDevID].unixdev = 0;
902 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
903 audio = open (SOUND_DEV, O_WRONLY, 0);
904 if (audio == -1) {
905 dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't open !\n");
906 return MMSYSERR_ALLOCATED ;
908 IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
909 if (abuf_size < 1024 || abuf_size > 65536) {
910 if (abuf_size == -1)
911 dprintf_mciwave(stddeb,"Linux 'wodOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
912 else
913 dprintf_mciwave(stddeb,"Linux 'wodOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
914 return MMSYSERR_NOTENABLED;
916 WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
917 switch(WOutDev[wDevID].wFlags) {
918 case DCB_NULL:
919 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_NULL !\n");
920 break;
921 case DCB_WINDOW:
922 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_WINDOW !\n");
923 break;
924 case DCB_TASK:
925 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_TASK !\n");
926 break;
927 case DCB_FUNCTION:
928 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_FUNCTION !\n");
929 break;
931 WOutDev[wDevID].lp16QueueHdr = NULL;
932 WOutDev[wDevID].unixdev = audio;
933 WOutDev[wDevID].dwTotalPlayed = 0;
934 WOutDev[wDevID].bufsize = abuf_size;
935 memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
936 dprintf_mciwave(stddeb,"Linux 'wodOpen' // lpDesc->lpFormat = %p\n",lpDesc->lpFormat);
937 lpFormat = (LPWAVEFORMAT) PTR_SEG_TO_LIN(lpDesc->lpFormat);
938 dprintf_mciwave(stddeb,"Linux 'wodOpen' // lpFormat = %p\n",lpFormat);
939 if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
940 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad format %04X !\n",
941 lpFormat->wFormatTag);
942 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nChannels %d !\n",
943 lpFormat->nChannels);
944 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nSamplesPerSec %ld !\n",
945 lpFormat->nSamplesPerSec);
946 return WAVERR_BADFORMAT;
948 memcpy(&WOutDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
949 if (WOutDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
950 if (WOutDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
951 dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n",
952 WOutDev[wDevID].Format.wBitsPerSample);
953 if (WOutDev[wDevID].Format.wBitsPerSample == 0) {
954 WOutDev[wDevID].Format.wBitsPerSample = 8 *
955 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec /
956 WOutDev[wDevID].Format.wf.nSamplesPerSec) /
957 WOutDev[wDevID].Format.wf.nChannels;
959 samplesize = WOutDev[wDevID].Format.wBitsPerSample;
960 smplrate = WOutDev[wDevID].Format.wf.nSamplesPerSec;
961 dsp_stereo = (WOutDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
962 IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
963 IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
964 IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
965 dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n",
966 WOutDev[wDevID].Format.wBitsPerSample);
967 dprintf_mciwave(stddeb,"Linux 'wodOpen' // nAvgBytesPerSec=%lu !\n",
968 WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
969 dprintf_mciwave(stddeb,"Linux 'wodOpen' // nSamplesPerSec=%lu !\n",
970 WOutDev[wDevID].Format.wf.nSamplesPerSec);
971 dprintf_mciwave(stddeb,"Linux 'wodOpen' // nChannels=%u !\n",
972 WOutDev[wDevID].Format.wf.nChannels);
973 if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
974 dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't notify client !\n");
975 return MMSYSERR_INVALPARAM;
977 return MMSYSERR_NOERROR;
980 /**************************************************************************
981 * wodClose [internal]
983 static DWORD wodClose(WORD wDevID)
985 dprintf_mciwave(stddeb,"wodClose(%u);\n", wDevID);
986 if (wDevID > MAX_WAVOUTDRV) return MMSYSERR_INVALPARAM;
987 if (WOutDev[wDevID].unixdev == 0) {
988 dprintf_mciwave(stddeb,"Linux 'wodClose' // can't close !\n");
989 return MMSYSERR_NOTENABLED;
991 if (WOutDev[wDevID].lp16QueueHdr != NULL) {
992 dprintf_mciwave(stddeb,"linux 'wodclose' // still buffers open !\n");
993 return WAVERR_STILLPLAYING;
995 close(WOutDev[wDevID].unixdev);
996 WOutDev[wDevID].unixdev = 0;
997 WOutDev[wDevID].bufsize = 0;
998 WOutDev[wDevID].lp16QueueHdr = NULL;
999 if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
1000 dprintf_mciwave(stddeb,"Linux 'wodClose' // can't notify client !\n");
1001 return MMSYSERR_INVALPARAM;
1003 return MMSYSERR_NOERROR;
1006 /**************************************************************************
1007 * wodWrite [internal]
1009 static DWORD wodWrite(WORD wDevID, SEGPTR lp16WaveHdr, DWORD dwSize)
1011 int count;
1012 LPSTR lpData;
1013 LPWAVEHDR lpWaveHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(lp16WaveHdr);
1015 dprintf_mciwave(stddeb,"wodWrite(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1016 if (WOutDev[wDevID].unixdev == 0) {
1017 dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't play !\n");
1018 return MMSYSERR_NOTENABLED;
1020 if (lpWaveHdr->lpData == NULL) return WAVERR_UNPREPARED;
1021 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) return WAVERR_UNPREPARED;
1022 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
1023 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1024 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1025 dprintf_mciwave(stddeb,
1026 "wodWrite() // dwBufferLength %lu !\n", lpWaveHdr->dwBufferLength);
1027 dprintf_mciwave(stddeb,
1028 "wodWrite() // WOutDev[%u].unixdev %u !\n", wDevID, WOutDev[wDevID].unixdev);
1029 lpData = PTR_SEG_TO_LIN(lpWaveHdr->lpData);
1030 count = write (WOutDev[wDevID].unixdev, lpData, lpWaveHdr->dwBufferLength);
1031 dprintf_mciwave(stddeb,
1032 "wodWrite() // write returned count %u !\n", count);
1033 if (count != lpWaveHdr->dwBufferLength) {
1034 dprintf_mciwave(stddeb,"Linux 'wodWrite' // error writting !\n");
1035 return MMSYSERR_NOTENABLED;
1037 WOutDev[wDevID].dwTotalPlayed += count;
1038 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1039 lpWaveHdr->dwFlags |= WHDR_DONE;
1040 if (WAVE_NotifyClient(wDevID, WOM_DONE, lp16WaveHdr, count) != MMSYSERR_NOERROR) {
1041 dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't notify client !\n");
1042 return MMSYSERR_INVALPARAM;
1044 return MMSYSERR_NOERROR;
1047 /**************************************************************************
1048 * wodPrepare [internal]
1050 static DWORD wodPrepare(WORD wDevID, SEGPTR lp16WaveHdr, DWORD dwSize)
1052 LPWAVEHDR lpWaveHdr;
1054 dprintf_mciwave(stddeb,
1055 "wodPrepare(%u, %p, %08lX);\n", wDevID, (void *)lp16WaveHdr, dwSize);
1056 if (WOutDev[wDevID].unixdev == 0) {
1057 dprintf_mciwave(stddeb,"Linux 'wodPrepare' // can't prepare !\n");
1058 return MMSYSERR_NOTENABLED;
1061 lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr);
1063 /* the COOL waveeditor feels much better without this check...
1064 * someone please have a look at available documentation
1065 if (WOutDev[wDevID].lpQueueHdr != NULL) {
1066 dprintf_mciwave(stddeb,"Linux 'wodPrepare' // already prepare !\n");
1067 return MMSYSERR_NOTENABLED;
1070 WOutDev[wDevID].dwTotalPlayed = 0;
1071 WOutDev[wDevID].lp16QueueHdr = lp16WaveHdr;
1072 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
1073 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1074 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1075 return MMSYSERR_NOERROR;
1078 /**************************************************************************
1079 * wodUnprepare [internal]
1081 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1083 dprintf_mciwave(stddeb,
1084 "wodUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1085 if (WOutDev[wDevID].unixdev == 0) {
1086 dprintf_mciwave(stddeb,"Linux 'wodUnprepare' // can't unprepare !\n");
1087 return MMSYSERR_NOTENABLED;
1090 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1091 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1092 lpWaveHdr->dwFlags |= WHDR_DONE;
1093 WOutDev[wDevID].lp16QueueHdr = NULL;
1094 dprintf_mciwave(stddeb,
1095 "Linux 'wodUnprepare' // all headers unprepared !\n");
1096 return MMSYSERR_NOERROR;
1099 /**************************************************************************
1100 * wodRestart [internal]
1102 static DWORD wodRestart(WORD wDevID)
1104 dprintf_mciwave(stddeb,"wodRestart(%u);\n", wDevID);
1105 if (WOutDev[wDevID].unixdev == 0) {
1106 dprintf_mciwave(stddeb,"Linux 'wodRestart' // can't restart !\n");
1107 return MMSYSERR_NOTENABLED;
1109 /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
1110 if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
1111 dprintf_mciwave(stddeb,"Linux 'wodRestart' // can't notify client !\n");
1112 return MMSYSERR_INVALPARAM;
1115 return MMSYSERR_NOERROR;
1118 /**************************************************************************
1119 * wodReset [internal]
1121 static DWORD wodReset(WORD wDevID)
1123 dprintf_mciwave(stddeb,"wodReset(%u);\n", wDevID);
1124 if (WOutDev[wDevID].unixdev == 0) {
1125 dprintf_mciwave(stddeb,"Linux 'wodReset' // can't reset !\n");
1126 return MMSYSERR_NOTENABLED;
1128 return MMSYSERR_NOERROR;
1132 /**************************************************************************
1133 * wodGetPosition [internal]
1135 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
1137 int time;
1138 dprintf_mciwave(stddeb,"wodGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1139 if (WOutDev[wDevID].unixdev == 0) {
1140 dprintf_mciwave(stddeb,"Linux 'wodGetPosition' // can't get pos !\n");
1141 return MMSYSERR_NOTENABLED;
1143 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1144 dprintf_mciwave(stddeb,"wodGetPosition // wType=%04X !\n",
1145 lpTime->wType);
1146 dprintf_mciwave(stddeb,"wodGetPosition // wBitsPerSample=%u\n",
1147 WOutDev[wDevID].Format.wBitsPerSample);
1148 dprintf_mciwave(stddeb,"wodGetPosition // nSamplesPerSec=%lu\n",
1149 WOutDev[wDevID].Format.wf.nSamplesPerSec);
1150 dprintf_mciwave(stddeb,"wodGetPosition // nChannels=%u\n",
1151 WOutDev[wDevID].Format.wf.nChannels);
1152 dprintf_mciwave(stddeb,"wodGetPosition // nAvgBytesPerSec=%lu\n",
1153 WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
1154 switch(lpTime->wType) {
1155 case TIME_BYTES:
1156 lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed;
1157 dprintf_mciwave(stddeb,"wodGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb);
1158 break;
1159 case TIME_SAMPLES:
1160 dprintf_mciwave(stddeb,"wodGetPosition // dwTotalPlayed=%lu\n",
1161 WOutDev[wDevID].dwTotalPlayed);
1162 dprintf_mciwave(stddeb,"wodGetPosition // wBitsPerSample=%u\n",
1163 WOutDev[wDevID].Format.wBitsPerSample);
1164 lpTime->u.sample = WOutDev[wDevID].dwTotalPlayed * 8 /
1165 WOutDev[wDevID].Format.wBitsPerSample;
1166 dprintf_mciwave(stddeb,"wodGetPosition // TIME_SAMPLES=%lu\n", lpTime->u.sample);
1167 break;
1168 case TIME_SMPTE:
1169 time = WOutDev[wDevID].dwTotalPlayed /
1170 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1171 lpTime->u.smpte.hour = time / 108000;
1172 time -= lpTime->u.smpte.hour * 108000;
1173 lpTime->u.smpte.min = time / 1800;
1174 time -= lpTime->u.smpte.min * 1800;
1175 lpTime->u.smpte.sec = time / 30;
1176 time -= lpTime->u.smpte.sec * 30;
1177 lpTime->u.smpte.frame = time;
1178 lpTime->u.smpte.fps = 30;
1179 dprintf_mciwave(stddeb,
1180 "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1181 lpTime->u.smpte.hour, lpTime->u.smpte.min,
1182 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1183 break;
1184 default:
1185 dprintf_mciwave(stddeb,"wodGetPosition() format not supported ! use TIME_MS !\n");
1186 lpTime->wType = TIME_MS;
1187 case TIME_MS:
1188 lpTime->u.ms = WOutDev[wDevID].dwTotalPlayed /
1189 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1190 dprintf_mciwave(stddeb,"wodGetPosition // TIME_MS=%lu\n", lpTime->u.ms);
1191 break;
1193 return MMSYSERR_NOERROR;
1196 /**************************************************************************
1197 * wodGetVolume [internal]
1199 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1201 int mixer;
1202 int volume, left, right;
1203 dprintf_mciwave(stddeb,"wodGetVolume(%u, %p);\n", wDevID, lpdwVol);
1204 if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
1205 if ((mixer = open(MIXER_DEV, O_RDONLY)) < 0) {
1206 dprintf_mciwave(stddeb, "Linux 'wodGetVolume' // mixer device not available !\n");
1207 return MMSYSERR_NOTENABLED;
1209 if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) {
1210 dprintf_mciwave(stddeb,"Linux 'wodGetVolume' // unable read mixer !\n");
1211 return MMSYSERR_NOTENABLED;
1213 close(mixer);
1214 left = volume & 0x7F;
1215 right = (volume >> 8) & 0x7F;
1216 dprintf_mciwave(stddeb,"Linux 'wodGetVolume' // left=%d right=%d !\n", left, right);
1217 *lpdwVol = MAKELONG(left << 9, right << 9);
1218 return MMSYSERR_NOERROR;
1222 /**************************************************************************
1223 * wodSetVolume [internal]
1225 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1227 int mixer;
1228 int volume;
1229 dprintf_mciwave(stddeb,"wodSetVolume(%u, %08lX);\n", wDevID, dwParam);
1230 volume = (LOWORD(dwParam) >> 9 & 0x7F) +
1231 ((HIWORD(dwParam) >> 9 & 0x7F) << 8);
1232 if ((mixer = open(MIXER_DEV, O_WRONLY)) < 0) {
1233 dprintf_mciwave(stddeb, "Linux 'wodSetVolume' // mixer device not available !\n");
1234 return MMSYSERR_NOTENABLED;
1236 if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) {
1237 dprintf_mciwave(stddeb,"Linux 'wodSetVolume' // unable set mixer !\n");
1238 return MMSYSERR_NOTENABLED;
1240 close(mixer);
1241 return MMSYSERR_NOERROR;
1244 #endif /* linux || __FreeBSD__*/
1246 /**************************************************************************
1247 * wodMessage [sample driver]
1249 DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1250 DWORD dwParam1, DWORD dwParam2)
1252 dprintf_mciwave(stddeb,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1253 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1254 #if defined(linux) || defined(__FreeBSD__)
1255 switch(wMsg) {
1256 case WODM_OPEN:
1257 return wodOpen(wDevID, (LPWAVEOPENDESC)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1258 case WODM_CLOSE:
1259 return wodClose(wDevID);
1260 case WODM_WRITE:
1261 return wodWrite(wDevID, dwParam1, dwParam2);
1262 case WODM_PAUSE:
1263 return MMSYSERR_NOTSUPPORTED;
1264 case WODM_STOP:
1265 return MMSYSERR_NOTSUPPORTED;
1266 case WODM_GETPOS:
1267 return wodGetPosition(wDevID, (LPMMTIME)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1268 case WODM_BREAKLOOP:
1269 return MMSYSERR_NOTSUPPORTED;
1270 case WODM_PREPARE:
1271 return wodPrepare(wDevID, dwParam1, dwParam2);
1272 case WODM_UNPREPARE:
1273 return wodUnprepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1274 case WODM_GETDEVCAPS:
1275 return wodGetDevCaps(wDevID, (LPWAVEOUTCAPS)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1276 case WODM_GETNUMDEVS:
1277 return 1L;
1278 case WODM_GETPITCH:
1279 return MMSYSERR_NOTSUPPORTED;
1280 case WODM_SETPITCH:
1281 return MMSYSERR_NOTSUPPORTED;
1282 case WODM_GETPLAYBACKRATE:
1283 return MMSYSERR_NOTSUPPORTED;
1284 case WODM_SETPLAYBACKRATE:
1285 return MMSYSERR_NOTSUPPORTED;
1286 case WODM_GETVOLUME:
1287 return wodGetVolume(wDevID, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
1288 case WODM_SETVOLUME:
1289 return wodSetVolume(wDevID, dwParam1);
1290 case WODM_RESTART:
1291 return wodRestart(wDevID);
1292 case WODM_RESET:
1293 return wodReset(wDevID);
1294 default:
1295 dprintf_mciwave(stddeb,"wodMessage // unknown message !\n");
1297 return MMSYSERR_NOTSUPPORTED;
1298 #else
1299 return MMSYSERR_NOTENABLED;
1300 #endif
1304 /*-----------------------------------------------------------------------*/
1306 #if defined(linux) || defined(__FreeBSD__)
1308 /**************************************************************************
1309 * widGetDevCaps [internal]
1311 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPS lpCaps, DWORD dwSize)
1313 int audio;
1314 int smplrate;
1315 int samplesize = 16;
1316 int dsp_stereo = 1;
1317 int bytespersmpl;
1318 dprintf_mciwave(stddeb,
1319 "widGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
1320 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1321 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
1322 audio = open (SOUND_DEV, O_RDONLY, 0);
1323 if (audio == -1) return MMSYSERR_ALLOCATED ;
1324 #ifdef EMULATE_SB16
1325 lpCaps->wMid = 0x0002;
1326 lpCaps->wPid = 0x0004;
1327 strcpy(lpCaps->szPname, "SB16 Wave In");
1328 #else
1329 lpCaps->wMid = 0x00FF; /* Manufac ID */
1330 lpCaps->wPid = 0x0001; /* Product ID */
1331 strcpy(lpCaps->szPname, "Linux WAVIN Driver");
1332 #endif
1333 lpCaps->dwFormats = 0x00000000;
1334 lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
1335 bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
1336 smplrate = 44100;
1337 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1338 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
1339 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S08;
1340 if (bytespersmpl > 1) {
1341 lpCaps->dwFormats |= WAVE_FORMAT_4M16;
1342 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_4S16;
1345 smplrate = 22050;
1346 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1347 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
1348 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S08;
1349 if (bytespersmpl > 1) {
1350 lpCaps->dwFormats |= WAVE_FORMAT_2M16;
1351 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_2S16;
1354 smplrate = 11025;
1355 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1356 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
1357 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S08;
1358 if (bytespersmpl > 1) {
1359 lpCaps->dwFormats |= WAVE_FORMAT_1M16;
1360 if (lpCaps->wChannels > 1) lpCaps->dwFormats |= WAVE_FORMAT_1S16;
1363 close(audio);
1364 dprintf_mciwave(stddeb,
1365 "widGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats);
1366 return MMSYSERR_NOERROR;
1370 /**************************************************************************
1371 * widOpen [internal]
1373 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1375 int audio;
1376 int abuf_size;
1377 int smplrate;
1378 int samplesize;
1379 int dsp_stereo;
1380 LPWAVEFORMAT lpFormat;
1381 dprintf_mciwave(stddeb, "widOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
1382 if (lpDesc == NULL) {
1383 dprintf_mciwave(stddeb,"Linux 'widOpen' // Invalid Parameter !\n");
1384 return MMSYSERR_INVALPARAM;
1386 if (wDevID >= MAX_WAVINDRV) {
1387 dprintf_mciwave(stddeb,"Linux 'widOpen' // MAX_WAVINDRV reached !\n");
1388 return MMSYSERR_ALLOCATED;
1390 WInDev[wDevID].unixdev = 0;
1391 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
1392 audio = open (SOUND_DEV, O_RDONLY, 0);
1393 if (audio == -1) {
1394 dprintf_mciwave(stddeb,"Linux 'widOpen' // can't open !\n");
1395 return MMSYSERR_ALLOCATED;
1397 IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
1398 if (abuf_size < 1024 || abuf_size > 65536) {
1399 if (abuf_size == -1)
1400 dprintf_mciwave(stddeb,"Linux 'widOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
1401 else
1402 dprintf_mciwave(stddeb,"Linux 'widOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
1403 return MMSYSERR_NOTENABLED;
1405 WInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1406 switch(WInDev[wDevID].wFlags) {
1407 case DCB_NULL:
1408 dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_NULL !\n");
1409 break;
1410 case DCB_WINDOW:
1411 dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_WINDOW !\n");
1412 break;
1413 case DCB_TASK:
1414 dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_TASK !\n");
1415 break;
1416 case DCB_FUNCTION:
1417 dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_FUNCTION !\n");
1418 break;
1420 WInDev[wDevID].lp16QueueHdr = NULL;
1421 WInDev[wDevID].unixdev = audio;
1422 WInDev[wDevID].bufsize = abuf_size;
1423 WInDev[wDevID].dwTotalRecorded = 0;
1424 memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
1425 lpFormat = (LPWAVEFORMAT) PTR_SEG_TO_LIN(lpDesc->lpFormat);
1426 if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
1427 dprintf_mciwave(stddeb,"Linux 'widOpen' // Bad format %04X !\n",
1428 lpFormat->wFormatTag);
1429 return WAVERR_BADFORMAT;
1431 memcpy(&WInDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
1432 WInDev[wDevID].Format.wBitsPerSample = 8; /* <-------------- */
1433 if (WInDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
1434 if (WInDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
1435 if (WInDev[wDevID].Format.wBitsPerSample == 0) {
1436 WInDev[wDevID].Format.wBitsPerSample = 8 *
1437 (WInDev[wDevID].Format.wf.nAvgBytesPerSec /
1438 WInDev[wDevID].Format.wf.nSamplesPerSec) /
1439 WInDev[wDevID].Format.wf.nChannels;
1441 samplesize = WInDev[wDevID].Format.wBitsPerSample;
1442 smplrate = WInDev[wDevID].Format.wf.nSamplesPerSec;
1443 dsp_stereo = (WInDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
1444 IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
1445 IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
1446 IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
1447 dprintf_mciwave(stddeb,"Linux 'widOpen' // wBitsPerSample=%u !\n",
1448 WInDev[wDevID].Format.wBitsPerSample);
1449 dprintf_mciwave(stddeb,"Linux 'widOpen' // nSamplesPerSec=%lu !\n",
1450 WInDev[wDevID].Format.wf.nSamplesPerSec);
1451 dprintf_mciwave(stddeb,"Linux 'widOpen' // nChannels=%u !\n",
1452 WInDev[wDevID].Format.wf.nChannels);
1453 dprintf_mciwave(stddeb,"Linux 'widOpen' // nAvgBytesPerSec=%lu\n",
1454 WInDev[wDevID].Format.wf.nAvgBytesPerSec);
1455 if (WAVE_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
1456 dprintf_mciwave(stddeb,"Linux 'widOpen' // can't notify client !\n");
1457 return MMSYSERR_INVALPARAM;
1459 return MMSYSERR_NOERROR;
1462 /**************************************************************************
1463 * widClose [internal]
1465 static DWORD widClose(WORD wDevID)
1467 dprintf_mciwave(stddeb,"widClose(%u);\n", wDevID);
1468 if (wDevID > MAX_WAVINDRV) return MMSYSERR_INVALPARAM;
1469 if (WInDev[wDevID].unixdev == 0) {
1470 dprintf_mciwave(stddeb,"Linux 'widClose' // can't close !\n");
1471 return MMSYSERR_NOTENABLED;
1473 if (WInDev[wDevID].lp16QueueHdr != NULL) {
1474 dprintf_mciwave(stddeb,"linux 'widclose' // still buffers open !\n");
1475 return WAVERR_STILLPLAYING;
1477 close(WInDev[wDevID].unixdev);
1478 WInDev[wDevID].unixdev = 0;
1479 WInDev[wDevID].bufsize = 0;
1480 if (WAVE_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
1481 dprintf_mciwave(stddeb,"Linux 'widClose' // can't notify client !\n");
1482 return MMSYSERR_INVALPARAM;
1484 return MMSYSERR_NOERROR;
1487 /**************************************************************************
1488 * widAddBuffer [internal]
1490 static DWORD widAddBuffer(WORD wDevID, SEGPTR lp16WaveHdr, DWORD dwSize)
1492 int count = 1;
1493 LPWAVEHDR lpWIHdr;
1494 LPWAVEHDR lpWaveHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(lp16WaveHdr);
1496 dprintf_mciwave(stddeb,
1497 "widAddBuffer(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1498 if (WInDev[wDevID].unixdev == 0) {
1499 dprintf_mciwave(stddeb,"Linux 'widAddBuffer' // can't do it !\n");
1500 return MMSYSERR_NOTENABLED;
1502 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
1503 dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // never been prepared !\n");
1504 return WAVERR_UNPREPARED;
1506 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
1507 dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // header already in use !\n");
1508 return WAVERR_STILLPLAYING;
1510 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1511 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1512 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1513 lpWaveHdr->dwBytesRecorded = 0;
1514 if (WInDev[wDevID].lp16QueueHdr == NULL) {
1515 /* begin the queue with a first header ... */
1516 WInDev[wDevID].lp16QueueHdr = lp16WaveHdr;
1517 WInDev[wDevID].dwTotalRecorded = 0;
1519 else {
1520 /* added to the queue, except if it's the one just prepared ... */
1521 lpWIHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(WInDev[wDevID].lp16QueueHdr);
1522 while (lpWIHdr->lp16Next != NULL) {
1523 lpWIHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(lpWIHdr->lp16Next);
1524 count++;
1526 lpWIHdr->lp16Next = lp16WaveHdr;
1527 count++;
1529 dprintf_mciwave(stddeb,
1530 "widAddBuffer // buffer added ! (now %u in queue)\n", count);
1531 return MMSYSERR_NOERROR;
1534 /**************************************************************************
1535 * widPrepare [internal]
1537 static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1539 dprintf_mciwave(stddeb,
1540 "widPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1541 if (WInDev[wDevID].unixdev == 0) {
1542 dprintf_mciwave(stddeb,"Linux 'widPrepare' // can't prepare !\n");
1543 return MMSYSERR_NOTENABLED;
1545 if (WInDev[wDevID].lp16QueueHdr != NULL) {
1546 dprintf_mciwave(stddeb,"Linux 'widPrepare' // already prepare !\n");
1547 return WAVERR_BADFORMAT;
1549 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
1550 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1551 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1552 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1553 lpWaveHdr->dwBytesRecorded = 0;
1554 dprintf_mciwave(stddeb,"Linux 'widPrepare' // header prepared !\n");
1555 return MMSYSERR_NOERROR;
1558 /**************************************************************************
1559 * widUnprepare [internal]
1561 static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1563 dprintf_mciwave(stddeb,
1564 "widUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1565 if (WInDev[wDevID].unixdev == 0) {
1566 dprintf_mciwave(stddeb,"Linux 'widUnprepare' // can't unprepare !\n");
1567 return MMSYSERR_NOTENABLED;
1569 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1570 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1571 lpWaveHdr->dwFlags |= WHDR_DONE;
1572 WInDev[wDevID].lp16QueueHdr = NULL;
1573 dprintf_mciwave(stddeb,
1574 "Linux 'widUnprepare' // all headers unprepared !\n");
1575 return MMSYSERR_NOERROR;
1578 /**************************************************************************
1579 * widStart [internal]
1581 static DWORD widStart(WORD wDevID)
1583 int count = 1;
1584 int bytesRead;
1585 LPWAVEHDR lpWIHdr;
1586 SEGPTR lp16WaveHdr;
1588 dprintf_mciwave(stddeb,"widStart(%u);\n", wDevID);
1589 if (WInDev[wDevID].unixdev == 0) {
1590 dprintf_mciwave(stddeb, "Linux 'widStart' // can't start recording !\n");
1591 return MMSYSERR_NOTENABLED;
1594 lp16WaveHdr = WInDev[wDevID].lp16QueueHdr;
1595 dprintf_mciwave(stddeb,"Linux 'widstart'// lp16WaveHdr = %08lx\n",(DWORD)lp16WaveHdr);
1596 if (lp16WaveHdr == NULL ||
1597 ((LPWAVEHDR)PTR_SEG_TO_LIN(lp16WaveHdr))->lpData == NULL) {
1598 dprintf_mciwave(stddeb,"Linux 'widStart' // never been prepared !\n");
1599 return WAVERR_UNPREPARED;
1602 while(lp16WaveHdr != NULL) {
1603 lpWIHdr = (LPWAVEHDR)PTR_SEG_TO_LIN(lp16WaveHdr);
1604 lpWIHdr->dwBufferLength &= 0xFFFF;
1605 dprintf_mciwave(stddeb,
1606 "widStart // recording buf#%u=%p size=%lu \n",
1607 count, lpWIHdr->lpData, lpWIHdr->dwBufferLength);
1608 fflush(stddeb);
1609 bytesRead = read (WInDev[wDevID].unixdev,
1610 PTR_SEG_TO_LIN(lpWIHdr->lpData),
1611 lpWIHdr->dwBufferLength);
1612 lpWIHdr->dwBytesRecorded = bytesRead;
1613 WInDev[wDevID].dwTotalRecorded += lpWIHdr->dwBytesRecorded;
1614 lpWIHdr->dwFlags &= ~WHDR_INQUEUE;
1615 lpWIHdr->dwFlags |= WHDR_DONE;
1617 if (WAVE_NotifyClient(wDevID, WIM_DATA, (DWORD)lp16WaveHdr, lpWIHdr->dwBytesRecorded) !=
1618 MMSYSERR_NOERROR) {
1619 dprintf_mciwave(stddeb, "Linux 'widStart' // can't notify client !\n");
1620 return MMSYSERR_INVALPARAM;
1622 lp16WaveHdr = lpWIHdr->lp16Next ;
1623 count++;
1625 dprintf_mciwave(stddeb,"widStart // end of recording !\n");
1626 fflush(stddeb);
1627 return MMSYSERR_NOERROR;
1630 /**************************************************************************
1631 * widStop [internal]
1633 static DWORD widStop(WORD wDevID)
1635 dprintf_mciwave(stddeb,"widStop(%u);\n", wDevID);
1636 if (WInDev[wDevID].unixdev == 0) {
1637 dprintf_mciwave(stddeb,"Linux 'widStop' // can't stop !\n");
1638 return MMSYSERR_NOTENABLED;
1640 return MMSYSERR_NOERROR;
1643 /**************************************************************************
1644 * widReset [internal]
1646 static DWORD widReset(WORD wDevID)
1648 dprintf_mciwave(stddeb,"widReset(%u);\n", wDevID);
1649 if (WInDev[wDevID].unixdev == 0) {
1650 dprintf_mciwave(stddeb,"Linux 'widReset' // can't reset !\n");
1651 return MMSYSERR_NOTENABLED;
1653 return MMSYSERR_NOERROR;
1656 /**************************************************************************
1657 * widGetPosition [internal]
1659 static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
1661 int time;
1663 dprintf_mciwave(stddeb,
1664 "widGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1665 if (WInDev[wDevID].unixdev == 0) {
1666 dprintf_mciwave(stddeb,"Linux 'widGetPosition' // can't get pos !\n");
1667 return MMSYSERR_NOTENABLED;
1669 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1670 dprintf_mciwave(stddeb,"widGetPosition // wType=%04X !\n",
1671 lpTime->wType);
1672 dprintf_mciwave(stddeb,"widGetPosition // wBitsPerSample=%u\n",
1673 WInDev[wDevID].Format.wBitsPerSample);
1674 dprintf_mciwave(stddeb,"widGetPosition // nSamplesPerSec=%lu\n",
1675 WInDev[wDevID].Format.wf.nSamplesPerSec);
1676 dprintf_mciwave(stddeb,"widGetPosition // nChannels=%u\n",
1677 WInDev[wDevID].Format.wf.nChannels);
1678 dprintf_mciwave(stddeb,"widGetPosition // nAvgBytesPerSec=%lu\n",
1679 WInDev[wDevID].Format.wf.nAvgBytesPerSec);
1680 fflush(stddeb);
1681 switch(lpTime->wType) {
1682 case TIME_BYTES:
1683 lpTime->u.cb = WInDev[wDevID].dwTotalRecorded;
1684 dprintf_mciwave(stddeb,
1685 "widGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb);
1686 break;
1687 case TIME_SAMPLES:
1688 lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 /
1689 WInDev[wDevID].Format.wBitsPerSample;
1690 dprintf_mciwave(stddeb,
1691 "widGetPosition // TIME_SAMPLES=%lu\n",
1692 lpTime->u.sample);
1693 break;
1694 case TIME_SMPTE:
1695 time = WInDev[wDevID].dwTotalRecorded /
1696 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1697 lpTime->u.smpte.hour = time / 108000;
1698 time -= lpTime->u.smpte.hour * 108000;
1699 lpTime->u.smpte.min = time / 1800;
1700 time -= lpTime->u.smpte.min * 1800;
1701 lpTime->u.smpte.sec = time / 30;
1702 time -= lpTime->u.smpte.sec * 30;
1703 lpTime->u.smpte.frame = time;
1704 lpTime->u.smpte.fps = 30;
1705 dprintf_mciwave(stddeb,"widGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1706 lpTime->u.smpte.hour, lpTime->u.smpte.min,
1707 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1708 break;
1709 default:
1710 dprintf_mciwave(stddeb,"widGetPosition() format not supported ! use TIME_MS !\n");
1711 lpTime->wType = TIME_MS;
1712 case TIME_MS:
1713 lpTime->u.ms = WInDev[wDevID].dwTotalRecorded /
1714 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1715 dprintf_mciwave(stddeb,
1716 "widGetPosition // TIME_MS=%lu\n", lpTime->u.ms);
1717 break;
1719 return MMSYSERR_NOERROR;
1722 #endif /* linux || __FreeBSD__ */
1724 /**************************************************************************
1725 * widMessage [sample driver]
1727 DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1728 DWORD dwParam1, DWORD dwParam2)
1730 dprintf_mciwave(stddeb,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1731 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1732 #if defined(linux) || defined(__FreeBSD__)
1733 switch(wMsg) {
1734 case WIDM_OPEN:
1735 return widOpen(wDevID, (LPWAVEOPENDESC)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1736 case WIDM_CLOSE:
1737 return widClose(wDevID);
1738 case WIDM_ADDBUFFER:
1739 return widAddBuffer(wDevID, dwParam1, dwParam2);
1740 case WIDM_PREPARE:
1741 return widPrepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1742 case WIDM_UNPREPARE:
1743 return widUnprepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1744 case WIDM_GETDEVCAPS:
1745 return widGetDevCaps(wDevID, (LPWAVEINCAPS)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1746 case WIDM_GETNUMDEVS:
1747 return 1;
1748 case WIDM_GETPOS:
1749 return widGetPosition(wDevID, (LPMMTIME)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1750 case WIDM_RESET:
1751 return widReset(wDevID);
1752 case WIDM_START:
1753 return widStart(wDevID);
1754 case WIDM_PAUSE:
1755 return widStop(wDevID);
1756 case WIDM_STOP:
1757 return widStop(wDevID);
1758 default:
1759 dprintf_mciwave(stddeb,"widMessage // unknown message !\n");
1761 return MMSYSERR_NOTSUPPORTED;
1762 #else
1763 return MMSYSERR_NOTENABLED;
1764 #endif
1768 /**************************************************************************
1769 * AUDIO_DriverProc [sample driver]
1771 LONG WAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
1772 DWORD dwParam1, DWORD dwParam2)
1774 #if defined(linux) || defined(__FreeBSD__)
1775 dprintf_mciwave(stddeb,"WAVE_DriverProc(%08lX, %04X, %04X, %08lX, %08lX)\n",
1776 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1777 switch(wMsg) {
1778 case DRV_LOAD:
1779 return 1;
1780 case DRV_FREE:
1781 return 1;
1782 case DRV_OPEN:
1783 return 1;
1784 case DRV_CLOSE:
1785 return 1;
1786 case DRV_ENABLE:
1787 return 1;
1788 case DRV_DISABLE:
1789 return 1;
1790 case DRV_QUERYCONFIGURE:
1791 return 1;
1792 case DRV_CONFIGURE:
1793 MessageBox16(0, "Sample MultiMedia Linux Driver !",
1794 "MMLinux Driver", MB_OK);
1795 return 1;
1796 case DRV_INSTALL:
1797 return DRVCNF_RESTART;
1798 case DRV_REMOVE:
1799 return DRVCNF_RESTART;
1800 case MCI_OPEN_DRIVER:
1801 case MCI_OPEN:
1802 return WAVE_mciOpen(dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS)PTR_SEG_TO_LIN(dwParam2));
1803 case MCI_CUE:
1804 return WAVE_mciCue(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1805 case MCI_CLOSE_DRIVER:
1806 case MCI_CLOSE:
1807 return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1808 case MCI_PLAY:
1809 return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
1810 case MCI_RECORD:
1811 return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2));
1812 case MCI_STOP:
1813 return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1814 case MCI_SET:
1815 return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
1816 case MCI_PAUSE:
1817 return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1818 case MCI_RESUME:
1819 return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1820 case MCI_STATUS:
1821 return WAVE_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1822 case MCI_GETDEVCAPS:
1823 return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1824 case MCI_INFO:
1825 return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS)PTR_SEG_TO_LIN(dwParam2));
1827 case MCI_LOAD:
1828 return MMSYSERR_NOTSUPPORTED;
1829 case MCI_SAVE:
1830 return MMSYSERR_NOTSUPPORTED;
1831 case MCI_SEEK:
1832 return MMSYSERR_NOTSUPPORTED;
1833 case MCI_FREEZE:
1834 return MMSYSERR_NOTSUPPORTED;
1835 case MCI_PUT:
1836 return MMSYSERR_NOTSUPPORTED;
1837 case MCI_REALIZE:
1838 return MMSYSERR_NOTSUPPORTED;
1839 case MCI_UNFREEZE:
1840 return MMSYSERR_NOTSUPPORTED;
1841 case MCI_UPDATE:
1842 return MMSYSERR_NOTSUPPORTED;
1843 case MCI_WHERE:
1844 return MMSYSERR_NOTSUPPORTED;
1845 case MCI_WINDOW:
1846 return MMSYSERR_NOTSUPPORTED;
1847 case MCI_STEP:
1848 return MMSYSERR_NOTSUPPORTED;
1849 case MCI_SPIN:
1850 return MMSYSERR_NOTSUPPORTED;
1851 case MCI_ESCAPE:
1852 return MMSYSERR_NOTSUPPORTED;
1853 case MCI_COPY:
1854 return MMSYSERR_NOTSUPPORTED;
1855 case MCI_CUT:
1856 return MMSYSERR_NOTSUPPORTED;
1857 case MCI_DELETE:
1858 return MMSYSERR_NOTSUPPORTED;
1859 case MCI_PASTE:
1860 return MMSYSERR_NOTSUPPORTED;
1862 default:
1863 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1865 #else
1866 return MMSYSERR_NOTENABLED;
1867 #endif