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