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