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