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