Release 950901
[wine] / multimedia / audio.c
1 /*                                 
2  * Sample Wine Driver for Linux
3  *
4  * Copyright 1994 Martin Ayotte
5  */
6
7 #ifndef WINELIB
8 #define BUILTIN_MMSYSTEM
9 #endif 
10
11 #ifdef BUILTIN_MMSYSTEM
12
13 #define EMULATE_SB16
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <sys/ioctl.h>
20 #include "windows.h"
21 #include "user.h"
22 #include "driver.h"
23 #include "mmsystem.h"
24 #include "ldt.h"
25 #include "stackframe.h"
26
27 #ifdef linux
28 #include <linux/soundcard.h>
29 #endif
30
31 #include "stddebug.h"
32 #include "debug.h"
33
34 #ifdef linux
35 #define SOUND_DEV "/dev/dsp"
36
37 #ifdef SOUND_VERSION
38 #define IOCTL(a,b,c)            ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
39 #else
40 #define IOCTL(a,b,c)            (c = ioctl(a,b,c) )
41 #endif
42
43 #define MAX_WAVOUTDRV   2
44 #define MAX_WAVINDRV    2
45 #define MAX_MCIWAVDRV   2
46
47 typedef struct {
48         int                             unixdev;
49         int                             state;
50         DWORD                   bufsize;
51         WAVEOPENDESC    waveDesc;
52         WORD                    wFlags;
53         PCMWAVEFORMAT   Format;
54         LPWAVEHDR               lpQueueHdr;
55         DWORD                   dwTotalPlayed;
56         } LINUX_WAVEOUT;
57
58 typedef struct {
59         int                             unixdev;
60         int                             state;
61         DWORD                   bufsize;        /* Linux '/dev/dsp' give us that size */
62         WAVEOPENDESC    waveDesc;
63         WORD                    wFlags;
64         PCMWAVEFORMAT   Format;
65         LPWAVEHDR               lpQueueHdr;
66         DWORD                   dwTotalRecorded;
67         } LINUX_WAVEIN;
68
69 typedef struct {
70     int     nUseCount;          /* Incremented for each shared open */
71     BOOL    fShareable;         /* TRUE if first open was shareable */
72     WORD    wNotifyDeviceID;    /* MCI device ID with a pending notification */
73     HANDLE  hCallback;          /* Callback handle for pending notification */
74         HMMIO   hFile;                          /* mmio file handle open as Element             */
75         MCI_WAVE_OPEN_PARMS openParms;
76         PCMWAVEFORMAT   WaveFormat;
77         WAVEHDR         WaveHdr;
78         } LINUX_MCIWAVE;
79
80 static LINUX_WAVEOUT    WOutDev[MAX_WAVOUTDRV];
81 static LINUX_WAVEIN     WInDev[MAX_WAVOUTDRV];
82 static LINUX_MCIWAVE    MCIWavDev[MAX_MCIWAVDRV];
83
84
85 /**************************************************************************
86 *                               WAVE_NotifyClient                       [internal]
87 */
88 static DWORD WAVE_NotifyClient(UINT wDevID, WORD wMsg, 
89                                 DWORD dwParam1, DWORD dwParam2)
90 {
91         if (WInDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
92                 WInDev[wDevID].waveDesc.dwCallBack, WInDev[wDevID].wFlags, 
93                 WInDev[wDevID].waveDesc.hWave, wMsg, 
94                 WInDev[wDevID].waveDesc.dwInstance, dwParam1, dwParam2)) {
95                 dprintf_mciwave(stddeb,"WAVE_NotifyClient // can't notify client !\n");
96                 return MMSYSERR_NOERROR;
97                 }
98         return 0;
99 }
100
101
102 /**************************************************************************
103 *                               WAVE_mciOpen    */
104 static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMS lpParms)
105 {
106         HANDLE          hFormat;
107         LPPCMWAVEFORMAT lpWaveFormat;
108         HANDLE          hDesc;
109         LPWAVEOPENDESC  lpDesc;
110         LPSTR           lpstrElementName;
111         DWORD           dwRet;
112         char            str[128];
113
114         dprintf_mciwave(stddeb,"WAVE_mciOpen(%04X, %08lX, %p)\n", 
115                                 wDevID, dwFlags, lpParms);
116         if (lpParms == NULL) return MCIERR_INTERNAL;
117         dprintf_mciwave(stddeb,"WAVE_mciOpen // wDevID=%04X\n", wDevID);
118         if (MCIWavDev[wDevID].nUseCount > 0) {
119                 /* The driver already open on this channel */
120                 /* If the driver was opened shareable before and this open specifies */
121                 /* shareable then increment the use count */
122                 if (MCIWavDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
123                         ++MCIWavDev[wDevID].nUseCount;
124                 else
125                         return MCIERR_MUST_USE_SHAREABLE;
126                 }
127         else {
128                 MCIWavDev[wDevID].nUseCount = 1;
129                 MCIWavDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
130                 }
131         dprintf_mciwave(stddeb,"WAVE_mciOpen // before setting lParams->wDeviceID // winstack=%p ds=%04X ss=%04X sp=%04X\n",
132                 (BYTE *)CURRENT_STACK16->args, 
133                 CURRENT_STACK16->ds, IF1632_Saved16_ss, IF1632_Saved16_sp);
134         lpParms->wDeviceID = wDevID;
135         dprintf_mciwave(stddeb,"WAVE_mciOpen // wDevID=%04X\n", wDevID);
136         dprintf_mciwave(stddeb,"WAVE_mciOpen // before OPEN_ELEMENT\n");
137         if (dwFlags & MCI_OPEN_ELEMENT) {
138                 lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(lpParms->lpstrElementName);
139                 dprintf_mciwave(stddeb,"WAVE_mciOpen // MCI_OPEN_ELEMENT '%s' !\n",
140                                                 lpstrElementName);
141 /*              printf("WAVE_mciOpen // cdw='%s'\n", DOS_GetCurrentDir(DOS_GetDefaultDrive())); */
142                 if (strlen(lpstrElementName) > 0) {
143                         strcpy(str, lpstrElementName);
144                         AnsiUpper(str);
145                         MCIWavDev[wDevID].hFile = mmioOpen(str, NULL, 
146                                 MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
147                         if (MCIWavDev[wDevID].hFile == 0) {
148                                 dprintf_mciwave(stddeb,"WAVE_mciOpen // can't find file='%s' !\n", str);
149                                 return MCIERR_FILE_NOT_FOUND;
150                                 }
151                         }
152                 else 
153                         MCIWavDev[wDevID].hFile = 0;
154                 }
155         dprintf_mciwave(stddeb,"WAVE_mciOpen // hFile=%u\n", MCIWavDev[wDevID].hFile);
156         memcpy(&MCIWavDev[wDevID].openParms, lpParms, sizeof(MCI_WAVE_OPEN_PARMS));
157         MCIWavDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
158         lpWaveFormat = &MCIWavDev[wDevID].WaveFormat;
159         hDesc = USER_HEAP_ALLOC(sizeof(WAVEOPENDESC));
160         lpDesc = (LPWAVEOPENDESC) USER_HEAP_LIN_ADDR(hDesc);
161         lpDesc->hWave = 0;
162 /*
163         lpWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM;
164         lpWaveFormat->wBitsPerSample = 8;
165         lpWaveFormat->wf.nChannels = 1;
166         lpWaveFormat->wf.nSamplesPerSec = 11025;
167         lpWaveFormat->wf.nAvgBytesPerSec = 11025;
168         lpWaveFormat->wf.nBlockAlign = 1;
169 */
170         if (MCIWavDev[wDevID].hFile != 0) {
171                 MMCKINFO        mmckInfo;
172                 MMCKINFO        ckMainRIFF;
173                 if (mmioDescend(MCIWavDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0) {
174                         return MCIERR_INTERNAL;
175                         }
176                 dprintf_mciwave(stddeb,
177                                 "WAVE_mciOpen // ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
178                                 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
179                                 ckMainRIFF.cksize);
180                 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
181                     (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) {
182                         return MCIERR_INTERNAL;
183                         }
184                 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
185                 if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) {
186                         return MCIERR_INTERNAL;
187                         }
188                 dprintf_mciwave(stddeb,
189                                 "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
190                                 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
191                                 mmckInfo.cksize);
192                 if (mmioRead(MCIWavDev[wDevID].hFile, (HPSTR) lpWaveFormat,
193                     (long) sizeof(PCMWAVEFORMAT)) != (long) sizeof(PCMWAVEFORMAT)) {
194                         return MCIERR_INTERNAL;
195                         }
196                 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
197                 if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0) {
198                         return MCIERR_INTERNAL;
199                         }
200                 dprintf_mciwave(stddeb,
201                                 "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
202                                 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
203                                 mmckInfo.cksize);
204                 dprintf_mciwave(stddeb,
205                         "WAVE_mciOpen // nChannels=%d nSamplesPerSec=%ld\n",
206                         lpWaveFormat->wf.nChannels, lpWaveFormat->wf.nSamplesPerSec);
207                 lpWaveFormat->wBitsPerSample = 0;
208                 }
209         lpWaveFormat->wf.nAvgBytesPerSec = 
210                 lpWaveFormat->wf.nSamplesPerSec * lpWaveFormat->wf.nBlockAlign;
211         hFormat = USER_HEAP_ALLOC(sizeof(PCMWAVEFORMAT));
212         lpDesc->lpFormat = (LPWAVEFORMAT) USER_HEAP_LIN_ADDR(hFormat);
213         memcpy(lpDesc->lpFormat, lpWaveFormat, sizeof(PCMWAVEFORMAT));
214         lpDesc = (LPWAVEOPENDESC) USER_HEAP_SEG_ADDR(hDesc);
215         dwRet = wodMessage(0, WODM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL);
216         dwRet = widMessage(0, WIDM_OPEN, 0, (DWORD)lpDesc, CALLBACK_NULL);
217         USER_HEAP_FREE(hFormat);
218         USER_HEAP_FREE(hDesc);
219         return 0;
220 }
221
222 /**************************************************************************
223 *                               WAVE_mciClose           [internal]
224 */
225 static DWORD WAVE_mciClose(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
226 {
227         DWORD           dwRet;
228         dprintf_mciwave(stddeb,
229                 "WAVE_mciClose(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
230         MCIWavDev[wDevID].nUseCount--;
231         if (MCIWavDev[wDevID].nUseCount == 0) {
232                 if (MCIWavDev[wDevID].hFile != 0) {
233                         mmioClose(MCIWavDev[wDevID].hFile, 0);
234                         MCIWavDev[wDevID].hFile = 0;
235                         }
236                 dwRet = wodMessage(0, WODM_CLOSE, 0, 0L, 0L);
237                 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
238                 dwRet = widMessage(0, WIDM_CLOSE, 0, 0L, 0L);
239                 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
240                 }
241         return 0;
242 }
243
244
245 /**************************************************************************
246 *                               WAVE_mciPlay            [internal]
247 */
248 static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
249 {
250         int                             start, end;
251         LONG                    bufsize, count;
252         HANDLE                  hData;
253         HANDLE                  hWaveHdr;
254         LPWAVEHDR               lpWaveHdr;
255         LPWAVEHDR               lp16WaveHdr;
256         DWORD                   dwRet;
257         dprintf_mciwave(stddeb,
258                  "WAVE_mciPlay(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
259         if (MCIWavDev[wDevID].hFile == 0) {
260         dprintf_mciwave(stddeb,"WAVE_mciPlay // can't find file='%s' !\n",
261                                 MCIWavDev[wDevID].openParms.lpstrElementName);
262                 return MCIERR_FILE_NOT_FOUND;
263                 }
264         start = 1;              end = 99999;
265         if (dwFlags & MCI_FROM) {
266                 start = lpParms->dwFrom; 
267                 dprintf_mciwave(stddeb,
268                                 "WAVE_mciPlay // MCI_FROM=%d \n", start);
269                 }
270         if (dwFlags & MCI_TO) {
271                 end = lpParms->dwTo;
272                 dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_TO=%d \n", end);
273                 }
274 #if 0
275         if (dwFlags & MCI_NOTIFY) {
276         dprintf_mciwave(stddeb,
277                 "WAVE_mciPlay // MCI_NOTIFY %08lX !\n", lpParms->dwCallback);
278                 switch(fork()) {
279                         case -1:
280                                 dprintf_mciwave(stddeb,
281                                   "WAVE_mciPlay // Can't 'fork' process !\n");
282                                 break;
283                         case 0:
284                                 break;         
285                         default:
286                                 dprintf_mciwave(stddeb,"WAVE_mciPlay // process started ! return to caller...\n");
287                                 return 0;
288                         }
289                 }
290 #endif
291         bufsize = 64000;
292         lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
293         hData = GlobalAlloc(GMEM_MOVEABLE, bufsize);
294         lpWaveHdr->lpData = (LPSTR) WIN16_GlobalLock(hData);
295         lpWaveHdr->dwUser = 0L;
296         lpWaveHdr->dwFlags = 0L;
297         lpWaveHdr->dwLoops = 0L;
298         hWaveHdr = USER_HEAP_ALLOC(sizeof(WAVEHDR));
299         lp16WaveHdr = (LPWAVEHDR) USER_HEAP_SEG_ADDR(hWaveHdr);
300         memcpy(PTR_SEG_TO_LIN(lp16WaveHdr), lpWaveHdr, sizeof(WAVEHDR));
301         lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr);
302         dwRet = wodMessage(0, WODM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
303         while(TRUE) {
304                 count = mmioRead(MCIWavDev[wDevID].hFile, 
305                         PTR_SEG_TO_LIN(lpWaveHdr->lpData), bufsize);
306                 dprintf_mciwave(stddeb,"WAVE_mciPlay // mmioRead bufsize=%ld count=%ld\n", bufsize, count);
307                 if (count < 1) break;
308                 lpWaveHdr->dwBufferLength = count;
309 /*              lpWaveHdr->dwBytesRecorded = count; */
310                 dprintf_mciwave(stddeb,"WAVE_mciPlay // before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
311                                 lpWaveHdr, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded);
312                 dwRet = wodMessage(0, WODM_WRITE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
313                 }
314         dwRet = wodMessage(0, WODM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
315         if (lpWaveHdr->lpData != NULL) {
316                 GlobalUnlock(hData);
317                 GlobalFree(hData);
318                 lpWaveHdr->lpData = NULL;
319                 }
320         USER_HEAP_FREE(hWaveHdr);
321         if (dwFlags & MCI_NOTIFY) {
322                 dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
323                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
324                         MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
325                 exit(0);
326                 }
327         return 0;
328 }
329
330
331 /**************************************************************************
332 *                               WAVE_mciRecord                  [internal]
333 */
334 static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
335 {
336         int                             start, end;
337         LONG                    bufsize;
338         HANDLE                  hData;
339         HANDLE                  hWaveHdr;
340         LPWAVEHDR               lpWaveHdr;
341         LPWAVEHDR               lp16WaveHdr;
342         DWORD                   dwRet;
343
344         dprintf_mciwave(stddeb,
345                 "WAVE_mciRecord(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
346         if (MCIWavDev[wDevID].hFile == 0) {
347                 dprintf_mciwave(stddeb,"WAVE_mciRecord // can't find file='%s' !\n", 
348                                 MCIWavDev[wDevID].openParms.lpstrElementName);
349                 return MCIERR_FILE_NOT_FOUND;
350                 }
351         start = 1;              end = 99999;
352         if (dwFlags & MCI_FROM) {
353                 start = lpParms->dwFrom; 
354                 dprintf_mciwave(stddeb,
355                                 "WAVE_mciRecord // MCI_FROM=%d \n", start);
356                 }
357         if (dwFlags & MCI_TO) {
358                 end = lpParms->dwTo;
359                 dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_TO=%d \n", end);
360                 }
361         bufsize = 64000;
362         lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
363         hData = GlobalAlloc(GMEM_MOVEABLE, bufsize);
364         lpWaveHdr->lpData = (LPSTR) WIN16_GlobalLock(hData);
365         lpWaveHdr->dwBufferLength = bufsize;
366         lpWaveHdr->dwUser = 0L;
367         lpWaveHdr->dwFlags = 0L;
368         lpWaveHdr->dwLoops = 0L;
369         hWaveHdr = USER_HEAP_ALLOC(sizeof(WAVEHDR));
370         lp16WaveHdr = (LPWAVEHDR) USER_HEAP_SEG_ADDR(hWaveHdr);
371         memcpy(PTR_SEG_TO_LIN(lp16WaveHdr), lpWaveHdr, sizeof(WAVEHDR));
372         lpWaveHdr = PTR_SEG_TO_LIN(lp16WaveHdr);
373         dwRet = widMessage(0, WIDM_PREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
374     dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_PREPARE \n");
375         while(TRUE) {
376                 lpWaveHdr->dwBytesRecorded = 0;
377                 dwRet = widMessage(0, WIDM_START, 0, 0L, 0L);
378                 dprintf_mciwave(stddeb,
379                     "WAVE_mciRecord // after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
380                                         lpWaveHdr, lpWaveHdr->dwBytesRecorded);
381                 if (lpWaveHdr->dwBytesRecorded == 0) break;
382                 }
383         dprintf_mciwave(stddeb,"WAVE_mciRecord // before WIDM_UNPREPARE \n");
384         dwRet = widMessage(0, WIDM_UNPREPARE, 0, (DWORD)lp16WaveHdr, sizeof(WAVEHDR));
385         dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_UNPREPARE \n");
386         if (lpWaveHdr->lpData != NULL) {
387                 GlobalUnlock(hData);
388                 GlobalFree(hData);
389                 lpWaveHdr->lpData = NULL;
390                 }
391         USER_HEAP_FREE(hWaveHdr);
392         if (dwFlags & MCI_NOTIFY) {
393           dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
394                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
395                         MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
396                 }
397         return 0;
398 }
399
400
401 /**************************************************************************
402 *                               WAVE_mciStop                    [internal]
403 */
404 static DWORD WAVE_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
405 {
406         dprintf_mciwave(stddeb,
407                 "WAVE_mciStop(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
408         if (lpParms == NULL) return MCIERR_INTERNAL;
409         return 0;
410 }
411
412
413 /**************************************************************************
414 *                               WAVE_mciPause                   [internal]
415 */
416 static DWORD WAVE_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
417 {
418         dprintf_mciwave(stddeb,
419                 "WAVE_mciPause(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
420         if (lpParms == NULL) return MCIERR_INTERNAL;
421         return 0;
422 }
423
424
425 /**************************************************************************
426 *                               WAVE_mciResume                  [internal]
427 */
428 static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
429 {
430         dprintf_mciwave(stddeb,
431                 "WAVE_mciResume(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
432         if (lpParms == NULL) return MCIERR_INTERNAL;
433         return 0;
434 }
435
436
437 /**************************************************************************
438 *                               WAVE_mciSet                     [internal]
439 */
440 static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
441 {
442         dprintf_mciwave(stddeb,
443                 "WAVE_mciSet(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
444         if (lpParms == NULL) return MCIERR_INTERNAL;
445         dprintf_mciwave(stddeb,
446                  "WAVE_mciSet // dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
447         dprintf_mciwave(stddeb,
448                  "WAVE_mciSet // dwAudio=%08lX\n", lpParms->dwAudio);
449         if (dwFlags & MCI_SET_TIME_FORMAT) {
450                 switch (lpParms->dwTimeFormat) {
451                         case MCI_FORMAT_MILLISECONDS:
452                                 dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_MILLISECONDS !\n");
453                                 break;
454                         case MCI_FORMAT_BYTES:
455                                 dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_BYTES !\n");
456                                 break;
457                         case MCI_FORMAT_SAMPLES:
458                                 dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_SAMPLES !\n");
459                                 break;
460                         default:
461                                 dprintf_mciwave(stddeb, "WAVE_mciSet // bad time format !\n");
462                                 return MCIERR_BAD_TIME_FORMAT;
463                         }
464                 }
465         if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
466         if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION;
467         if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION;
468         if (dwFlags & MCI_SET_AUDIO) 
469           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO !\n");
470         if (dwFlags && MCI_SET_ON) {
471           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_ON !\n");
472           if (dwFlags && MCI_SET_AUDIO_LEFT) 
473             dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_LEFT !\n");
474           if (dwFlags && MCI_SET_AUDIO_RIGHT) 
475             dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_RIGHT !\n");
476         }
477         if (dwFlags & MCI_SET_OFF) 
478           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_OFF !\n");
479         if (dwFlags & MCI_WAVE_INPUT) 
480           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_INPUT !\n");
481         if (dwFlags & MCI_WAVE_OUTPUT) 
482           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_OUTPUT !\n");
483         if (dwFlags & MCI_WAVE_SET_ANYINPUT) 
484           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYINPUT !\n");
485         if (dwFlags & MCI_WAVE_SET_ANYOUTPUT) 
486           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYOUTPUT !\n");
487         if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) 
488           dprintf_mciwave(stddeb,
489                           "WAVE_mciSet // MCI_WAVE_SET_AVGBYTESPERSEC !\n");
490         if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) 
491           dprintf_mciwave(stddeb,
492                           "WAVE_mciSet // MCI_WAVE_SET_BITSPERSAMPLE !\n");
493         if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) 
494           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_BLOCKALIGN !\n");
495         if (dwFlags & MCI_WAVE_SET_CHANNELS) 
496           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_CHANNELS !\n");
497         if (dwFlags & MCI_WAVE_SET_FORMATTAG) 
498           dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_FORMATTAG !\n");
499         if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) 
500           dprintf_mciwave(stddeb,
501                           "WAVE_mciSet // MCI_WAVE_SET_SAMPLESPERSEC !\n");
502         return 0;
503 }
504
505
506 /**************************************************************************
507 *                               WAVE_mciStatus          [internal]
508 */
509 static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
510 {
511         dprintf_mciwave(stddeb,
512                 "WAVE_mciStatus(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
513         if (lpParms == NULL) return MCIERR_INTERNAL;
514         if (dwFlags & MCI_STATUS_ITEM) {
515                 switch(lpParms->dwItem) {
516                         case MCI_STATUS_CURRENT_TRACK:
517                                 lpParms->dwReturn = 1;
518                                 break;
519                         case MCI_STATUS_LENGTH:
520                                 lpParms->dwReturn = 5555;
521                                 if (dwFlags & MCI_TRACK) {
522                                         lpParms->dwTrack = 1;
523                                         lpParms->dwReturn = 2222;
524                                         }
525                                 break;
526                         case MCI_STATUS_MODE:
527                                 lpParms->dwReturn = MCI_MODE_STOP;
528                                 break;
529                         case MCI_STATUS_MEDIA_PRESENT:
530                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_MEDIA_PRESENT !\n");
531                                 lpParms->dwReturn = TRUE;
532                                 break;
533                         case MCI_STATUS_NUMBER_OF_TRACKS:
534                                 lpParms->dwReturn = 1;
535                                 break;
536                         case MCI_STATUS_POSITION:
537                                 lpParms->dwReturn = 3333;
538                                 if (dwFlags & MCI_STATUS_START) {
539                                         lpParms->dwItem = 1;
540                                         }
541                                 if (dwFlags & MCI_TRACK) {
542                                         lpParms->dwTrack = 1;
543                                         lpParms->dwReturn = 777;
544                                         }
545                                 break;
546                         case MCI_STATUS_READY:
547                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_READY !\n");
548                                 lpParms->dwReturn = TRUE;
549                                 break;
550                         case MCI_STATUS_TIME_FORMAT:
551                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_TIME_FORMAT !\n");
552                                 lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
553                                 break;
554                         case MCI_WAVE_INPUT:
555                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_INPUT !\n");
556                                 lpParms->dwReturn = 0;
557                                 break;
558                         case MCI_WAVE_OUTPUT:
559                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_OUTPUT !\n");
560                                 lpParms->dwReturn = 0;
561                                 break;
562                         case MCI_WAVE_STATUS_AVGBYTESPERSEC:
563                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_AVGBYTESPERSEC !\n");
564                                 lpParms->dwReturn = 22050;
565                                 break;
566                         case MCI_WAVE_STATUS_BITSPERSAMPLE:
567                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BITSPERSAMPLE !\n");
568                                 lpParms->dwReturn = 8;
569                                 break;
570                         case MCI_WAVE_STATUS_BLOCKALIGN:
571                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BLOCKALIGN !\n");
572                                 lpParms->dwReturn = 1;
573                                 break;
574                         case MCI_WAVE_STATUS_CHANNELS:
575                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_CHANNELS !\n");
576                                 lpParms->dwReturn = 1;
577                                 break;
578                         case MCI_WAVE_STATUS_FORMATTAG:
579                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_FORMATTAG !\n");
580                                 lpParms->dwReturn = WAVE_FORMAT_PCM;
581                                 break;
582                         case MCI_WAVE_STATUS_LEVEL:
583                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_LEVEL !\n");
584                                 lpParms->dwReturn = 0xAAAA5555;
585                                 break;
586                         case MCI_WAVE_STATUS_SAMPLESPERSEC:
587                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_SAMPLESPERSEC !\n");
588                                 lpParms->dwReturn = 22050;
589                                 break;
590                         default:
591                                 dprintf_mciwave(stddeb,"WAVE_mciStatus // unknown command %08lX !\n", lpParms->dwItem);
592                                 return MCIERR_UNRECOGNIZED_COMMAND;
593                         }
594                 }
595         if (dwFlags & MCI_NOTIFY) {
596                 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
597                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
598                         MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
599                 }
600         return 0;
601 }
602
603 /**************************************************************************
604 *                               WAVE_mciGetDevCaps              [internal]
605 */
606 static DWORD WAVE_mciGetDevCaps(UINT wDevID, DWORD dwFlags, 
607                                         LPMCI_GETDEVCAPS_PARMS lpParms)
608 {
609         dprintf_mciwave(stddeb,
610                 "WAVE_mciGetDevCaps(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
611         if (lpParms == NULL) return MCIERR_INTERNAL;
612         if (dwFlags & MCI_GETDEVCAPS_ITEM) {
613                 switch(lpParms->dwItem) {
614                         case MCI_GETDEVCAPS_CAN_RECORD:
615                                 lpParms->dwReturn = TRUE;
616                                 break;
617                         case MCI_GETDEVCAPS_HAS_AUDIO:
618                                 lpParms->dwReturn = TRUE;
619                                 break;
620                         case MCI_GETDEVCAPS_HAS_VIDEO:
621                                 lpParms->dwReturn = FALSE;
622                                 break;
623                         case MCI_GETDEVCAPS_DEVICE_TYPE:
624                                 lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
625                                 break;
626                         case MCI_GETDEVCAPS_USES_FILES:
627                                 lpParms->dwReturn = TRUE;
628                                 break;
629                         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
630                                 lpParms->dwReturn = TRUE;
631                                 break;
632                         case MCI_GETDEVCAPS_CAN_EJECT:
633                                 lpParms->dwReturn = FALSE;
634                                 break;
635                         case MCI_GETDEVCAPS_CAN_PLAY:
636                                 lpParms->dwReturn = TRUE;
637                                 break;
638                         case MCI_GETDEVCAPS_CAN_SAVE:
639                                 lpParms->dwReturn = TRUE;
640                                 break;
641                         case MCI_WAVE_GETDEVCAPS_INPUTS:
642                                 lpParms->dwReturn = 1;
643                                 break;
644                         case MCI_WAVE_GETDEVCAPS_OUTPUTS:
645                                 lpParms->dwReturn = 1;
646                                 break;
647                         default:
648                                 return MCIERR_UNRECOGNIZED_COMMAND;
649                         }
650                 }
651         return 0;
652 }
653
654 /**************************************************************************
655 *                               WAVE_mciInfo                    [internal]
656 */
657 static DWORD WAVE_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMS lpParms)
658 {
659         dprintf_mciwave(stddeb,
660                 "WAVE_mciInfo(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
661         if (lpParms == NULL) return MCIERR_INTERNAL;
662         lpParms->lpstrReturn = NULL;
663         switch(dwFlags) {
664                 case MCI_INFO_PRODUCT:
665                         lpParms->lpstrReturn = "Linux Sound System 0.5";
666                         break;
667                 case MCI_INFO_FILE:
668                         lpParms->lpstrReturn = 
669                                 (LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName;
670                         break;
671                 case MCI_WAVE_INPUT:
672                         lpParms->lpstrReturn = "Linux Sound System 0.5";
673                         break;
674                 case MCI_WAVE_OUTPUT:
675                         lpParms->lpstrReturn = "Linux Sound System 0.5";
676                         break;
677                 default:
678                         return MCIERR_UNRECOGNIZED_COMMAND;
679                 }
680         if (lpParms->lpstrReturn != NULL)
681                 lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
682         else
683                 lpParms->dwRetSize = 0;
684         return 0;
685 }
686
687
688 /*-----------------------------------------------------------------------*/
689
690
691 /**************************************************************************
692 *                               wodGetDevCaps                           [internal]
693 */
694 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS lpCaps, DWORD dwSize)
695 {
696         int     audio;
697         int             smplrate;
698         int             samplesize = 16;
699         int             dsp_stereo = 1;
700         int             bytespersmpl;
701         dprintf_mciwave(stddeb,
702                    "wodGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
703         if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
704         audio = open (SOUND_DEV, O_WRONLY, 0);
705         if (audio == -1) return MMSYSERR_NOTENABLED;
706 #ifdef EMULATE_SB16
707         lpCaps->wMid = 0x0002;
708         lpCaps->wPid = 0x0104;
709         strcpy(lpCaps->szPname, "SB16 Wave Out");
710 #else
711         lpCaps->wMid = 0x00FF;  /* Manufac ID */
712         lpCaps->wPid = 0x0001;  /* Product ID */
713         strcpy(lpCaps->szPname, "Linux WAVOUT Driver");
714 #endif
715         lpCaps->dwFormats = 0x00000000;
716         lpCaps->dwSupport = WAVECAPS_VOLUME;
717         lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
718         if (lpCaps->wChannels > 1) lpCaps->dwSupport |= WAVECAPS_LRVOLUME;
719         bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
720         smplrate = 44100;
721         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
722                 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
723                 if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_4S08;
724                 if (bytespersmpl > 1) {
725                         lpCaps->dwFormats |= WAVE_FORMAT_4M16;
726                         if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_4S16;
727                         }
728                 }
729         smplrate = 22050;
730         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
731                 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
732                 if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_2S08;
733                 if (bytespersmpl > 1) {
734                         lpCaps->dwFormats |= WAVE_FORMAT_2M16;
735                         if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_2S16;
736                         }
737                 }
738         smplrate = 11025;
739         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
740                 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
741                 if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_1S08;
742                 if (bytespersmpl > 1) {
743                         lpCaps->dwFormats |= WAVE_FORMAT_1M16;
744                         if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_1S16;
745                         }
746                 }
747         close(audio);
748         dprintf_mciwave(stddeb,
749                 "wodGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats);
750         return MMSYSERR_NOERROR;
751 }
752
753
754 /**************************************************************************
755 *                               wodOpen                         [internal]
756 */
757 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
758 {
759         int             audio;
760         int                     abuf_size;
761         int                     smplrate;
762         int                     samplesize;
763         int                     dsp_stereo;
764         LPWAVEFORMAT lpFormat;
765
766         dprintf_mciwave(stddeb,
767                 "wodOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
768         if (lpDesc == NULL) {
769                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Invalid Parameter !\n");
770                 return MMSYSERR_INVALPARAM;
771                 }
772         if (wDevID >= MAX_WAVOUTDRV) {
773                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // MAX_WAVOUTDRV reached !\n");
774                 return MMSYSERR_ALLOCATED;
775                 }
776         WOutDev[wDevID].unixdev = 0;
777         audio = open (SOUND_DEV, O_WRONLY, 0);
778         if (audio == -1) {
779                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't open !\n");
780                 return MMSYSERR_NOTENABLED;
781                 }
782         IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
783         if (abuf_size < 4096 || abuf_size > 65536) {
784                 if (abuf_size == -1)
785                         dprintf_mciwave(stddeb,"Linux 'wodOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
786                 else
787                         dprintf_mciwave(stddeb,"Linux 'wodOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
788                 return MMSYSERR_NOTENABLED;
789                 }
790         WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
791         switch(WOutDev[wDevID].wFlags) {
792                 case DCB_NULL:
793                         dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_NULL !\n");
794                         break;
795                 case DCB_WINDOW:
796                         dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_WINDOW !\n");
797                         break;
798                 case DCB_TASK:
799                         dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_TASK !\n");
800                         break;
801                 case DCB_FUNCTION:
802                         dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_FUNCTION !\n");
803                         break;
804                 }
805         WOutDev[wDevID].lpQueueHdr = NULL;
806         WOutDev[wDevID].unixdev = audio;
807         WOutDev[wDevID].dwTotalPlayed = 0;
808         WOutDev[wDevID].bufsize = abuf_size;
809         memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
810 /*      lpFormat = (LPWAVEFORMAT) PTR_SEG_TO_LIN(lpDesc->lpFormat); */
811         lpFormat = lpDesc->lpFormat;
812         if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
813                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad format %04X !\n",
814                                 lpFormat->wFormatTag);
815                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nChannels %d !\n",
816                                 lpFormat->nChannels);
817                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nSamplesPerSec %ld !\n",
818                                 lpFormat->nSamplesPerSec);
819                 return WAVERR_BADFORMAT;
820                 }
821         memcpy(&WOutDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
822         if (WOutDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
823         if (WOutDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
824         dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n",
825                                 WOutDev[wDevID].Format.wBitsPerSample);
826         if (WOutDev[wDevID].Format.wBitsPerSample == 0) {
827                 WOutDev[wDevID].Format.wBitsPerSample = 8 *
828                 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec /
829                 WOutDev[wDevID].Format.wf.nSamplesPerSec) /
830                 WOutDev[wDevID].Format.wf.nChannels;
831                 }
832         samplesize = WOutDev[wDevID].Format.wBitsPerSample;
833         smplrate = WOutDev[wDevID].Format.wf.nSamplesPerSec;
834         dsp_stereo = (WOutDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
835         IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
836         IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
837         IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
838         dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n",
839                                 WOutDev[wDevID].Format.wBitsPerSample);
840         dprintf_mciwave(stddeb,"Linux 'wodOpen' // nAvgBytesPerSec=%lu !\n",
841                                 WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
842         dprintf_mciwave(stddeb,"Linux 'wodOpen' // nSamplesPerSec=%lu !\n",
843                                 WOutDev[wDevID].Format.wf.nSamplesPerSec);
844         dprintf_mciwave(stddeb,"Linux 'wodOpen' // nChannels=%u !\n",
845                                 WOutDev[wDevID].Format.wf.nChannels);
846         if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
847                 dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't notify client !\n");
848                 return MMSYSERR_INVALPARAM;
849                 }
850         return MMSYSERR_NOERROR;
851 }
852
853 /**************************************************************************
854 *                               wodClose                        [internal]
855 */
856 static DWORD wodClose(WORD wDevID)
857 {
858         dprintf_mciwave(stddeb,"wodClose(%u);\n", wDevID);
859         if (WOutDev[wDevID].unixdev == 0) {
860                 dprintf_mciwave(stddeb,"Linux 'wodClose' // can't close !\n");
861                 return MMSYSERR_NOTENABLED;
862                 }
863         close(WOutDev[wDevID].unixdev);
864         WOutDev[wDevID].unixdev = 0;
865         WOutDev[wDevID].bufsize = 0;
866         WOutDev[wDevID].lpQueueHdr = NULL;
867         if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
868                 dprintf_mciwave(stddeb,"Linux 'wodClose' // can't notify client !\n");
869                 return MMSYSERR_INVALPARAM;
870         }
871         return MMSYSERR_NOERROR;
872 }
873
874 /**************************************************************************
875 *                               wodWrite                        [internal]
876 */
877 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
878 {
879         int             count;
880         LPSTR   lpData;
881         dprintf_mciwave(stddeb,"wodWrite(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
882         if (WOutDev[wDevID].unixdev == 0) {
883         dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't play !\n");
884                 return MMSYSERR_NOTENABLED;
885                 }
886         if (lpWaveHdr->lpData == NULL) return WAVERR_UNPREPARED;
887         if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) return WAVERR_UNPREPARED;
888         if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
889         lpWaveHdr->dwFlags &= ~WHDR_DONE;
890         lpWaveHdr->dwFlags |= WHDR_INQUEUE;
891         dprintf_mciwave(stddeb,
892                 "wodWrite() // dwBufferLength %lu !\n", lpWaveHdr->dwBufferLength);
893         dprintf_mciwave(stddeb,
894                 "wodWrite() // WOutDev[%u].unixdev %u !\n", wDevID, WOutDev[wDevID].unixdev);
895         lpData = PTR_SEG_TO_LIN(lpWaveHdr->lpData);
896         count = write (WOutDev[wDevID].unixdev, lpData, lpWaveHdr->dwBufferLength);
897         dprintf_mciwave(stddeb,
898                 "wodWrite() // write returned count %u !\n", count);
899         if (count != lpWaveHdr->dwBufferLength) {
900                 dprintf_mciwave(stddeb,"Linux 'wodWrite' // error writting !\n");
901                 return MMSYSERR_NOTENABLED;
902                 }
903         WOutDev[wDevID].dwTotalPlayed += count;
904         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
905         lpWaveHdr->dwFlags |= WHDR_DONE;
906         if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
907                 dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't notify client !\n");
908                 return MMSYSERR_INVALPARAM;
909                 }
910         return MMSYSERR_NOERROR;
911 }
912
913 /**************************************************************************
914 *                               wodPrepare                      [internal]
915 */
916 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
917 {
918         dprintf_mciwave(stddeb,
919                 "wodPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
920         if (WOutDev[wDevID].unixdev == 0) {
921                 dprintf_mciwave(stddeb,"Linux 'wodPrepare' // can't prepare !\n");
922                 return MMSYSERR_NOTENABLED;
923                 }
924         /* the COOL waveeditor feels much better without this check... 
925          * someone please have a look at available documentation
926         if (WOutDev[wDevID].lpQueueHdr != NULL) {
927                 dprintf_mciwave(stddeb,"Linux 'wodPrepare' // already prepare !\n");
928                 return MMSYSERR_NOTENABLED;
929         }
930         */
931         WOutDev[wDevID].dwTotalPlayed = 0;
932         WOutDev[wDevID].lpQueueHdr = lpWaveHdr;
933         if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
934         lpWaveHdr->dwFlags |= WHDR_PREPARED;
935         lpWaveHdr->dwFlags &= ~WHDR_DONE;
936         return MMSYSERR_NOERROR;
937 }
938
939 /**************************************************************************
940 *                               wodUnprepare                    [internal]
941 */
942 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
943 {
944         dprintf_mciwave(stddeb,
945                 "wodUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
946         if (WOutDev[wDevID].unixdev == 0) {
947                 dprintf_mciwave(stddeb,"Linux 'wodUnprepare' // can't unprepare !\n");
948                 return MMSYSERR_NOTENABLED;
949                 }
950         return MMSYSERR_NOERROR;
951 }
952
953 /**************************************************************************
954 *                               wodRestart                              [internal]
955 */
956 static DWORD wodRestart(WORD wDevID)
957 {
958         dprintf_mciwave(stddeb,"wodRestart(%u);\n", wDevID);
959         if (WOutDev[wDevID].unixdev == 0) {
960                 dprintf_mciwave(stddeb,"Linux 'wodRestart' // can't restart !\n");
961                 return MMSYSERR_NOTENABLED;
962                 }
963         return MMSYSERR_NOERROR;
964 }
965
966 /**************************************************************************
967 *                               wodReset                                [internal]
968 */
969 static DWORD wodReset(WORD wDevID)
970 {
971     dprintf_mciwave(stddeb,"wodReset(%u);\n", wDevID);
972         if (WOutDev[wDevID].unixdev == 0) {
973                 dprintf_mciwave(stddeb,"Linux 'wodReset' // can't reset !\n");
974                 return MMSYSERR_NOTENABLED;
975                 }
976         return MMSYSERR_NOERROR;
977 }
978
979
980 /**************************************************************************
981 *                               wodGetPosition                  [internal]
982 */
983 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
984 {
985         int             time;
986         dprintf_mciwave(stddeb,"wodGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize);
987         if (WOutDev[wDevID].unixdev == 0) {
988                 dprintf_mciwave(stddeb,"Linux 'wodGetPosition' // can't get pos !\n");
989                 return MMSYSERR_NOTENABLED;
990                 }
991         if (lpTime == NULL)     return MMSYSERR_INVALPARAM;
992         switch(lpTime->wType) {
993                 case TIME_BYTES:
994                         lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed;
995                         dprintf_mciwave(stddeb,"wodGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb);
996                         break;
997                 case TIME_SAMPLES:
998                         dprintf_mciwave(stddeb,"wodGetPosition // dwTotalPlayed=%lu\n", 
999                                         WOutDev[wDevID].dwTotalPlayed);
1000                         dprintf_mciwave(stddeb,"wodGetPosition // wBitsPerSample=%u\n", 
1001                                         WOutDev[wDevID].Format.wBitsPerSample);
1002                         lpTime->u.sample = WOutDev[wDevID].dwTotalPlayed * 8 /
1003                                                 WOutDev[wDevID].Format.wBitsPerSample;
1004                         dprintf_mciwave(stddeb,"wodGetPosition // TIME_SAMPLES=%lu\n", lpTime->u.sample);
1005                         break;
1006                 case TIME_SMPTE:
1007                         time = WOutDev[wDevID].dwTotalPlayed /
1008                                 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1009                         lpTime->u.smpte.hour = time / 108000;
1010                         time -= lpTime->u.smpte.hour * 108000;
1011                         lpTime->u.smpte.min = time / 1800;
1012                         time -= lpTime->u.smpte.min * 1800;
1013                         lpTime->u.smpte.sec = time / 30;
1014                         time -= lpTime->u.smpte.sec * 30;
1015                         lpTime->u.smpte.frame = time;
1016                         lpTime->u.smpte.fps = 30;
1017                         dprintf_mciwave(stddeb,
1018                           "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1019                           lpTime->u.smpte.hour, lpTime->u.smpte.min,
1020                           lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1021                         break;
1022                 default:
1023                         dprintf_mciwave(stddeb,"wodGetPosition() format not supported ! use TIME_MS !\n");
1024                         lpTime->wType = TIME_MS;
1025                 case TIME_MS:
1026                         lpTime->u.ms = WOutDev[wDevID].dwTotalPlayed /
1027                                         (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1028                         dprintf_mciwave(stddeb,"wodGetPosition // TIME_MS=%lu\n", lpTime->u.ms);
1029                         break;
1030                 }
1031         return MMSYSERR_NOERROR;
1032 }
1033
1034 /**************************************************************************
1035 *                               wodGetVolume                    [internal]
1036 */
1037 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1038 {
1039         int     mixer;
1040         int             volume, left, right;
1041         dprintf_mciwave(stddeb,"wodGetVolume(%u, %p);\n", wDevID, lpdwVol);
1042         if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
1043         if ((mixer = open("/dev/mixer", O_RDONLY)) < 0) {
1044                 dprintf_mciwave(stddeb, "Linux 'wodGetVolume' // mixer device not available !\n");
1045                 return MMSYSERR_NOTENABLED;
1046                 }
1047     if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) {
1048                 dprintf_mciwave(stddeb,"Linux 'wodGetVolume' // unable read mixer !\n");
1049                 return MMSYSERR_NOTENABLED;
1050                 }
1051         close(mixer);
1052         left = volume & 0x7F;
1053         right = (volume >> 8) & 0x7F;
1054         printf("Linux 'AUX_GetVolume' // left=%d right=%d !\n", left, right);
1055         *lpdwVol = MAKELONG(left << 9, right << 9);
1056         return MMSYSERR_NOERROR;
1057 }
1058
1059
1060 /**************************************************************************
1061 *                               wodSetVolume                    [internal]
1062 */
1063 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1064 {
1065         int     mixer;
1066         int             volume;
1067         dprintf_mciwave(stddeb,"wodSetVolume(%u, %08lX);\n", wDevID, dwParam);
1068         volume = (LOWORD(dwParam) >> 9 & 0x7F) + 
1069                 ((HIWORD(dwParam) >> 9  & 0x7F) << 8);
1070         if ((mixer = open("/dev/mixer", O_WRONLY)) < 0) {
1071                 dprintf_mciwave(stddeb, "Linux 'wodSetVolume' // mixer device not available !\n");
1072                 return MMSYSERR_NOTENABLED;
1073                 }
1074     if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) {
1075                 dprintf_mciwave(stddeb,"Linux 'wodSetVolume' // unable set mixer !\n");
1076                 return MMSYSERR_NOTENABLED;
1077                 }
1078         close(mixer);
1079         return MMSYSERR_NOERROR;
1080 }
1081
1082 #endif /* linux */
1083
1084 /**************************************************************************
1085 *                               wodMessage                      [sample driver]
1086 */
1087 DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1088                                         DWORD dwParam1, DWORD dwParam2)
1089 {
1090         dprintf_mciwave(stddeb,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1091                         wDevID, wMsg, dwUser, dwParam1, dwParam2);
1092 #ifdef linux
1093         switch(wMsg) {
1094                 case WODM_OPEN:
1095                         return wodOpen(wDevID, (LPWAVEOPENDESC)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1096                 case WODM_CLOSE:
1097                         return wodClose(wDevID);
1098                 case WODM_WRITE:
1099                         return wodWrite(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1100                 case WODM_PAUSE:
1101                         return 0L;
1102                 case WODM_GETPOS:
1103                         return wodGetPosition(wDevID, (LPMMTIME)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1104                 case WODM_BREAKLOOP:
1105                         return 0L;
1106                 case WODM_PREPARE:
1107                         return wodPrepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1108                 case WODM_UNPREPARE:
1109                         return wodUnprepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1110                 case WODM_GETDEVCAPS:
1111                         return wodGetDevCaps(wDevID, (LPWAVEOUTCAPS)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1112                 case WODM_GETNUMDEVS:
1113                         return 1L;
1114                 case WODM_GETPITCH:
1115                         return 0L;
1116                 case WODM_SETPITCH:
1117                         return 0L;
1118                 case WODM_GETPLAYBACKRATE:
1119                         return 0L;
1120                 case WODM_SETPLAYBACKRATE:
1121                         return 0L;
1122                 case WODM_GETVOLUME:
1123                         return wodGetVolume(wDevID, (LPDWORD)PTR_SEG_TO_LIN(dwParam1));
1124                 case WODM_SETVOLUME:
1125                         return wodSetVolume(wDevID, dwParam1);
1126                 case WODM_RESTART:
1127                         return wodRestart(wDevID);
1128                 case WODM_RESET:
1129                         return wodReset(wDevID);
1130                 default:
1131                         dprintf_mciwave(stddeb,"wodMessage // unknown message !\n");
1132                 }
1133         return MMSYSERR_NOTSUPPORTED;
1134 #else
1135         return MMSYSERR_NOTENABLED;
1136 #endif
1137 }
1138
1139
1140 /*-----------------------------------------------------------------------*/
1141
1142 #ifdef linux
1143
1144 /**************************************************************************
1145 *                               widGetDevCaps                           [internal]
1146 */
1147 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPS lpCaps, DWORD dwSize)
1148 {
1149         int     audio;
1150         int             smplrate;
1151         int             samplesize = 16;
1152         int             dsp_stereo = 1;
1153         int             bytespersmpl;
1154         dprintf_mciwave(stddeb,
1155                 "widGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
1156         if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1157         audio = open (SOUND_DEV, O_RDONLY, 0);
1158         if (audio == -1) return MMSYSERR_NOTENABLED;
1159 #ifdef EMULATE_SB16
1160         lpCaps->wMid = 0x0002;
1161         lpCaps->wPid = 0x0004;
1162         strcpy(lpCaps->szPname, "SB16 Wave Out");
1163 #else
1164         lpCaps->wMid = 0x00FF;  /* Manufac ID */
1165         lpCaps->wPid = 0x0001;  /* Product ID */
1166         strcpy(lpCaps->szPname, "Linux WAVIN Driver");
1167 #endif
1168         lpCaps->dwFormats = 0x00000000;
1169         lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
1170         bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
1171         smplrate = 44100;
1172         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1173                 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
1174                 if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_4S08;
1175                 if (bytespersmpl > 1) {
1176                         lpCaps->dwFormats |= WAVE_FORMAT_4M16;
1177                         if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_4S16;
1178                         }
1179                 }
1180         smplrate = 22050;
1181         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1182                 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
1183                 if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_2S08;
1184                 if (bytespersmpl > 1) {
1185                         lpCaps->dwFormats |= WAVE_FORMAT_2M16;
1186                         if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_2S16;
1187                         }
1188                 }
1189         smplrate = 11025;
1190         if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1191                 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
1192                 if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_1S08;
1193                 if (bytespersmpl > 1) {
1194                         lpCaps->dwFormats |= WAVE_FORMAT_1M16;
1195                         if (lpCaps->wChannels > 1)      lpCaps->dwFormats |= WAVE_FORMAT_1S16;
1196                         }
1197                 }
1198         close(audio);
1199         dprintf_mciwave(stddeb,
1200                 "widGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats);
1201         return MMSYSERR_NOERROR;
1202 }
1203
1204
1205 /**************************************************************************
1206 *                               widOpen                         [internal]
1207 */
1208 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1209 {
1210         int             audio;
1211         int                     abuf_size;
1212         int                     smplrate;
1213         int                     samplesize;
1214         int                     dsp_stereo;
1215         LPWAVEFORMAT  lpFormat;
1216         dprintf_mciwave(stddeb, "widOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
1217         if (lpDesc == NULL) {
1218                 dprintf_mciwave(stddeb,"Linux 'widOpen' // Invalid Parameter !\n");
1219                 return MMSYSERR_INVALPARAM;
1220                 }
1221         if (wDevID >= MAX_WAVINDRV) {
1222                 dprintf_mciwave(stddeb,"Linux 'widOpen' // MAX_WAVINDRV reached !\n");
1223                 return MMSYSERR_ALLOCATED;
1224                 }
1225         WInDev[wDevID].unixdev = 0;
1226         audio = open (SOUND_DEV, O_RDONLY, 0);
1227         if (audio == -1) {
1228                 dprintf_mciwave(stddeb,"Linux 'widOpen' // can't open !\n");
1229                 return MMSYSERR_NOTENABLED;
1230                 }
1231         IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
1232         if (abuf_size < 4096 || abuf_size > 65536) {
1233                 if (abuf_size == -1)
1234                         dprintf_mciwave(stddeb,"Linux 'widOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
1235                 else
1236                         dprintf_mciwave(stddeb,"Linux 'widOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
1237                 return MMSYSERR_NOTENABLED;
1238                 }
1239         WInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1240         switch(WInDev[wDevID].wFlags) {
1241                 case DCB_NULL:
1242                         dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_NULL !\n");
1243                         break;
1244                 case DCB_WINDOW:
1245                         dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_WINDOW !\n");
1246                         break;
1247                 case DCB_TASK:
1248                         dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_TASK !\n");
1249                         break;
1250                 case DCB_FUNCTION:
1251                         dprintf_mciwave(stddeb, "Linux 'widOpen' // CALLBACK_FUNCTION !\n");
1252                         break;
1253                 }
1254         WInDev[wDevID].lpQueueHdr = NULL;
1255         WInDev[wDevID].unixdev = audio;
1256         WInDev[wDevID].bufsize = abuf_size;
1257         WInDev[wDevID].dwTotalRecorded = 0;
1258         memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
1259         lpFormat = lpDesc->lpFormat;
1260         if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
1261                 dprintf_mciwave(stddeb,"Linux 'widOpen' // Bad format %04X !\n",
1262                                         lpFormat->wFormatTag);
1263                 return WAVERR_BADFORMAT;
1264                 }
1265         memcpy(&WInDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
1266         WInDev[wDevID].Format.wBitsPerSample = 8; /* <-------------- */
1267         if (WInDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
1268         if (WInDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
1269         if (WInDev[wDevID].Format.wBitsPerSample == 0) {
1270                 WInDev[wDevID].Format.wBitsPerSample = 8 *
1271                 (WInDev[wDevID].Format.wf.nAvgBytesPerSec /
1272                 WInDev[wDevID].Format.wf.nSamplesPerSec) /
1273                 WInDev[wDevID].Format.wf.nChannels;
1274                 }
1275         samplesize = WInDev[wDevID].Format.wBitsPerSample;
1276         smplrate = WInDev[wDevID].Format.wf.nSamplesPerSec;
1277         dsp_stereo = (WInDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
1278         IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
1279         IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
1280         IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
1281         dprintf_mciwave(stddeb,"Linux 'widOpen' // wBitsPerSample=%u !\n",
1282                                 WInDev[wDevID].Format.wBitsPerSample);
1283         dprintf_mciwave(stddeb,"Linux 'widOpen' // nSamplesPerSec=%lu !\n",
1284                                 WInDev[wDevID].Format.wf.nSamplesPerSec);
1285         dprintf_mciwave(stddeb,"Linux 'widOpen' // nChannels=%u !\n",
1286                                 WInDev[wDevID].Format.wf.nChannels);
1287         dprintf_mciwave(stddeb,"Linux 'widOpen' // nAvgBytesPerSec=%lu\n",
1288                         WInDev[wDevID].Format.wf.nAvgBytesPerSec); 
1289         if (WAVE_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
1290                 dprintf_mciwave(stddeb,"Linux 'widOpen' // can't notify client !\n");
1291                 return MMSYSERR_INVALPARAM;
1292                 }
1293         return MMSYSERR_NOERROR;
1294 }
1295
1296 /**************************************************************************
1297 *                               widClose                        [internal]
1298 */
1299 static DWORD widClose(WORD wDevID)
1300 {
1301         dprintf_mciwave(stddeb,"widClose(%u);\n", wDevID);
1302         if (WInDev[wDevID].unixdev == 0) {
1303                 dprintf_mciwave(stddeb,"Linux 'widClose' // can't close !\n");
1304                 return MMSYSERR_NOTENABLED;
1305                 }
1306         close(WInDev[wDevID].unixdev);
1307         WInDev[wDevID].unixdev = 0;
1308         WInDev[wDevID].bufsize = 0;
1309         if (WAVE_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
1310                 dprintf_mciwave(stddeb,"Linux 'widClose' // can't notify client !\n");
1311                 return MMSYSERR_INVALPARAM;
1312                 }
1313         return MMSYSERR_NOERROR;
1314 }
1315
1316 /**************************************************************************
1317 *                               widAddBuffer            [internal]
1318 */
1319 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1320 {
1321         int                     count   = 1;
1322         LPWAVEHDR       lpWIHdr;
1323         dprintf_mciwave(stddeb,
1324                 "widAddBuffer(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1325         if (WInDev[wDevID].unixdev == 0) {
1326                 dprintf_mciwave(stddeb,"Linux 'widAddBuffer' // can't do it !\n");
1327                 return MMSYSERR_NOTENABLED;
1328                 }
1329         if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
1330                 dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // never been prepared !\n");
1331                 return WAVERR_UNPREPARED;
1332                 }
1333         if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
1334                 dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // header already in use !\n");
1335                 return WAVERR_STILLPLAYING;
1336                 }
1337         lpWaveHdr->dwFlags |= WHDR_PREPARED;
1338         lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1339         lpWaveHdr->dwFlags &= ~WHDR_DONE;
1340         lpWaveHdr->dwBytesRecorded = 0;
1341         if (WInDev[wDevID].lpQueueHdr == NULL) {
1342                 /* begin the queue with a first header ... */
1343                 WInDev[wDevID].lpQueueHdr = lpWaveHdr;
1344                 WInDev[wDevID].dwTotalRecorded = 0;
1345                 }
1346         else {
1347                 /* added to the queue, except if it's the one just prepared ... */
1348                 lpWIHdr = WInDev[wDevID].lpQueueHdr;
1349                 while (lpWIHdr->lpNext != NULL) {
1350                         lpWIHdr = lpWIHdr->lpNext;
1351                         count++;
1352                         }
1353                 lpWIHdr->lpNext = lpWaveHdr;
1354                 count++;
1355                 }
1356         dprintf_mciwave(stddeb,
1357                 "widAddBuffer // buffer added ! (now %u in queue)\n", count);
1358         return MMSYSERR_NOERROR;
1359 }
1360
1361 /**************************************************************************
1362 *                               widPrepare                      [internal]
1363 */
1364 static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1365 {
1366         dprintf_mciwave(stddeb,
1367                 "widPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1368         if (WInDev[wDevID].unixdev == 0) {
1369                 dprintf_mciwave(stddeb,"Linux 'widPrepare' // can't prepare !\n");
1370                 return MMSYSERR_NOTENABLED;
1371                 }
1372         if (WInDev[wDevID].lpQueueHdr != NULL) {
1373                 dprintf_mciwave(stddeb,"Linux 'widPrepare' // already prepare !\n");
1374                 return WAVERR_BADFORMAT;
1375                 }
1376         if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
1377         lpWaveHdr->dwFlags |= WHDR_PREPARED;
1378         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1379         lpWaveHdr->dwFlags &= ~WHDR_DONE;
1380         lpWaveHdr->dwBytesRecorded = 0;
1381         dprintf_mciwave(stddeb,"Linux 'widPrepare' // header prepared !\n");
1382         return MMSYSERR_NOERROR;
1383 }
1384
1385 /**************************************************************************
1386 *                               widUnprepare                    [internal]
1387 */
1388 static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1389 {
1390         dprintf_mciwave(stddeb,
1391                 "widUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1392         if (WInDev[wDevID].unixdev == 0) {
1393                 dprintf_mciwave(stddeb,"Linux 'widUnprepare' // can't unprepare !\n");
1394                 return MMSYSERR_NOTENABLED;
1395                 }
1396         lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1397         lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1398         lpWaveHdr->dwFlags |= WHDR_DONE;
1399         WInDev[wDevID].lpQueueHdr = NULL;
1400         dprintf_mciwave(stddeb,
1401                 "Linux 'widUnprepare' // all headers unprepared !\n");
1402         return MMSYSERR_NOERROR;
1403 }
1404
1405 /**************************************************************************
1406 *                               widStart                                [internal]
1407 */
1408 static DWORD widStart(WORD wDevID)
1409 {
1410         int                     count   = 1;
1411         LPWAVEHDR       lpWIHdr;
1412         dprintf_mciwave(stddeb,"widStart(%u);\n", wDevID);
1413         if (WInDev[wDevID].unixdev == 0) {
1414                 dprintf_mciwave(stddeb, "Linux 'widStart' // can't start recording !\n");
1415                 return MMSYSERR_NOTENABLED;
1416                 }
1417         if (WInDev[wDevID].lpQueueHdr == NULL || 
1418                 WInDev[wDevID].lpQueueHdr->lpData == NULL) {
1419                 dprintf_mciwave(stddeb,"Linux 'widStart' // never been prepared !\n");
1420                 return WAVERR_UNPREPARED;
1421                 }
1422         lpWIHdr = WInDev[wDevID].lpQueueHdr;
1423         while(lpWIHdr != NULL) {
1424                 lpWIHdr->dwBufferLength &= 0xFFFF;
1425                 dprintf_mciwave(stddeb,
1426                         "widStart // recording buf#%u=%p size=%lu \n",
1427                         count, lpWIHdr->lpData, lpWIHdr->dwBufferLength);
1428                 fflush(stddeb);
1429                 read (WInDev[wDevID].unixdev, 
1430                         PTR_SEG_TO_LIN(lpWIHdr->lpData),
1431                         lpWIHdr->dwBufferLength);
1432                 lpWIHdr->dwBytesRecorded = lpWIHdr->dwBufferLength;
1433                 WInDev[wDevID].dwTotalRecorded += lpWIHdr->dwBytesRecorded;
1434                 lpWIHdr->dwFlags &= ~WHDR_INQUEUE;
1435                 lpWIHdr->dwFlags |= WHDR_DONE;
1436                 if (WAVE_NotifyClient(wDevID, WIM_DATA, (DWORD)lpWIHdr, 0L) != 
1437                         MMSYSERR_NOERROR) {
1438                         dprintf_mciwave(stddeb, "Linux 'widStart' // can't notify client !\n");
1439                         return MMSYSERR_INVALPARAM;
1440                         }
1441                 lpWIHdr = lpWIHdr->lpNext;
1442                 count++;
1443                 }
1444         dprintf_mciwave(stddeb,"widStart // end of recording !\n");
1445         fflush(stdout);
1446         return MMSYSERR_NOERROR;
1447 }
1448
1449 /**************************************************************************
1450 *                               widStop                                 [internal]
1451 */
1452 static DWORD widStop(WORD wDevID)
1453 {
1454         dprintf_mciwave(stddeb,"widStop(%u);\n", wDevID);
1455         if (WInDev[wDevID].unixdev == 0) {
1456                 dprintf_mciwave(stddeb,"Linux 'widStop' // can't stop !\n");
1457                 return MMSYSERR_NOTENABLED;
1458                 }
1459         return MMSYSERR_NOERROR;
1460 }
1461
1462 /**************************************************************************
1463 *                               widReset                                [internal]
1464 */
1465 static DWORD widReset(WORD wDevID)
1466 {
1467         dprintf_mciwave(stddeb,"widReset(%u);\n", wDevID);
1468         if (WInDev[wDevID].unixdev == 0) {
1469                 dprintf_mciwave(stddeb,"Linux 'widReset' // can't reset !\n");
1470                 return MMSYSERR_NOTENABLED;
1471                 }
1472         return MMSYSERR_NOERROR;
1473 }
1474
1475 /**************************************************************************
1476 *                               widGetPosition                  [internal]
1477 */
1478 static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
1479 {
1480         int             time;
1481     
1482         dprintf_mciwave(stddeb,
1483                 "widGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1484         if (WInDev[wDevID].unixdev == 0) {
1485                 dprintf_mciwave(stddeb,"Linux 'widGetPosition' // can't get pos !\n");
1486                 return MMSYSERR_NOTENABLED;
1487                 }
1488         if (lpTime == NULL)     return MMSYSERR_INVALPARAM;
1489         dprintf_mciwave(stddeb,"widGetPosition // wType=%04X !\n", 
1490                         lpTime->wType);
1491         dprintf_mciwave(stddeb,"widGetPosition // wBitsPerSample=%u\n",
1492                         WInDev[wDevID].Format.wBitsPerSample); 
1493         dprintf_mciwave(stddeb,"widGetPosition // nSamplesPerSec=%lu\n",
1494                         WInDev[wDevID].Format.wf.nSamplesPerSec); 
1495         dprintf_mciwave(stddeb,"widGetPosition // nChannels=%u\n",
1496                         WInDev[wDevID].Format.wf.nChannels); 
1497         dprintf_mciwave(stddeb,"widGetPosition // nAvgBytesPerSec=%lu\n",
1498                         WInDev[wDevID].Format.wf.nAvgBytesPerSec); 
1499         fflush(stddeb);
1500         switch(lpTime->wType) {
1501                 case TIME_BYTES:
1502                         lpTime->u.cb = WInDev[wDevID].dwTotalRecorded;
1503                         dprintf_mciwave(stddeb,
1504                             "widGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb);
1505                         break;
1506                 case TIME_SAMPLES:
1507                         lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 /
1508                                           WInDev[wDevID].Format.wBitsPerSample;
1509                         dprintf_mciwave(stddeb,
1510                                         "widGetPosition // TIME_SAMPLES=%lu\n", 
1511                                         lpTime->u.sample);
1512                         break;
1513                 case TIME_SMPTE:
1514                         time = WInDev[wDevID].dwTotalRecorded /
1515                                 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1516                         lpTime->u.smpte.hour = time / 108000;
1517                         time -= lpTime->u.smpte.hour * 108000;
1518                         lpTime->u.smpte.min = time / 1800;
1519                         time -= lpTime->u.smpte.min * 1800;
1520                         lpTime->u.smpte.sec = time / 30;
1521                         time -= lpTime->u.smpte.sec * 30;
1522                         lpTime->u.smpte.frame = time;
1523                         lpTime->u.smpte.fps = 30;
1524             dprintf_mciwave(stddeb,"widGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1525                                         lpTime->u.smpte.hour, lpTime->u.smpte.min,
1526                                         lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1527                         break;
1528                 default:
1529                         dprintf_mciwave(stddeb,"widGetPosition() format not supported ! use TIME_MS !\n");
1530                         lpTime->wType = TIME_MS;
1531                 case TIME_MS:
1532                         lpTime->u.ms = WInDev[wDevID].dwTotalRecorded /
1533                                         (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1534                         dprintf_mciwave(stddeb,
1535                               "widGetPosition // TIME_MS=%lu\n", lpTime->u.ms);
1536                         break;
1537                 }
1538         return MMSYSERR_NOERROR;
1539 }
1540
1541 #endif /* linux */
1542
1543 /**************************************************************************
1544 *                               widMessage                      [sample driver]
1545 */
1546 DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
1547                                         DWORD dwParam1, DWORD dwParam2)
1548 {
1549         dprintf_mciwave(stddeb,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1550                         wDevID, wMsg, dwUser, dwParam1, dwParam2);
1551 #ifdef linux
1552         switch(wMsg) {
1553                 case WIDM_OPEN:
1554                         return widOpen(wDevID, (LPWAVEOPENDESC)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1555                 case WIDM_CLOSE:
1556                         return widClose(wDevID);
1557                 case WIDM_ADDBUFFER:
1558                         return widAddBuffer(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1559                 case WIDM_PREPARE:
1560                         return widPrepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1561                 case WIDM_UNPREPARE:
1562                         return widUnprepare(wDevID, (LPWAVEHDR)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1563                 case WIDM_GETDEVCAPS:
1564                         return widGetDevCaps(wDevID, (LPWAVEINCAPS)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1565                 case WIDM_GETNUMDEVS:
1566                         return 1;
1567                 case WIDM_GETPOS:
1568                         return widGetPosition(wDevID, (LPMMTIME)PTR_SEG_TO_LIN(dwParam1), dwParam2);
1569                 case WIDM_RESET:
1570                         return widReset(wDevID);
1571                 case WIDM_START:
1572                         return widStart(wDevID);
1573                 case WIDM_STOP:
1574                         return widStop(wDevID);
1575                 default:
1576                         dprintf_mciwave(stddeb,"widMessage // unknown message !\n");
1577                 }
1578         return MMSYSERR_NOTSUPPORTED;
1579 #else
1580         return MMSYSERR_NOTENABLED;
1581 #endif
1582 }
1583
1584
1585 /**************************************************************************
1586 *                               AUDIO_DriverProc                [sample driver]
1587 */
1588 LONG WAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg, 
1589                                                 DWORD dwParam1, DWORD dwParam2)
1590 {
1591 #ifdef linux
1592         dprintf_mciwave(stddeb,"WAVE_DriverProc(%08lX, %04X, %04X, %08lX, %08lX)\n", 
1593                 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1594         switch(wMsg) {
1595                 case DRV_LOAD:
1596                         return 1;
1597                 case DRV_FREE:
1598                         return 1;
1599                 case DRV_OPEN:
1600                         return 1;
1601                 case DRV_CLOSE:
1602                         return 1;
1603                 case DRV_ENABLE:
1604                         return 1;
1605                 case DRV_DISABLE:
1606                         return 1;
1607                 case DRV_QUERYCONFIGURE:
1608                         return 1;
1609                 case DRV_CONFIGURE:
1610                         MessageBox((HWND)NULL, "Sample MultiMedia Linux Driver !", 
1611                                                                 "MMLinux Driver", MB_OK);
1612                         return 1;
1613                 case DRV_INSTALL:
1614                         return DRVCNF_RESTART;
1615                 case DRV_REMOVE:
1616                         return DRVCNF_RESTART;
1617                 case MCI_OPEN_DRIVER:
1618                 case MCI_OPEN:
1619                         return WAVE_mciOpen(dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS)PTR_SEG_TO_LIN(dwParam2));
1620                 case MCI_CLOSE_DRIVER:
1621                 case MCI_CLOSE:
1622                         return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1623                 case MCI_PLAY:
1624                         return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
1625                 case MCI_RECORD:
1626                         return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2));
1627                 case MCI_STOP:
1628                         return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1629                 case MCI_SET:
1630                         return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
1631                 case MCI_PAUSE:
1632                         return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1633                 case MCI_RESUME:
1634                         return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1635                 case MCI_STATUS:
1636                         return WAVE_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1637                 case MCI_GETDEVCAPS:
1638                         return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1639                 case MCI_INFO:
1640                         return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS)PTR_SEG_TO_LIN(dwParam2));
1641                 default:
1642                         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1643                 }
1644 #else
1645         return MMSYSERR_NOTENABLED;
1646 #endif
1647 }
1648
1649
1650 #endif /* #ifdef BUILTIN_MMSYSTEM */