ReactOS  0.4.13-dev-99-g7e18b6d
mcimidi.c
Go to the documentation of this file.
1 /*
2  * Sample MIDI Wine Driver for Linux
3  *
4  * Copyright 1994 Martin Ayotte
5  * Copyright 1999 Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 /* TODO:
23  * + implement it correctly
24  * + finish asynchronous commands
25  * + better implement non waiting command (without the MCI_WAIT flag).
26  */
27 
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "wownt32.h"
38 #include "mmddk.h"
39 #include "wine/debug.h"
40 #include "wine/unicode.h"
41 
43 
44 #define MIDI_NOTEOFF 0x80
45 #define MIDI_NOTEON 0x90
46 
47 typedef struct {
48  DWORD dwFirst; /* offset in file of track */
49  DWORD dwLast; /* number of bytes in file of track */
50  DWORD dwIndex; /* current index in file (dwFirst <= dwIndex < dwLast) */
51  DWORD dwLength; /* number of pulses in this track */
52  DWORD dwEventPulse; /* current pulse # (event) pointed by dwIndex */
53  DWORD dwEventData; /* current data (event) pointed by dwIndex */
54  WORD wEventLength; /* current length (event) pointed by dwIndex */
55  WORD wStatus : 1, /* 1 : playing, 0 : done */
56  wTrackNr : 7,
57  wLastCommand : 8; /* last MIDI command on track */
59 
60 typedef struct tagWINE_MCIMIDI {
61  UINT wDevID; /* the MCI one */
62  HMIDI hMidi;
63  int nUseCount; /* Incremented for each shared open */
64  HANDLE hCallback; /* Callback handle for pending notification */
65  HANDLE hThread; /* Player thread */
66  HMMIO hFile; /* mmio file handle open as Element */
67  LPWSTR lpstrElementName; /* Name of file (if any) */
70  WORD wPort; /* the WINMM device unit */
71  WORD dwStatus; /* one from MCI_MODE_xxxx */
72  DWORD dwMciTimeFormat; /* One of the supported MCI_FORMAT_xxxx */
73  WORD wFormat; /* Format of MIDI hFile (0, 1 or 2) */
74  WORD nTracks; /* Number of tracks in hFile */
75  WORD nDivision; /* Number of division in hFile PPQN or SMPTE */
77  DWORD dwTempo; /* Tempo (# of 1/4 note per second */
78  MCI_MIDITRACK* tracks; /* Content of each track */
83 } WINE_MCIMIDI;
84 
85 /*======================================================================*
86  * MCI MIDI implementation *
87  *======================================================================*/
88 
90 {
91  switch (ret) {
92  case MMSYSERR_ALLOCATED:
93  return MCIERR_SEQ_PORT_INUSE;
94  case MMSYSERR_NOMEM:
95  return MCIERR_OUT_OF_MEMORY;
96  case MMSYSERR_BADDEVICEID: /* wine*.drv disabled */
98  case MIDIERR_INVALIDSETUP: /* from midimap.dll without snd-seq module */
100  default:
101  return ret;
102  }
103 }
104 
106 
107 /**************************************************************************
108  * MIDI_drvOpen [internal]
109  */
111 {
112  WINE_MCIMIDI* wmm;
113 
114  if (!modp) return 0xFFFFFFFF;
115 
117 
118  if (!wmm)
119  return 0;
120 
121  wmm->wDevID = modp->wDeviceID;
122  mciSetDriverData(wmm->wDevID, (DWORD_PTR)wmm);
125  return modp->wDeviceID;
126 }
127 
128 /**************************************************************************
129  * MCIMIDI_drvClose [internal]
130  */
131 static DWORD MIDI_drvClose(DWORD dwDevID)
132 {
133  WINE_MCIMIDI* wmm = (WINE_MCIMIDI*)mciGetDriverData(dwDevID);
134 
135  if (wmm) {
136  HeapFree(GetProcessHeap(), 0, wmm);
137  mciSetDriverData(dwDevID, 0);
138  return 1;
139  }
140  return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
141 }
142 
143 /**************************************************************************
144  * MIDI_mciGetOpenDev [internal]
145  */
147 {
148  WINE_MCIMIDI* wmm = (WINE_MCIMIDI*)mciGetDriverData(wDevID);
149 
150  if (wmm == NULL || ((wmm->nUseCount == 0) ^ (wMsg == MCI_OPEN_DRIVER))) {
151  WARN("Invalid wDevID=%u\n", wDevID);
152  return 0;
153  }
154  return wmm;
155 }
156 
157 /**************************************************************************
158  * MIDI_mciNotify [internal]
159  *
160  * Notifications in MCI work like a 1-element queue.
161  * Each new notification request supersedes the previous one.
162  * This affects Play and Record; other commands are immediate.
163  */
164 static void MIDI_mciNotify(DWORD_PTR hWndCallBack, WINE_MCIMIDI* wmm, UINT wStatus)
165 {
166  /* We simply save one parameter by not passing the wDevID local
167  * to the command. They are the same (via mciGetDriverData).
168  */
169  MCIDEVICEID wDevID = wmm->wDevID;
171  if (old) mciDriverNotify(old, wDevID, MCI_NOTIFY_SUPERSEDED);
172  mciDriverNotify(HWND_32(LOWORD(hWndCallBack)), wDevID, wStatus);
173 }
174 
175 /**************************************************************************
176  * MIDI_mciReadByte [internal]
177  */
179 {
180  DWORD ret = 0;
181 
182  if (mmioRead(wmm->hFile, (HPSTR)lpbyt, sizeof(BYTE)) != (long)sizeof(BYTE)) {
183  WARN("Error reading wmm=%p\n", wmm);
185  }
186 
187  return ret;
188 }
189 
190 /**************************************************************************
191  * MIDI_mciReadWord [internal]
192  */
194 {
195  BYTE hibyte, lobyte;
197 
198  if (MIDI_mciReadByte(wmm, &hibyte) == 0 &&
199  MIDI_mciReadByte(wmm, &lobyte) == 0) {
200  *lpw = ((WORD)hibyte << 8) + lobyte;
201  ret = 0;
202  }
203  return ret;
204 }
205 
206 /**************************************************************************
207  * MIDI_mciReadLong [internal]
208  */
210 {
211  WORD hiword, loword;
213 
214  if (MIDI_mciReadWord(wmm, &hiword) == 0 &&
215  MIDI_mciReadWord(wmm, &loword) == 0) {
216  *lpdw = MAKELONG(loword, hiword);
217  ret = 0;
218  }
219  return ret;
220 }
221 
222 /**************************************************************************
223  * MIDI_mciReadVaryLen [internal]
224  */
226 {
227  BYTE byte;
228  DWORD value = 0;
229  WORD len = 0;
230 
231  do {
232  if (MIDI_mciReadByte(wmm, &byte) != 0) {
233  return 0;
234  }
235  value = (value << 7) + (byte & 0x7F);
236  len++;
237  } while (byte & 0x80);
238  *lpdw = value;
239  return len;
240 }
241 
242 /**************************************************************************
243  * MIDI_mciReadNextEvent [internal]
244  */
246 {
247  BYTE b1, b2 = 0, b3;
248  WORD hw = 0;
249  DWORD evtPulse;
250  DWORD evtLength;
251  DWORD tmp;
252 
253  if (mmioSeek(wmm->hFile, mmt->dwIndex, SEEK_SET) != mmt->dwIndex) {
254  WARN("Can't seek at %08X\n", mmt->dwIndex);
255  return MCIERR_INVALID_FILE;
256  }
257  evtLength = MIDI_mciReadVaryLen(wmm, &evtPulse) + 1; /* > 0 */
258  MIDI_mciReadByte(wmm, &b1);
259  switch (b1) {
260  case 0xF0:
261  case 0xF7:
262  evtLength += MIDI_mciReadVaryLen(wmm, &tmp);
263  evtLength += tmp;
264  break;
265  case 0xFF:
266  MIDI_mciReadByte(wmm, &b2); evtLength++;
267 
268  evtLength += MIDI_mciReadVaryLen(wmm, &tmp);
269  if (evtLength >= 0x10000u) {
270  /* this limitation shouldn't be a problem */
271  WARN("Ouch !! Implementation limitation to 64k bytes for a MIDI event is overflowed\n");
272  hw = 0xFFFF;
273  } else {
274  hw = LOWORD(evtLength);
275  }
276  evtLength += tmp;
277  break;
278  default:
279  if (b1 & 0x80) { /* use running status ? */
280  mmt->wLastCommand = b1;
281  MIDI_mciReadByte(wmm, &b2); evtLength++;
282  } else {
283  b2 = b1;
284  b1 = mmt->wLastCommand;
285  }
286  switch ((b1 >> 4) & 0x07) {
287  case 0: case 1: case 2: case 3: case 6:
288  MIDI_mciReadByte(wmm, &b3); evtLength++;
289  hw = b3;
290  break;
291  case 4: case 5:
292  break;
293  case 7:
294  WARN("Strange indeed b1=0x%02x\n", b1);
295  }
296  break;
297  }
298  if (mmt->dwIndex + evtLength > mmt->dwLast)
299  return MCIERR_INTERNAL;
300 
301  mmt->dwEventPulse += evtPulse;
302  mmt->dwEventData = (hw << 16) + (b2 << 8) + b1;
303  mmt->wEventLength = evtLength;
304 
305  /*
306  TRACE("[%u] => pulse=%08x(%08x), data=%08x, length=%u\n",
307  mmt->wTrackNr, mmt->dwEventPulse, evtPulse,
308  mmt->dwEventData, mmt->wEventLength);
309  */
310  return 0;
311 }
312 
313 /**************************************************************************
314  * MIDI_mciReadMTrk [internal]
315  */
317 {
318  DWORD toberead;
319  FOURCC fourcc;
320 
321  if (mmioRead(wmm->hFile, (HPSTR)&fourcc, (long)sizeof(FOURCC)) !=
322  (long)sizeof(FOURCC)) {
323  return MCIERR_INVALID_FILE;
324  }
325 
326  if (fourcc != mmioFOURCC('M', 'T', 'r', 'k')) {
327  WARN("Can't synchronize on 'MTrk' !\n");
328  return MCIERR_INVALID_FILE;
329  }
330 
331  if (MIDI_mciReadLong(wmm, &toberead) != 0) {
332  return MCIERR_INVALID_FILE;
333  }
334  mmt->dwFirst = mmioSeek(wmm->hFile, 0, SEEK_CUR); /* >= 0 */
335  mmt->dwLast = mmt->dwFirst + toberead;
336 
337  /* compute # of pulses in this track */
338  mmt->dwIndex = mmt->dwFirst;
339  mmt->dwEventPulse = 0;
340 
341  while (MIDI_mciReadNextEvent(wmm, mmt) == 0 && LOWORD(mmt->dwEventData) != 0x2FFF) {
342  char buf[1024];
343  WORD len;
344 
345  mmt->dwIndex += mmt->wEventLength;
346 
347  switch (LOWORD(mmt->dwEventData)) {
348  case 0x02FF:
349  case 0x03FF:
350  len = mmt->wEventLength - HIWORD(mmt->dwEventData);
351  if (len >= sizeof(buf)) {
352  WARN("Buffer for text is too small (%u are needed)\n", len);
353  len = sizeof(buf) - 1;
354  }
355  if (mmioRead(wmm->hFile, buf, len) == len) {
356  buf[len] = 0; /* end string in case */
357  switch (HIBYTE(LOWORD(mmt->dwEventData))) {
358  case 0x02:
359  if (wmm->lpstrCopyright) {
360  WARN("Two copyright notices (%s|%s)\n", debugstr_w(wmm->lpstrCopyright), buf);
362  }
363  len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
364  wmm->lpstrCopyright = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
365  MultiByteToWideChar( CP_ACP, 0, buf, -1, wmm->lpstrCopyright, len );
366  break;
367  case 0x03:
368  if (wmm->lpstrName) {
369  WARN("Two names (%s|%s)\n", debugstr_w(wmm->lpstrName), buf);
370  HeapFree(GetProcessHeap(), 0, wmm->lpstrName);
371  } /* last name or name from last track wins */
372  len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 );
373  wmm->lpstrName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
374  MultiByteToWideChar( CP_ACP, 0, buf, -1, wmm->lpstrName, len );
375  break;
376  }
377  }
378  break;
379  }
380  }
381  mmt->dwLength = mmt->dwEventPulse;
382 
383  TRACE("Track %u has %u bytes and %u pulses\n", mmt->wTrackNr, toberead, mmt->dwLength);
384 
385  /* reset track data */
386  mmt->wStatus = 1; /* ok, playing */
387  mmt->dwIndex = mmt->dwFirst;
388  mmt->dwEventPulse = 0;
389 
390  if (mmioSeek(wmm->hFile, 0, SEEK_CUR) != mmt->dwLast) {
391  WARN("Ouch, out of sync seek=%u track=%u\n",
392  mmioSeek(wmm->hFile, 0, SEEK_CUR), mmt->dwLast);
393  /* position at end of this track, to be ready to read next track */
394  mmioSeek(wmm->hFile, mmt->dwLast, SEEK_SET);
395  }
396 
397  return 0;
398 }
399 
400 /**************************************************************************
401  * MIDI_mciReadMThd [internal]
402  */
404 {
405  DWORD toberead;
406  FOURCC fourcc;
407  WORD nt;
408 
409  TRACE("(%p, %08X);\n", wmm, dwOffset);
410 
411  if (mmioSeek(wmm->hFile, dwOffset, SEEK_SET) != dwOffset) {
412  WARN("Can't seek at %08X begin of 'MThd'\n", dwOffset);
413  return MCIERR_INVALID_FILE;
414  }
415  if (mmioRead(wmm->hFile, (HPSTR)&fourcc,
416  (long) sizeof(FOURCC)) != (long) sizeof(FOURCC))
417  return MCIERR_INVALID_FILE;
418 
419  if (fourcc != mmioFOURCC('M', 'T', 'h', 'd')) {
420  WARN("Can't synchronize on 'MThd' !\n");
421  return MCIERR_INVALID_FILE;
422  }
423 
424  if (MIDI_mciReadLong(wmm, &toberead) != 0 || toberead < 3 * sizeof(WORD))
425  return MCIERR_INVALID_FILE;
426 
427  if (MIDI_mciReadWord(wmm, &wmm->wFormat) != 0 ||
428  MIDI_mciReadWord(wmm, &wmm->nTracks) != 0 ||
429  MIDI_mciReadWord(wmm, &wmm->nDivision) != 0) {
430  return MCIERR_INVALID_FILE;
431  }
432 
433  TRACE("toberead=0x%08X, wFormat=0x%04X nTracks=0x%04X nDivision=0x%04X\n",
434  toberead, wmm->wFormat, wmm->nTracks, wmm->nDivision);
435 
436  /* MS doc says that the MIDI MCI time format must be put by default to the format
437  * stored in the MIDI file...
438  */
439  if (wmm->nDivision > 0x8000) {
440  /* eric.pouech@lemel.fr 98/11
441  * I did not check this very code (pulses are expressed as SMPTE sub-frames).
442  * In about 40 MB of MIDI files I have, none was SMPTE based...
443  * I'm just wondering if this is widely used :-). So, if someone has one of
444  * these files, I'd like to know about it.
445  */
446  FIXME("Handling SMPTE time in MIDI files has not been tested\n"
447  "Please report to comp.emulators.ms-windows.wine with MIDI file !\n");
448 
449  switch (HIBYTE(wmm->nDivision)) {
450  case 0xE8: wmm->dwMciTimeFormat = MCI_FORMAT_SMPTE_24; break; /* -24 */
451  case 0xE7: wmm->dwMciTimeFormat = MCI_FORMAT_SMPTE_25; break; /* -25 */
452  case 0xE3: wmm->dwMciTimeFormat = MCI_FORMAT_SMPTE_30DROP; break; /* -29 */ /* is the MCI constant correct ? */
453  case 0xE2: wmm->dwMciTimeFormat = MCI_FORMAT_SMPTE_30; break; /* -30 */
454  default:
455  WARN("Unsupported number of frames %d\n", -(char)HIBYTE(wmm->nDivision));
456  return MCIERR_INVALID_FILE;
457  }
458  switch (LOBYTE(wmm->nDivision)) {
459  case 4: /* MIDI Time Code */
460  case 8:
461  case 10:
462  case 80: /* SMPTE bit resolution */
463  case 100:
464  default:
465  WARN("Unsupported number of sub-frames %d\n", LOBYTE(wmm->nDivision));
466  return MCIERR_INVALID_FILE;
467  }
468  } else if (wmm->nDivision == 0) {
469  WARN("Number of division is 0, can't support that !!\n");
470  return MCIERR_INVALID_FILE;
471  } else {
473  }
474 
475  switch (wmm->wFormat) {
476  case 0:
477  if (wmm->nTracks != 1) {
478  WARN("Got type 0 file whose number of track is not 1. Setting it to 1\n");
479  wmm->nTracks = 1;
480  }
481  break;
482  case 1:
483  case 2:
484  break;
485  default:
486  WARN("Handling MIDI files which format = %d is not (yet) supported\n"
487  "Please report with MIDI file !\n", wmm->wFormat);
488  return MCIERR_INVALID_FILE;
489  }
490 
491  if (wmm->nTracks > 0x80) {
492  /* wTrackNr is 7 bits only */
493  FIXME("Truncating MIDI file with %u tracks\n", wmm->nTracks);
494  wmm->nTracks = 0x80;
495  }
496 
497  if ((wmm->tracks = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_MIDITRACK) * wmm->nTracks)) == NULL) {
498  return MCIERR_OUT_OF_MEMORY;
499  }
500 
501  toberead -= 3 * sizeof(WORD);
502  if (toberead > 0) {
503  TRACE("Size of MThd > 6, skipping %d extra bytes\n", toberead);
504  mmioSeek(wmm->hFile, toberead, SEEK_CUR);
505  }
506 
507  for (nt = 0; nt < wmm->nTracks; nt++) {
508  wmm->tracks[nt].wTrackNr = nt;
509  if (MIDI_mciReadMTrk(wmm, &wmm->tracks[nt]) != 0) {
510  WARN("Can't read 'MTrk' header\n");
511  return MCIERR_INVALID_FILE;
512  }
513  }
514 
515  wmm->dwTempo = 500000;
516 
517  return 0;
518 }
519 
520 /**************************************************************************
521  * MIDI_ConvertPulseToMS [internal]
522  */
524 {
525  DWORD ret = 0;
526 
527  /* FIXME: this function may return false values since the tempo (wmm->dwTempo)
528  * may change during file playing
529  */
530  if (wmm->nDivision == 0) {
531  FIXME("Shouldn't happen. wmm->nDivision = 0\n");
532  } else if (wmm->nDivision > 0x8000) { /* SMPTE, unchecked FIXME? */
533  int nf = -(char)HIBYTE(wmm->nDivision); /* number of frames */
534  int nsf = LOBYTE(wmm->nDivision); /* number of sub-frames */
535  ret = (pulse * 1000) / (nf * nsf);
536  } else {
537  ret = (DWORD)((double)pulse * ((double)wmm->dwTempo / 1000) /
538  (double)wmm->nDivision);
539  }
540 
541  /*
542  TRACE("pulse=%u tempo=%u division=%u=0x%04x => ms=%u\n",
543  pulse, wmm->dwTempo, wmm->nDivision, wmm->nDivision, ret);
544  */
545 
546  return ret;
547 }
548 
549 #define TIME_MS_IN_ONE_HOUR (60*60*1000)
550 #define TIME_MS_IN_ONE_MINUTE (60*1000)
551 #define TIME_MS_IN_ONE_SECOND (1000)
552 
553 /**************************************************************************
554  * MIDI_ConvertTimeFormatToMS [internal]
555  */
557 {
558  DWORD ret = 0;
559 
560  switch (wmm->dwMciTimeFormat) {
562  ret = val;
563  break;
564  case MCI_FORMAT_SMPTE_24:
565  ret =
566  (HIBYTE(HIWORD(val)) * 125) / 3 + LOBYTE(HIWORD(val)) * TIME_MS_IN_ONE_SECOND +
568  break;
569  case MCI_FORMAT_SMPTE_25:
570  ret =
573  break;
574  case MCI_FORMAT_SMPTE_30:
575  ret =
576  (HIBYTE(HIWORD(val)) * 100) / 3 + LOBYTE(HIWORD(val)) * TIME_MS_IN_ONE_SECOND +
578  break;
579  default:
580  WARN("Bad time format %u!\n", wmm->dwMciTimeFormat);
581  }
582  /*
583  TRACE("val=%u=0x%08x [tf=%u] => ret=%u\n", val, val, wmm->dwMciTimeFormat, ret);
584  */
585  return ret;
586 }
587 
588 /**************************************************************************
589  * MIDI_ConvertMSToTimeFormat [internal]
590  */
592 {
593  DWORD ret = 0, val = _val;
594  DWORD h, m, s, f;
595 
596  switch (wmm->dwMciTimeFormat) {
598  ret = val;
599  break;
600  case MCI_FORMAT_SMPTE_24:
601  case MCI_FORMAT_SMPTE_25:
602  case MCI_FORMAT_SMPTE_30:
606  switch (wmm->dwMciTimeFormat) {
607  case MCI_FORMAT_SMPTE_24:
608  /* one frame is 1000/24 val long, 1000/24 == 125/3 */
609  f = (val * 3) / 125; val -= (f * 125) / 3;
610  break;
611  case MCI_FORMAT_SMPTE_25:
612  /* one frame is 1000/25 ms long, 1000/25 == 40 */
613  f = val / 40; val -= f * 40;
614  break;
615  case MCI_FORMAT_SMPTE_30:
616  /* one frame is 1000/30 ms long, 1000/30 == 100/3 */
617  f = (val * 3) / 100; val -= (f * 100) / 3;
618  break;
619  default:
620  FIXME("There must be some bad bad programmer\n");
621  f = 0;
622  }
623  /* val contains the number of ms which cannot make a complete frame */
624  /* FIXME: is this correct ? programs seem to be happy with that */
625  ret = (f << 24) | (s << 16) | (m << 8) | (h << 0);
626  break;
627  default:
628  WARN("Bad time format %u!\n", wmm->dwMciTimeFormat);
629  }
630  /*
631  TRACE("val=%u [tf=%u] => ret=%u=0x%08x\n", _val, wmm->dwMciTimeFormat, ret, ret);
632  */
633  return ret;
634 }
635 
636 /**************************************************************************
637  * MIDI_GetMThdLengthMS [internal]
638  */
640 {
641  WORD nt;
642  DWORD ret = 0;
643 
644  for (nt = 0; nt < wmm->nTracks; nt++) {
645  if (wmm->wFormat == 2) {
646  ret += wmm->tracks[nt].dwLength;
647  } else if (wmm->tracks[nt].dwLength > ret) {
648  ret = wmm->tracks[nt].dwLength;
649  }
650  }
651  /* FIXME: this is wrong if there is a tempo change inside the file */
652  return MIDI_ConvertPulseToMS(wmm, ret);
653 }
654 
655 /**************************************************************************
656  * MIDI_mciOpen [internal]
657  */
659 {
660  DWORD dwRet = 0;
661 
662  TRACE("(%d, %08X, %p)\n", wmm->wDevID, dwFlags, lpParms);
663 
664  if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
666  return MCIERR_HARDWARE;
667 
668  if (wmm->nUseCount > 0) {
669  /* The driver is already opened on this channel
670  * MIDI sequencer cannot be shared
671  */
672  return MCIERR_DEVICE_OPEN;
673  }
674  wmm->nUseCount++;
675 
676  wmm->hFile = 0;
677  wmm->hMidi = 0;
678  wmm->wPort = MIDI_MAPPER;
679  wmm->lpstrElementName = NULL;
680 
681  TRACE("wDevID=%d (lpParams->wDeviceID=%d)\n", wmm->wDevID, lpParms->wDeviceID);
682  /* lpParms->wDeviceID = wDevID;*/
683 
684  if (dwFlags & MCI_OPEN_ELEMENT) {
685  TRACE("MCI_OPEN_ELEMENT %s!\n", debugstr_w(lpParms->lpstrElementName));
686  if (lpParms->lpstrElementName && lpParms->lpstrElementName[0]) {
687  wmm->hFile = mmioOpenW((LPWSTR)lpParms->lpstrElementName, NULL,
689  if (wmm->hFile == 0) {
690  WARN("Can't find file %s!\n", debugstr_w(lpParms->lpstrElementName));
691  wmm->nUseCount--;
692  return MCIERR_FILE_NOT_FOUND;
693  }
695  (strlenW(lpParms->lpstrElementName) + 1) * sizeof(WCHAR));
696  strcpyW(wmm->lpstrElementName, lpParms->lpstrElementName);
697  }
698  }
699  TRACE("hFile=%p\n", wmm->hFile);
700 
701  wmm->lpstrCopyright = NULL;
702  wmm->lpstrName = NULL;
703 
704  wmm->dwStatus = MCI_MODE_NOT_READY; /* while loading file contents */
705  /* spec says it should be the default format from the MIDI file... */
707 
708  if (wmm->hFile != 0) {
709  MMCKINFO ckMainRIFF;
710  MMCKINFO mmckInfo;
711  DWORD dwOffset = 0;
712 
713  if (mmioDescend(wmm->hFile, &ckMainRIFF, NULL, 0) != 0) {
714  dwRet = MCIERR_INVALID_FILE;
715  } else {
716  TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08X\n",
717  (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
718 
719  if (ckMainRIFF.ckid == FOURCC_RIFF && ckMainRIFF.fccType == mmioFOURCC('R', 'M', 'I', 'D')) {
720  mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
721  mmioSeek(wmm->hFile, ckMainRIFF.dwDataOffset + ((ckMainRIFF.cksize + 1) & ~1), SEEK_SET);
722  if (mmioDescend(wmm->hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) == 0) {
723  TRACE("... is a 'RMID' file\n");
724  dwOffset = mmckInfo.dwDataOffset;
725  } else {
726  dwRet = MCIERR_INVALID_FILE;
727  }
728  }
729  if (dwRet == 0 && MIDI_mciReadMThd(wmm, dwOffset) != 0) {
730  WARN("Can't read 'MThd' header\n");
731  dwRet = MCIERR_INVALID_FILE;
732  }
733  }
734  } else {
735  TRACE("hFile==0, setting #tracks to 0; is this correct ?\n");
736  wmm->nTracks = 0;
737  wmm->wFormat = 0;
738  wmm->nDivision = 1;
739  }
740  if (dwRet != 0) {
741  wmm->nUseCount--;
742  if (wmm->hFile != 0)
743  mmioClose(wmm->hFile, 0);
744  wmm->hFile = 0;
745  HeapFree(GetProcessHeap(), 0, wmm->tracks);
748  HeapFree(GetProcessHeap(), 0, wmm->lpstrName);
749  } else {
750  wmm->dwPositionMS = 0;
751  wmm->dwStatus = MCI_MODE_STOP;
752  if (dwFlags & MCI_NOTIFY)
754  }
755  return dwRet;
756 }
757 
758 /**************************************************************************
759  * MIDI_mciStop [internal]
760  */
762 {
763  DWORD dwRet = 0;
764 
765  TRACE("(%d, %08X, %p);\n", wmm->wDevID, dwFlags, lpParms);
766 
767  if (wmm->dwStatus != MCI_MODE_STOP) {
769  if (old) mciDriverNotify(old, wmm->wDevID, MCI_NOTIFY_ABORTED);
770  }
771 
772  if (wmm->dwStatus != MCI_MODE_STOP) {
773  int oldstat = wmm->dwStatus;
774 
776  if (oldstat == MCI_MODE_PAUSE)
777  dwRet = midiOutReset((HMIDIOUT)wmm->hMidi);
778 
779  if (wmm->hThread)
781  }
782 
783  /* sanity reset */
784  wmm->dwStatus = MCI_MODE_STOP;
785 
786  if ((dwFlags & MCI_NOTIFY) && lpParms && MMSYSERR_NOERROR==dwRet)
788  return dwRet;
789 }
790 
791 /**************************************************************************
792  * MIDI_mciClose [internal]
793  */
795 {
796 
797  TRACE("(%d, %08X, %p);\n", wmm->wDevID, dwFlags, lpParms);
798 
799  if (wmm->dwStatus != MCI_MODE_STOP) {
800  /* mciStop handles MCI_NOTIFY_ABORTED */
801  MIDI_mciStop(wmm, MCI_WAIT, lpParms);
802  }
803 
804  wmm->nUseCount--;
805  if (wmm->nUseCount == 0) {
806  if (wmm->hFile != 0) {
807  mmioClose(wmm->hFile, 0);
808  wmm->hFile = 0;
809  TRACE("hFile closed !\n");
810  }
811  if (wmm->hThread) {
812  CloseHandle(wmm->hThread);
813  wmm->hThread = 0;
814  }
815  HeapFree(GetProcessHeap(), 0, wmm->tracks);
818  HeapFree(GetProcessHeap(), 0, wmm->lpstrName);
819  } else {
820  TRACE("Shouldn't happen... nUseCount=%d\n", wmm->nUseCount);
821  return MCIERR_INTERNAL;
822  }
823 
824  if ((dwFlags & MCI_NOTIFY) && lpParms) {
826  }
827  return 0;
828 }
829 
830 /**************************************************************************
831  * MIDI_mciFindNextEvent [internal]
832  */
834 {
835  WORD cnt, nt;
836  MCI_MIDITRACK* mmt;
837 
838  *hiPulse = 0xFFFFFFFFul;
839  cnt = 0xFFFFu;
840  for (nt = 0; nt < wmm->nTracks; nt++) {
841  mmt = &wmm->tracks[nt];
842 
843  if (mmt->wStatus == 0)
844  continue;
845  if (mmt->dwEventPulse < *hiPulse) {
846  *hiPulse = mmt->dwEventPulse;
847  cnt = nt;
848  }
849  }
850  return (cnt == 0xFFFFu) ? 0 /* no more event on all tracks */
851  : &wmm->tracks[cnt];
852 }
853 
854 /**************************************************************************
855  * MIDI_player [internal]
856  */
858 {
859  DWORD dwRet;
860  WORD doPlay, nt;
861  MCI_MIDITRACK* mmt;
862  DWORD hiPulse, dwStartMS = wmm->dwPositionMS;
863  HANDLE oldcb = NULL;
864 
865  /* init tracks */
866  for (nt = 0; nt < wmm->nTracks; nt++) {
867  mmt = &wmm->tracks[nt];
868 
869  mmt->wStatus = 1; /* ok, playing */
870  mmt->dwIndex = mmt->dwFirst;
871  if (wmm->wFormat == 2 && nt > 0) {
872  mmt->dwEventPulse = wmm->tracks[nt - 1].dwLength;
873  } else {
874  mmt->dwEventPulse = 0;
875  }
876  MIDI_mciReadNextEvent(wmm, mmt); /* FIXME == 0 */
877  }
878 
879  dwRet = midiOutOpen((LPHMIDIOUT)&wmm->hMidi, wmm->wPort, 0L, 0L, CALLBACK_NULL);
880  if (dwRet != MMSYSERR_NOERROR) {
881  return mmr2mci(dwRet);
882  }
883 
884  wmm->dwPulse = 0;
885  wmm->dwTempo = 500000;
886  wmm->dwPositionMS = 0;
887  wmm->wStartedPlaying = FALSE;
888 
889  while (wmm->dwStatus != MCI_MODE_STOP && wmm->dwStatus != MCI_MODE_NOT_READY) {
890  /* it seems that in case of multi-threading, gcc is optimizing just a little bit
891  * too much. Tell gcc not to optimize status value using volatile.
892  */
893  while (((volatile WINE_MCIMIDI*)wmm)->dwStatus == MCI_MODE_PAUSE);
894 
895  doPlay = (wmm->dwPositionMS >= dwStartMS && wmm->dwPositionMS <= wmm->dwEndMS);
896 
897  TRACE("wmm->dwStatus=%d, doPlay=%c\n", wmm->dwStatus, doPlay ? 'T' : 'F');
898 
899  if ((mmt = MIDI_mciFindNextEvent(wmm, &hiPulse)) == NULL)
900  break; /* no more event on tracks */
901 
902  /* if starting playing, then set StartTicks to the value it would have had
903  * if play had started at position 0
904  */
905  if (doPlay && !wmm->wStartedPlaying) {
907  wmm->wStartedPlaying = TRUE;
908  TRACE("Setting dwStartTicks to %u\n", wmm->dwStartTicks);
909  }
910 
911  if (hiPulse > wmm->dwPulse) {
912  wmm->dwPositionMS += MIDI_ConvertPulseToMS(wmm, hiPulse - wmm->dwPulse);
913  if (doPlay) {
914  DWORD togo = wmm->dwStartTicks + wmm->dwPositionMS;
915  DWORD tc = GetTickCount();
916 
917  TRACE("Pulses hi=0x%08x <> cur=0x%08x\n", hiPulse, wmm->dwPulse);
918  TRACE("Wait until %u => %u ms\n",
919  tc - wmm->dwStartTicks, togo - wmm->dwStartTicks);
920  if (tc < togo)
921  Sleep(togo - tc);
922  }
923  wmm->dwPulse = hiPulse;
924  }
925 
926  switch (LOBYTE(LOWORD(mmt->dwEventData))) {
927  case 0xF0:
928  case 0xF7: /* sysex events */
929  {
930  FIXME("Not handling SysEx events (yet)\n");
931  }
932  break;
933  case 0xFF:
934  /* position after meta data header */
935  mmioSeek(wmm->hFile, mmt->dwIndex + HIWORD(mmt->dwEventData), SEEK_SET);
936  switch (HIBYTE(LOWORD(mmt->dwEventData))) {
937  case 0x00: /* 16-bit sequence number */
938  if (TRACE_ON(mcimidi)) {
939  WORD twd;
940 
941  MIDI_mciReadWord(wmm, &twd); /* == 0 */
942  TRACE("Got sequence number %u\n", twd);
943  }
944  break;
945  case 0x01: /* any text */
946  case 0x02: /* Copyright Message text */
947  case 0x03: /* Sequence/Track Name text */
948  case 0x04: /* Instrument Name text */
949  case 0x05: /* Lyric text */
950  case 0x06: /* Marker text */
951  case 0x07: /* Cue-point text */
952  if (TRACE_ON(mcimidi)) {
953  char buf[1024];
954  WORD len = mmt->wEventLength - HIWORD(mmt->dwEventData);
955  static const char* const info[8] = {"", "Text", "Copyright", "Seq/Trk name",
956  "Instrument", "Lyric", "Marker", "Cue-point"};
957  WORD idx = HIBYTE(LOWORD(mmt->dwEventData));
958 
959  if (len >= sizeof(buf)) {
960  WARN("Buffer for text is too small (%u are needed)\n", len);
961  len = sizeof(buf) - 1;
962  }
963  if (mmioRead(wmm->hFile, buf, len) == len) {
964  buf[len] = 0; /* end string in case */
965  TRACE("%s => \"%s\"\n", (idx < 8 ) ? info[idx] : "", buf);
966  } else {
967  WARN("Couldn't read data for %s\n", (idx < 8) ? info[idx] : "");
968  }
969  }
970  break;
971  case 0x20:
972  /* MIDI channel (cc) */
973  if (FIXME_ON(mcimidi)) {
974  BYTE bt;
975 
976  MIDI_mciReadByte(wmm, &bt); /* == 0 */
977  FIXME("NIY: MIDI channel=%u, track=%u\n", bt, mmt->wTrackNr);
978  }
979  break;
980  case 0x21:
981  /* MIDI port (pp) */
982  if (FIXME_ON(mcimidi)) {
983  BYTE bt;
984 
985  MIDI_mciReadByte(wmm, &bt); /* == 0 */
986  FIXME("NIY: MIDI port=%u, track=%u\n", bt, mmt->wTrackNr);
987  }
988  break;
989  case 0x2F: /* end of track */
990  mmt->wStatus = 0;
991  break;
992  case 0x51:/* set tempo */
993  /* Tempo is expressed in -seconds per midi quarter note
994  * for format 1 MIDI files, this can only be present on track #0
995  */
996  if (mmt->wTrackNr != 0 && wmm->wFormat == 1) {
997  WARN("For format #1 MIDI files, tempo can only be changed on track #0 (%u)\n", mmt->wTrackNr);
998  } else {
999  BYTE tbt;
1000  DWORD value = 0;
1001 
1002  MIDI_mciReadByte(wmm, &tbt); value = ((DWORD)tbt) << 16;
1003  MIDI_mciReadByte(wmm, &tbt); value |= ((DWORD)tbt) << 8;
1004  MIDI_mciReadByte(wmm, &tbt); value |= ((DWORD)tbt) << 0;
1005  TRACE("Setting tempo to %d (BPM=%d)\n", wmm->dwTempo, (value) ? (60000000 / value) : 0);
1006  wmm->dwTempo = value;
1007  }
1008  break;
1009  case 0x54: /* (hour) (min) (second) (frame) (fractional-frame) - SMPTE track start */
1010  if (mmt->wTrackNr != 0 && wmm->wFormat == 1) {
1011  WARN("For format #1 MIDI files, SMPTE track start can only be expressed on track #0 (%u)\n", mmt->wTrackNr);
1012  } if (mmt->dwEventPulse != 0) {
1013  WARN("SMPTE track start can only be expressed at start of track (%u)\n", mmt->dwEventPulse);
1014  } else {
1015  BYTE h, m, s, f, ff;
1016 
1017  MIDI_mciReadByte(wmm, &h);
1018  MIDI_mciReadByte(wmm, &m);
1019  MIDI_mciReadByte(wmm, &s);
1020  MIDI_mciReadByte(wmm, &f);
1021  MIDI_mciReadByte(wmm, &ff);
1022  FIXME("NIY: SMPTE track start %u:%u:%u %u.%u\n", h, m, s, f, ff);
1023  }
1024  break;
1025  case 0x58: /* file rhythm */
1026  if (TRACE_ON(mcimidi)) {
1027  BYTE num, den, cpmc, _32npqn;
1028 
1029  MIDI_mciReadByte(wmm, &num);
1030  MIDI_mciReadByte(wmm, &den); /* to notate e.g. 6/8 */
1031  MIDI_mciReadByte(wmm, &cpmc); /* number of MIDI clocks per metronome click */
1032  MIDI_mciReadByte(wmm, &_32npqn); /* number of notated 32nd notes per MIDI quarter note */
1033 
1034  TRACE("%u/%u, clock per metronome click=%u, 32nd notes by 1/4 note=%u\n", num, 1 << den, cpmc, _32npqn);
1035  }
1036  break;
1037  case 0x59: /* key signature */
1038  if (TRACE_ON(mcimidi)) {
1039  BYTE sf, mm;
1040 
1041  MIDI_mciReadByte(wmm, &sf);
1042  MIDI_mciReadByte(wmm, &mm);
1043 
1044  if (sf >= 0x80) TRACE("%d flats\n", -(char)sf);
1045  else if (sf > 0) TRACE("%d sharps\n", (char)sf);
1046  else TRACE("Key of C\n");
1047  TRACE("Mode: %s\n", (mm == 0) ? "major" : "minor");
1048  }
1049  break;
1050  default:
1051  WARN("Unknown MIDI meta event %02x. Skipping...\n", HIBYTE(LOWORD(mmt->dwEventData)));
1052  break;
1053  }
1054  break;
1055  default:
1056  if (doPlay) {
1057  dwRet = midiOutShortMsg((HMIDIOUT)wmm->hMidi, mmt->dwEventData);
1058  } else {
1059  switch (LOBYTE(LOWORD(mmt->dwEventData)) & 0xF0) {
1060  case MIDI_NOTEON:
1061  case MIDI_NOTEOFF:
1062  dwRet = 0;
1063  break;
1064  default:
1065  dwRet = midiOutShortMsg((HMIDIOUT)wmm->hMidi, mmt->dwEventData);
1066  }
1067  }
1068  }
1069  mmt->dwIndex += mmt->wEventLength;
1070  if (mmt->dwIndex < mmt->dwFirst || mmt->dwIndex >= mmt->dwLast) {
1071  mmt->wStatus = 0;
1072  }
1073  if (mmt->wStatus) {
1074  MIDI_mciReadNextEvent(wmm, mmt);
1075  }
1076  }
1077 
1078  midiOutReset((HMIDIOUT)wmm->hMidi);
1079 
1080  dwRet = midiOutClose((HMIDIOUT)wmm->hMidi);
1081 
1082  if (dwFlags & MCI_NOTIFY)
1083  oldcb = InterlockedExchangePointer(&wmm->hCallback, NULL);
1084 
1085  wmm->dwStatus = MCI_MODE_STOP;
1086 
1087  /* Let the potentially asynchronous commands support FAILURE notification. */
1088  if (oldcb) mciDriverNotify(oldcb, wmm->wDevID,
1090  return mmr2mci(dwRet);
1091 }
1092 
1094 {
1095  WINE_MCIMIDI* wmm = ptr;
1096  return MIDI_player(wmm, MCI_NOTIFY);
1097 }
1098 
1100 {
1101  if (1) {
1102  DWORD dwRet;
1103 
1104  switch (wmm->dwStatus) {
1105  default:
1107  case MCI_MODE_PAUSE:
1108  return MIDI_mciResume(wmm, 0, NULL);
1109  case MCI_MODE_PLAY:
1110  /* the player was not stopped, use it */
1111  return 0;
1112  case MCI_MODE_STOP:
1113  break;
1114  }
1115  wmm->dwStatus = MCI_MODE_PLAY;
1116  if (wmm->hThread) {
1118  CloseHandle(wmm->hThread);
1119  wmm->hThread = 0;
1120  }
1121  wmm->hThread = CreateThread(NULL, 0, MIDI_Starter, wmm, 0, NULL);
1122  if (!wmm->hThread) {
1123  dwRet = MCIERR_OUT_OF_MEMORY;
1124  } else {
1126  dwRet = 0;
1127  }
1128  if (dwRet)
1129  wmm->dwStatus = MCI_MODE_STOP;
1130  return dwRet;
1131  }
1132 }
1133 
1134 /**************************************************************************
1135  * MIDI_mciPlay [internal]
1136  */
1138 {
1139  DWORD dwStartMS, dwEndMS;
1140  DWORD dwRet;
1141  HANDLE oldcb;
1142 
1143  TRACE("(%d, %08X, %p);\n", wmm->wDevID, dwFlags, lpParms);
1144 
1145  if (wmm->hFile == 0) {
1146  WARN("Can't play: no file %s!\n", debugstr_w(wmm->lpstrElementName));
1147  return MCIERR_FILE_NOT_FOUND;
1148  }
1149 
1150  if (lpParms && (dwFlags & MCI_TO)) {
1151  dwEndMS = MIDI_ConvertTimeFormatToMS(wmm, lpParms->dwTo);
1152  /* FIXME: if (dwEndMS > length) return MCIERR_OUTOFRANGE; */
1153  } else {
1154  dwEndMS = 0xFFFFFFFFul; /* FIXME: dwEndMS = length; */
1155  }
1156  if (lpParms && (dwFlags & MCI_FROM)) {
1157  dwStartMS = MIDI_ConvertTimeFormatToMS(wmm, lpParms->dwFrom);
1158  } else {
1159  dwStartMS = wmm->dwPositionMS;
1160  }
1161  if (dwEndMS < dwStartMS)
1162  return MCIERR_OUTOFRANGE;
1163 
1164  if (dwFlags & MCI_FROM) {
1165  /* Stop with MCI_NOTIFY_ABORTED and set new position. */
1166  MIDI_mciStop(wmm, MCI_WAIT, NULL);
1167  wmm->dwPositionMS = dwStartMS;
1168  } /* else use existing player. */
1169  if (wmm->dwEndMS != dwEndMS) {
1170  oldcb = InterlockedExchangePointer(&wmm->hCallback, NULL);
1171  if (oldcb) mciDriverNotify(oldcb, wmm->wDevID, MCI_NOTIFY_ABORTED);
1172  wmm->dwEndMS = dwEndMS;
1173  }
1174 
1175  TRACE("Playing from %u to %u\n", dwStartMS, dwEndMS);
1176 
1177  if ((dwFlags & MCI_NOTIFY) && lpParms) {
1178  oldcb = InterlockedExchangePointer(&wmm->hCallback, HWND_32(LOWORD(lpParms->dwCallback)));
1179  if (oldcb) mciDriverNotify(oldcb, wmm->wDevID, MCI_NOTIFY_SUPERSEDED);
1180  }
1181 
1182  dwRet = ensurePlayerThread(wmm);
1183 
1184  if (!dwRet && (dwFlags & MCI_WAIT)) {
1186  GetExitCodeThread(wmm->hThread, &dwRet);
1187  /* STATUS_PENDING cannot happen. It folds onto MCIERR_UNRECOGNIZED_KEYWORD */
1188  }
1189  /* The player thread performs notification at exit. */
1190  return dwRet;
1191 }
1192 
1193 /**************************************************************************
1194  * MIDI_mciPause [internal]
1195  */
1197 {
1198  TRACE("(%d, %08X, %p);\n", wmm->wDevID, dwFlags, lpParms);
1199 
1200  if (wmm->dwStatus == MCI_MODE_PLAY) {
1201  /* stop all notes */
1202  unsigned chn;
1203  for (chn = 0; chn < 16; chn++)
1204  midiOutShortMsg((HMIDIOUT)(wmm->hMidi), 0x78B0 | chn);
1205  wmm->dwStatus = MCI_MODE_PAUSE;
1206  }
1207  if ((dwFlags & MCI_NOTIFY) && lpParms)
1209  return 0;
1210 }
1211 
1212 /**************************************************************************
1213  * MIDI_mciResume [internal]
1214  */
1216 {
1217  TRACE("(%d, %08X, %p);\n", wmm->wDevID, dwFlags, lpParms);
1218 
1219  if (wmm->dwStatus == MCI_MODE_PAUSE) {
1220  wmm->wStartedPlaying = FALSE;
1221  wmm->dwStatus = MCI_MODE_PLAY;
1222  }
1223  if ((dwFlags & MCI_NOTIFY) && lpParms)
1225  return 0;
1226 }
1227 
1228 /**************************************************************************
1229  * MIDI_mciSet [internal]
1230  */
1232 {
1233  TRACE("(%d, %08X, %p);\n", wmm->wDevID, dwFlags, lpParms);
1234 
1235  if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1236 
1237  if (dwFlags & MCI_SET_TIME_FORMAT) {
1238  switch (lpParms->dwTimeFormat) {
1240  TRACE("MCI_FORMAT_MILLISECONDS !\n");
1242  break;
1243  case MCI_FORMAT_SMPTE_24:
1244  TRACE("MCI_FORMAT_SMPTE_24 !\n");
1246  break;
1247  case MCI_FORMAT_SMPTE_25:
1248  TRACE("MCI_FORMAT_SMPTE_25 !\n");
1250  break;
1251  case MCI_FORMAT_SMPTE_30:
1252  TRACE("MCI_FORMAT_SMPTE_30 !\n");
1254  break;
1255  default:
1256  WARN("Bad time format %u!\n", lpParms->dwTimeFormat);
1257  return MCIERR_BAD_TIME_FORMAT;
1258  }
1259  }
1260  if (dwFlags & MCI_SET_VIDEO) {
1261  TRACE("No support for video !\n");
1263  }
1264  if (dwFlags & MCI_SET_DOOR_OPEN) {
1265  TRACE("No support for door open !\n");
1267  }
1268  if (dwFlags & MCI_SET_DOOR_CLOSED) {
1269  TRACE("No support for door close !\n");
1271  }
1272  if (dwFlags & MCI_SET_AUDIO) {
1273  if (dwFlags & MCI_SET_ON) {
1274  TRACE("MCI_SET_ON audio !\n");
1275  } else if (dwFlags & MCI_SET_OFF) {
1276  TRACE("MCI_SET_OFF audio !\n");
1277  } else {
1278  WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
1279  return MCIERR_BAD_INTEGER;
1280  }
1281 
1282  switch (lpParms->dwAudio)
1283  {
1284  case MCI_SET_AUDIO_ALL: TRACE("MCI_SET_AUDIO_ALL !\n"); break;
1285  case MCI_SET_AUDIO_LEFT: TRACE("MCI_SET_AUDIO_LEFT !\n"); break;
1286  case MCI_SET_AUDIO_RIGHT: TRACE("MCI_SET_AUDIO_RIGHT !\n"); break;
1287  default: WARN("Unknown audio channel %u\n", lpParms->dwAudio); break;
1288  }
1289  }
1290 
1292  TRACE("MCI_SEQ_SET_MASTER !\n");
1293  if (dwFlags & MCI_SEQ_SET_SLAVE)
1294  TRACE("MCI_SEQ_SET_SLAVE !\n");
1296  TRACE("MCI_SEQ_SET_OFFSET !\n");
1297  if (dwFlags & MCI_SEQ_SET_PORT) {
1298  TRACE("MCI_SEQ_SET_PORT = %d\n", lpParms->dwPort);
1299  if ((UINT16)lpParms->dwPort != (UINT16)MIDI_MAPPER &&
1300  (UINT16)lpParms->dwPort >= midiOutGetNumDevs())
1301  /* FIXME: input/output port distinction? */
1303  /* FIXME: Native manages to swap the device while playing! */
1304  wmm->wPort = lpParms->dwPort;
1305  }
1306  if (dwFlags & MCI_SEQ_SET_TEMPO)
1307  TRACE("MCI_SEQ_SET_TEMPO !\n");
1308  if (dwFlags & MCI_NOTIFY)
1310  return 0;
1311 }
1312 
1313 /**************************************************************************
1314  * MIDI_mciStatus [internal]
1315  */
1317 {
1318  DWORD ret = 0;
1319 
1320  TRACE("(%d, %08X, %p);\n", wmm->wDevID, dwFlags, lpParms);
1321 
1322  if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1323 
1324  if (dwFlags & MCI_STATUS_ITEM) {
1325  switch (lpParms->dwItem) {
1327  /* FIXME in Format 2 */
1328  lpParms->dwReturn = 1;
1329  TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
1330  break;
1331  case MCI_STATUS_LENGTH:
1332  if ((dwFlags & MCI_TRACK) && wmm->wFormat == 2) {
1333  if (lpParms->dwTrack >= wmm->nTracks)
1334  return MCIERR_OUTOFRANGE;
1335  /* FIXME: this is wrong if there is a tempo change inside the file */
1336  lpParms->dwReturn = MIDI_ConvertPulseToMS(wmm, wmm->tracks[lpParms->dwTrack].dwLength);
1337  } else {
1338  lpParms->dwReturn = MIDI_GetMThdLengthMS(wmm);
1339  }
1340  lpParms->dwReturn = MIDI_ConvertMSToTimeFormat(wmm, lpParms->dwReturn);
1341  /* FIXME: ret = MCI_COLONIZED4_RETURN if SMPTE */
1342  TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
1343  break;
1344  case MCI_STATUS_MODE:
1345  TRACE("MCI_STATUS_MODE => %u\n", wmm->dwStatus);
1346  lpParms->dwReturn = MAKEMCIRESOURCE(wmm->dwStatus, wmm->dwStatus);
1348  break;
1350  TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE\n");
1351  lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1353  break;
1355  lpParms->dwReturn = (wmm->wFormat == 2) ? wmm->nTracks : 1;
1356  TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu\n", lpParms->dwReturn);
1357  break;
1358  case MCI_STATUS_POSITION:
1359  /* FIXME: check MCI_TRACK == 1 if set */
1360  lpParms->dwReturn = MIDI_ConvertMSToTimeFormat(wmm,
1361  (dwFlags & MCI_STATUS_START) ? 0 : wmm->dwPositionMS);
1362  /* FIXME: ret = MCI_COLONIZED4_RETURN if SMPTE */
1363  TRACE("MCI_STATUS_POSITION %s => %lu\n",
1364  (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
1365  break;
1366  case MCI_STATUS_READY:
1367  lpParms->dwReturn = (wmm->dwStatus == MCI_MODE_NOT_READY) ?
1370  TRACE("MCI_STATUS_READY = %u\n", LOWORD(lpParms->dwReturn));
1371  break;
1374  TRACE("MCI_STATUS_TIME_FORMAT => %u\n", LOWORD(lpParms->dwReturn));
1376  break;
1378  TRACE("MCI_SEQ_STATUS_DIVTYPE !\n");
1379  if (wmm->nDivision > 0x8000) {
1380  switch (HIBYTE(wmm->nDivision)) {
1381  case 0xE8: lpParms->dwReturn = MCI_SEQ_DIV_SMPTE_24; break; /* -24 */
1382  case 0xE7: lpParms->dwReturn = MCI_SEQ_DIV_SMPTE_25; break; /* -25 */
1383  case 0xE3: lpParms->dwReturn = MCI_SEQ_DIV_SMPTE_30DROP; break; /* -29 */ /* is the MCI constant correct ? */
1384  case 0xE2: lpParms->dwReturn = MCI_SEQ_DIV_SMPTE_30; break; /* -30 */
1385  default: FIXME("There is a bad bad programmer\n");
1386  }
1387  } else {
1388  lpParms->dwReturn = MCI_SEQ_DIV_PPQN;
1389  }
1390  lpParms->dwReturn = MAKEMCIRESOURCE(lpParms->dwReturn,lpParms->dwReturn);
1392  break;
1393  case MCI_SEQ_STATUS_MASTER:
1394  TRACE("MCI_SEQ_STATUS_MASTER !\n");
1397  break;
1398  case MCI_SEQ_STATUS_SLAVE:
1399  TRACE("MCI_SEQ_STATUS_SLAVE !\n");
1402  break;
1403  case MCI_SEQ_STATUS_OFFSET:
1404  TRACE("MCI_SEQ_STATUS_OFFSET !\n");
1405  lpParms->dwReturn = 0;
1406  break;
1407  case MCI_SEQ_STATUS_PORT:
1408  if (wmm->wPort != (UINT16)MIDI_MAPPER)
1409  lpParms->dwReturn = wmm->wPort;
1410  else {
1413  }
1414  TRACE("MCI_SEQ_STATUS_PORT (%u) => %d\n", wmm->wDevID, wmm->wPort);
1415  break;
1416  case MCI_SEQ_STATUS_TEMPO:
1417  TRACE("MCI_SEQ_STATUS_TEMPO !\n");
1418  lpParms->dwReturn = wmm->dwTempo;
1419  break;
1420  default:
1421  FIXME("Unknown command %08X !\n", lpParms->dwItem);
1423  }
1424  } else {
1425  return MCIERR_MISSING_PARAMETER;
1426  }
1427  if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
1429  return ret;
1430 }
1431 
1432 /**************************************************************************
1433  * MIDI_mciGetDevCaps [internal]
1434  */
1436  LPMCI_GETDEVCAPS_PARMS lpParms)
1437 {
1438  DWORD ret;
1439 
1440  TRACE("(%d, %08X, %p);\n", wmm->wDevID, dwFlags, lpParms);
1441 
1442  if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1443 
1444  if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1445  switch (lpParms->dwItem) {
1447  TRACE("MCI_GETDEVCAPS_DEVICE_TYPE !\n");
1450  break;
1452  TRACE("MCI_GETDEVCAPS_HAS_AUDIO !\n");
1453  lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1455  break;
1457  TRACE("MCI_GETDEVCAPS_HAS_VIDEO !\n");
1458  lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1460  break;
1462  TRACE("MCI_GETDEVCAPS_USES_FILES !\n");
1463  lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1465  break;
1467  TRACE("MCI_GETDEVCAPS_COMPOUND_DEVICE !\n");
1468  lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1470  break;
1472  TRACE("MCI_GETDEVCAPS_CAN_EJECT !\n");
1473  lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1475  break;
1477  TRACE("MCI_GETDEVCAPS_CAN_PLAY !\n");
1478  lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1480  break;
1482  TRACE("MCI_GETDEVCAPS_CAN_RECORD !\n");
1483  lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1485  break;
1487  TRACE("MCI_GETDEVCAPS_CAN_SAVE !\n");
1488  lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1490  break;
1491  default:
1492  FIXME("Unknown capability (%08x) !\n", lpParms->dwItem);
1494  }
1495  } else {
1496  WARN("No GetDevCaps-Item !\n");
1498  }
1499  if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
1501  return ret;
1502 }
1503 
1504 /**************************************************************************
1505  * MIDI_mciInfo [internal]
1506  */
1508 {
1509  LPCWSTR str = 0;
1510  DWORD ret = 0;
1511  static const WCHAR wszMidiSeq[] = {'W','i','n','e','\'','s',' ','M','I','D','I',' ','s','e','q','u','e','n','c','e','r',0};
1512 
1513  TRACE("(%d, %08X, %p);\n", wmm->wDevID, dwFlags, lpParms);
1514 
1515  if (lpParms == NULL || lpParms->lpstrReturn == NULL)
1517 
1518  TRACE("buf=%p, len=%u\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1519 
1520  switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1521  case MCI_INFO_PRODUCT: str = wszMidiSeq; break;
1522  case MCI_INFO_FILE: str = wmm->lpstrElementName; break;
1523  case MCI_INFO_COPYRIGHT: str = wmm->lpstrCopyright; break;
1524  case MCI_INFO_NAME: str = wmm->lpstrName; break;
1525  default:
1526  WARN("Don't know this info command (%u)\n", dwFlags);
1527  return MCIERR_MISSING_PARAMETER; /* not MCIERR_FLAGS_... */
1528  }
1529  if (!ret) {
1530  if (lpParms->dwRetSize) {
1531  WCHAR zero = 0;
1532  /* FIXME? Since NT, mciwave, mciseq and mcicda set dwRetSize
1533  * to the number of characters written, excluding \0. */
1534  lstrcpynW(lpParms->lpstrReturn, str ? str : &zero, lpParms->dwRetSize);
1535  } else ret = MCIERR_PARAM_OVERFLOW;
1536  }
1537  if (MMSYSERR_NOERROR==ret && (dwFlags & MCI_NOTIFY))
1539  return ret;
1540 }
1541 
1542 /**************************************************************************
1543  * MIDI_mciSeek [internal]
1544  */
1546 {
1547  DWORD position;
1548 
1549  TRACE("(%d, %08X, %p);\n", wmm->wDevID, dwFlags, lpParms);
1550 
1551  if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1552 
1554  if (!position) return MCIERR_MISSING_PARAMETER;
1555  if (position&(position-1)) return MCIERR_FLAGS_NOT_COMPATIBLE;
1556 
1557  MIDI_mciStop(wmm, MCI_WAIT, 0);
1558 
1559  if (dwFlags & MCI_TO) { /* FIXME: compare with length */
1560  wmm->dwPositionMS = MIDI_ConvertTimeFormatToMS(wmm, lpParms->dwTo);
1561  } else if (dwFlags & MCI_SEEK_TO_START) {
1562  wmm->dwPositionMS = 0;
1563  } else {
1564  wmm->dwPositionMS = 0xFFFFFFFF; /* FIXME */
1565  }
1566 
1567  TRACE("Seeking to position=%u ms\n", wmm->dwPositionMS);
1568 
1569  if (dwFlags & MCI_NOTIFY)
1571 
1572  return 0;
1573 }
1574 
1575 /*======================================================================*
1576  * MIDI entry points *
1577  *======================================================================*/
1578 
1579 /**************************************************************************
1580  * DriverProc (MCISEQ.@)
1581  */
1582 LRESULT CALLBACK MCIMIDI_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1583  LPARAM dwParam1, LPARAM dwParam2)
1584 {
1585  WINE_MCIMIDI* wmm;
1586  switch (wMsg) {
1587  case DRV_LOAD: return 1;
1588  case DRV_FREE: return 1;
1589  case DRV_ENABLE: return 1;
1590  case DRV_DISABLE: return 1;
1591  case DRV_QUERYCONFIGURE: return 1;
1592  case DRV_CONFIGURE: MessageBoxA(0, "Sample Midi Driver !", "OSS Driver", MB_OK); return 1;
1593  case DRV_INSTALL: return DRVCNF_RESTART;
1594  case DRV_REMOVE: return DRVCNF_RESTART;
1595  case DRV_OPEN: return MIDI_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1596  case DRV_CLOSE: return MIDI_drvClose(dwDevID);
1597  }
1598  if ((wMsg < DRV_MCI_FIRST) || (wMsg > DRV_MCI_LAST)) {
1599  TRACE("Sending msg %04x to default driver proc\n", wMsg);
1600  return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1601  }
1602 
1603  wmm = MIDI_mciGetOpenDev(dwDevID, wMsg);
1604  if (wmm == NULL) return MCIERR_INVALID_DEVICE_ID;
1605 
1606  switch (wMsg) {
1607  case MCI_OPEN_DRIVER: return MIDI_mciOpen (wmm, dwParam1, (LPMCI_OPEN_PARMSW) dwParam2);
1608  case MCI_CLOSE_DRIVER: return MIDI_mciClose (wmm, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1609  case MCI_PLAY: return MIDI_mciPlay (wmm, dwParam1, (LPMCI_PLAY_PARMS) dwParam2);
1610  case MCI_STOP: return MIDI_mciStop (wmm, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1611  case MCI_SET: return MIDI_mciSet (wmm, dwParam1, (LPMCI_SEQ_SET_PARMS) dwParam2);
1612  case MCI_PAUSE: return MIDI_mciPause (wmm, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1613  case MCI_RESUME: return MIDI_mciResume (wmm, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1614  case MCI_STATUS: return MIDI_mciStatus (wmm, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
1615  case MCI_GETDEVCAPS: return MIDI_mciGetDevCaps(wmm, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
1616  case MCI_INFO: return MIDI_mciInfo (wmm, dwParam1, (LPMCI_INFO_PARMSW) dwParam2);
1617  case MCI_SEEK: return MIDI_mciSeek (wmm, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
1618  case MCI_OPEN:
1619  case MCI_CLOSE:
1620  FIXME("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1621  /* fall through */
1622  default:
1623  TRACE("Unsupported command [0x%x]\n", wMsg);
1624  return MCIERR_UNSUPPORTED_FUNCTION; /* Win9x: MCIERR_UNRECOGNIZED_COMMAND */
1625  }
1626 }
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
#define DRV_DISABLE
Definition: mmsystem.h:123
#define MMIO_ALLOCBUF
Definition: mmsystem.h:532
BOOL WINAPI mciSetDriverData(UINT uDeviceID, DWORD dwData)
#define MCI_NO_COMMAND_TABLE
Definition: mmddk.h:375
WORD wEventLength
Definition: mcimidi.c:54
#define MCIERR_NONAPPLICABLE_FUNCTION
Definition: mmsystem.h:610
#define SEEK_CUR
Definition: util.h:63
#define MCI_SEQ_DIV_PPQN
Definition: mmsystem.h:841
static WINE_MCIMIDI * MIDI_mciGetOpenDev(MCIDEVICEID wDevID, UINT wMsg)
Definition: mcimidi.c:146
#define MCI_MODE_STOP
Definition: mmsystem.h:695
#define MCIERR_INVALID_FILE
Definition: mmsystem.h:604
#define TIME_MS_IN_ONE_MINUTE
Definition: mcimidi.c:550
DWORD WINAPI mciGetDriverData(UINT uDeviceID)
Definition: mci.c:2066
static DWORD MIDI_ConvertPulseToMS(WINE_MCIMIDI *wmm, DWORD pulse)
Definition: mcimidi.c:523
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:736
#define MCI_SEQ_DIV_SMPTE_30DROP
Definition: mmsystem.h:844
#define MCI_INFO_PRODUCT
Definition: mmsystem.h:752
#define FIXME_ON(ch)
Definition: debug.h:406
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
#define MIDI_NOTEOFF
Definition: mcimidi.c:44
DWORD dwPulse
Definition: mcimidi.c:79
#define MCI_STATUS_ITEM
Definition: mmsystem.h:742
#define MCI_WAIT
Definition: mmsystem.h:730
#define MCI_FORMAT_SMPTE_25
Definition: mmsystem.h:706
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
DWORD dwLength
Definition: mcimidi.c:51
#define LOBYTE(W)
Definition: jmemdos.c:487
LRESULT CALLBACK MCIMIDI_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, LPARAM dwParam1, LPARAM dwParam2)
Definition: mcimidi.c:1582
#define MIDI_MAPPER
Definition: mmsystem.h:253
DWORD dwLast
Definition: mcimidi.c:49
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
WORD wStatus
Definition: mcimidi.c:55
DWORD_PTR dwCallback
Definition: mmsystem.h:2635
#define MCI_STATUS_NUMBER_OF_TRACKS
Definition: mmsystem.h:746
#define MCI_GETDEVCAPS_CAN_SAVE
Definition: mmsystem.h:767
#define CP_ACP
Definition: compat.h:99
#define TIME_MS_IN_ONE_HOUR
Definition: mcimidi.c:549
static DWORD MIDI_drvClose(DWORD dwDevID)
Definition: mcimidi.c:131
static DWORD MIDI_mciOpen(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_OPEN_PARMSW lpParms)
Definition: mcimidi.c:658
#define MCIERR_UNSUPPORTED_FUNCTION
Definition: mmsystem.h:584
#define WARN(fmt,...)
Definition: debug.h:111
DWORD dwDataOffset
Definition: mmsystem.h:1510
MMRESULT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags)
Definition: winmm.c:942
#define CALLBACK
Definition: compat.h:27
DWORD_PTR dwCallback
Definition: mmsystem.h:1537
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:445
#define HIBYTE(W)
Definition: jmemdos.c:486
static DWORD MIDI_mciReadMTrk(WINE_MCIMIDI *wmm, MCI_MIDITRACK *mmt)
Definition: mcimidi.c:316
static DWORD MIDI_mciStop(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
Definition: mcimidi.c:761
#define MIDI_NOTEON
Definition: mcimidi.c:45
#define MCI_GETDEVCAPS_COMPOUND_DEVICE
Definition: mmsystem.h:764
MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags)
Definition: mmio.c:701
#define MCI_SET_OFF
Definition: mmsystem.h:778
#define MCI_PLAY
Definition: mmsystem.h:649
#define DRV_CLOSE
Definition: mmsystem.h:122
#define MCI_RESUME
Definition: mmsystem.h:675
static DWORD MIDI_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
Definition: mcimidi.c:110
static DWORD MIDI_mciInfo(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_INFO_PARMSW lpParms)
Definition: mcimidi.c:1507
#define MCI_SEQ_DIV_SMPTE_24
Definition: mmsystem.h:842
static DWORD CALLBACK MIDI_Starter(void *ptr)
Definition: mcimidi.c:1093
#define MCI_SET_AUDIO
Definition: mmsystem.h:775
#define DRV_MCI_LAST
Definition: mmsystem.h:140
HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO *lpmmioinfo, DWORD dwOpenFlags)
Definition: mmio.c:669
#define MCI_RESOURCE_RETURNED
Definition: mmddk.h:369
#define MMIO_DENYWRITE
Definition: mmsystem.h:540
#define MCI_SEQ_STATUS_TEMPO
Definition: mmsystem.h:852
#define MCI_GETDEVCAPS_CAN_RECORD
Definition: mmsystem.h:759
char * LPSTR
Definition: xmlstorage.h:182
#define MAKEMCIRESOURCE(wRet, wRes)
Definition: mmddk.h:388
#define MCI_SET_DOOR_CLOSED
Definition: mmsystem.h:773
#define MCI_STATUS_POSITION
Definition: mmsystem.h:745
#define MCI_FORMAT_SMPTE_30
Definition: mmsystem.h:707
#define DWORD
Definition: nt_native.h:44
LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin)
Definition: mmio.c:835
IMAGE_NT_HEADERS nt
Definition: module.c:50
#define MCI_NOTIFY_ABORTED
Definition: mmsystem.h:727
MCI_MIDITRACK * tracks
Definition: mcimidi.c:78
const GLfloat * m
Definition: glext.h:10848
static DWORD MIDI_mciPause(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
Definition: mcimidi.c:1196
#define lstrcpynW
Definition: compat.h:397
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
_In_ DWORD _In_ DWORD dwOffset
Definition: ntgdi.h:2032
#define DRV_QUERYCONFIGURE
Definition: mmsystem.h:126
#define DRV_OPEN
Definition: mmsystem.h:121
#define MCI_STOP
Definition: mmsystem.h:651
UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg)
Definition: winmm.c:1042
static DWORD MIDI_mciGetDevCaps(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_GETDEVCAPS_PARMS lpParms)
Definition: mcimidi.c:1435
int WINAPI MessageBoxA(_In_opt_ HWND, _In_opt_ LPCSTR, _In_opt_ LPCSTR, _In_ UINT)
DWORD_PTR dwReturn
Definition: mmsystem.h:1567
BOOL WINAPI GetExitCodeThread(IN HANDLE hThread, OUT LPDWORD lpExitCode)
Definition: thread.c:503
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
BOOL WINAPI mciDriverNotify(HWND hwndCallback, UINT uDeviceID, UINT uStatus)
Definition: mci.c:2056
#define MCI_SEQ_NONE
Definition: mmsystem.h:850
HMIDIOUT * LPHMIDIOUT
Definition: mmsystem.h:1101
#define MCI_GETDEVCAPS_USES_FILES
Definition: mmsystem.h:763
#define MCI_SET
Definition: mmsystem.h:656
#define MMSYSERR_NOMEM
Definition: mmsystem.h:103
#define MCI_SEQ_STATUS_MASTER
Definition: mmsystem.h:855
DWORD dwFirst
Definition: mcimidi.c:48
LPCWSTR lpstrElementName
Definition: mmsystem.h:1532
static DWORD MIDI_mciReadWord(WINE_MCIMIDI *wmm, LPWORD lpw)
Definition: mcimidi.c:193
#define MCIERR_FLAGS_NOT_COMPATIBLE
Definition: mmsystem.h:593
static WORD MIDI_mciReadVaryLen(WINE_MCIMIDI *wmm, LPDWORD lpdw)
Definition: mcimidi.c:225
#define MCI_FORMAT_MILLISECONDS
Definition: mmsystem.h:701
static DWORD MIDI_GetMThdLengthMS(WINE_MCIMIDI *wmm)
Definition: mcimidi.c:639
WORD wLastCommand
Definition: mcimidi.c:55
static DWORD mmr2mci(DWORD ret)
Definition: mcimidi.c:89
UINT wCustomCommandTable
Definition: mmddk.h:438
static DWORD MIDI_player(WINE_MCIMIDI *wmm, DWORD dwFlags)
Definition: mcimidi.c:857
#define debugstr_w
Definition: kernel32.h:32
#define MCI_MODE_PLAY
Definition: mmsystem.h:696
#define FIXME(fmt,...)
Definition: debug.h:110
static PVOID ptr
Definition: dispmode.c:27
#define MCIERR_SEQ_PORT_MAPNODEVICE
Definition: mmsystem.h:634
static CRYPT_DATA_BLOB b1[]
Definition: msg.c:573
unsigned int idx
Definition: utils.c:41
static DWORD MIDI_mciClose(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
Definition: mcimidi.c:794
#define MCI_GETDEVCAPS_DEVICE_TYPE
Definition: mmsystem.h:762
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
static DWORD MIDI_mciReadNextEvent(WINE_MCIMIDI *wmm, MCI_MIDITRACK *mmt)
Definition: mcimidi.c:245
DWORD dwEndMS
Definition: mcimidi.c:81
const WCHAR * str
#define MAKELONG(a, b)
Definition: typedefs.h:248
#define MCI_SEQ_SET_TEMPO
Definition: mmsystem.h:860
#define MCI_INFO_FILE
Definition: mmsystem.h:753
const GLfloat * tc
Definition: glext.h:8925
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:112
static DWORD MIDI_mciReadMThd(WINE_MCIMIDI *wmm, DWORD dwOffset)
Definition: mcimidi.c:403
#define MCI_SEQ_NONE_S
Definition: mmddk.h:366
DWORD dwPositionMS
Definition: mcimidi.c:80
smooth NULL
Definition: ftsmooth.c:416
#define MCI_SEQ_STATUS_PORT
Definition: mmsystem.h:853
unsigned char
Definition: typeof.h:29
DWORD dwEventData
Definition: mcimidi.c:53
HMIDI hMidi
Definition: mcimidi.c:62
LONG_PTR LPARAM
Definition: windef.h:208
#define DRV_LOAD(x)
DWORD_PTR dwCallback
Definition: mmsystem.h:1579
#define MMIO_FINDCHUNK
Definition: mmsystem.h:551
#define MCI_OPEN
Definition: mmsystem.h:646
#define MCI_SEQ_SET_PORT
Definition: mmsystem.h:861
#define TIME_MS_IN_ONE_SECOND
Definition: mcimidi.c:551
FOURCC fccType
Definition: mmsystem.h:1509
static DWORD MIDI_mciPlay(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
Definition: mcimidi.c:1137
#define MCIERR_MISSING_PARAMETER
Definition: mmsystem.h:583
#define DRVCNF_RESTART
Definition: mmsystem.h:135
#define DRV_REMOVE
Definition: mmsystem.h:128
#define MCI_INFO
Definition: mmsystem.h:653
#define MCI_NOTIFY_FAILURE
Definition: mmsystem.h:728
BOOL WINAPI SetThreadPriority(IN HANDLE hThread, IN int nPriority)
Definition: thread.c:662
#define MCI_GETDEVCAPS_HAS_VIDEO
Definition: mmsystem.h:761
GLuint GLfloat * val
Definition: glext.h:7180
#define MCI_OPEN_DRIVER
Definition: mmddk.h:334
UINT WINAPI midiOutReset(HMIDIOUT hMidiOut)
Definition: winmm.c:1073
#define MMIO_READ
Definition: mmsystem.h:535
#define MCIERR_PARAM_OVERFLOW
Definition: mmsystem.h:578
#define MCI_STATUS
Definition: mmsystem.h:662
WORD nTracks
Definition: mcimidi.c:74
static DWORD ensurePlayerThread(WINE_MCIMIDI *wmm)
Definition: mcimidi.c:1099
#define MCIERR_OUT_OF_MEMORY
Definition: mmsystem.h:574
WORD wFormat
Definition: mcimidi.c:73
#define SEEK_SET
Definition: jmemansi.c:26
#define MCI_SEQ_SET_SLAVE
Definition: mmsystem.h:862
GLfloat f
Definition: glext.h:7540
#define TRACE(s)
Definition: solgame.cpp:4
#define InterlockedExchangePointer(Target, Value)
Definition: dshow.h:45
#define MCI_SET_ON
Definition: mmsystem.h:777
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define GetProcessHeap()
Definition: compat.h:395
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
static DWORD MIDI_mciSeek(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
Definition: mcimidi.c:1545
#define MCI_STATUS_LENGTH
Definition: mmsystem.h:744
#define DRV_CONFIGURE
Definition: mmsystem.h:125
#define MCIERR_BAD_INTEGER
Definition: mmsystem.h:580
__wchar_t WCHAR
Definition: xmlstorage.h:180
static DWORD MIDI_mciStatus(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
Definition: mcimidi.c:1316
#define MCI_OPEN_SHAREABLE
Definition: mmsystem.h:734
#define MCI_SET_TIME_FORMAT
Definition: mmsystem.h:774
#define MMSYSERR_ALLOCATED
Definition: mmsystem.h:100
UINT WINAPI midiOutClose(HMIDIOUT hMidiOut)
Definition: winmm.c:981
#define MCI_SET_AUDIO_LEFT
Definition: mmsystem.h:780
#define MCIERR_BAD_TIME_FORMAT
Definition: mmsystem.h:601
DWORD dwEventPulse
Definition: mcimidi.c:52
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint num
Definition: glext.h:9618
#define MCI_FORMAT_SMPTE_24
Definition: mmsystem.h:705
DWORD_PTR dwCallback
Definition: mmsystem.h:1529
LPWSTR lpstrCopyright
Definition: mcimidi.c:68
#define DRV_FREE
Definition: mmsystem.h:124
DWORD cksize
Definition: mmsystem.h:1508
#define MCI_STATUS_MODE
Definition: mmsystem.h:747
LPWSTR lpstrName
Definition: mcimidi.c:69
#define MCI_STATUS_START
Definition: mmsystem.h:743
DWORD_PTR dwCallback
Definition: mmsystem.h:1543
#define MIDIERR_INVALIDSETUP
Definition: mmsystem.h:236
#define MCI_NOTIFY_SUCCESSFUL
Definition: mmsystem.h:725
WORD nDivision
Definition: mcimidi.c:75
#define THREAD_PRIORITY_TIME_CRITICAL
Definition: winbase.h:278
static double zero
Definition: j0_y0.c:96
int ret
#define MCI_SET_AUDIO_RIGHT
Definition: mmsystem.h:781
char * HPSTR
Definition: mmsystem.h:1477
#define MCI_SEQ_STATUS_DIVTYPE
Definition: mmsystem.h:857
static const WCHAR L[]
Definition: oid.c:1250
#define FOURCC_RIFF
Definition: mmsystem.h:564
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
#define mmioFOURCC(c0, c1, c2, c3)
Definition: mmsystem.h:38
#define MCI_GETDEVCAPS_HAS_AUDIO
Definition: mmsystem.h:760
#define MCIERR_INTERNAL
Definition: mmsystem.h:587
#define MCI_STATUS_CURRENT_TRACK
Definition: mmsystem.h:751
#define MCI_SEQ_SET_MASTER
Definition: mmsystem.h:863
GLenum GLsizei len
Definition: glext.h:6722
unsigned char BYTE
Definition: mem.h:68
static DWORD MIDI_mciResume(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
Definition: mcimidi.c:1215
#define MCI_SEEK_TO_END
Definition: mmsystem.h:741
GLdouble s
Definition: gl.h:2039
#define MMSYSERR_BADDEVICEID
Definition: mmsystem.h:98
#define MCIERR_OUTOFRANGE
Definition: mmsystem.h:592
#define MCI_GETDEVCAPS_ITEM
Definition: mmsystem.h:758
#define MCI_FALSE
Definition: mmddk.h:340
uint32_t DWORD_PTR
Definition: typedefs.h:63
GLsizei const GLfloat * value
Definition: glext.h:6069
#define MCI_CLOSE_DRIVER
Definition: mmddk.h:335
#define MCI_SEQ_SET_OFFSET
Definition: mmsystem.h:864
DWORD FOURCC
Definition: dmdls.h:25
#define MCI_SEEK_TO_START
Definition: mmsystem.h:740
#define DRV_ENABLE
Definition: mmsystem.h:120
uint16_t * LPWORD
Definition: typedefs.h:54
DWORD_PTR dwCallback
Definition: mmsystem.h:1566
#define HWND_32(h16)
Definition: wownt32.h:29
#define MCIERR_FILE_NOT_FOUND
Definition: mmsystem.h:585
WINE_UNICODE_INLINE WCHAR * strcpyW(WCHAR *dst, const WCHAR *src)
Definition: unicode.h:219
DWORD dwStatus
Definition: mediaobj.idl:95
#define CALLBACK_NULL
Definition: mmsystem.h:147
#define MCI_INFO_NAME
Definition: mmsystem.h:756
#define MCI_FORMAT_SMPTE_30DROP
Definition: mmsystem.h:708
#define MCI_SEQ_MAPPER_S
Definition: mmddk.h:361
#define MCI_MODE_NOT_READY
Definition: mmsystem.h:694
static CRYPT_DATA_BLOB b3[]
Definition: msg.c:592
DWORD dwIndex
Definition: mcimidi.c:50
#define MCI_SET_VIDEO
Definition: mmsystem.h:776
#define MCI_NOTIFY_SUPERSEDED
Definition: mmsystem.h:726
FOURCC ckid
Definition: mmsystem.h:1507
#define byte(x, n)
Definition: tomcrypt.h:118
#define DRV_MCI_FIRST
Definition: mmsystem.h:139
static void MIDI_mciNotify(DWORD_PTR hWndCallBack, WINE_MCIMIDI *wmm, UINT wStatus)
Definition: mcimidi.c:164
DWORD_PTR dwCallback
Definition: mmsystem.h:1517
MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, const MMCKINFO *lpckParent, UINT uFlags)
Definition: mmio.c:1106
static MCI_MIDITRACK * MIDI_mciFindNextEvent(WINE_MCIMIDI *wmm, LPDWORD hiPulse)
Definition: mcimidi.c:833
#define f
Definition: ke_i.h:83
#define MCI_OPEN_ELEMENT
Definition: mmsystem.h:735
#define MCI_SEQ_STATUS_OFFSET
Definition: mmsystem.h:856
HMMIO hFile
Definition: mcimidi.c:66
unsigned short UINT16
unsigned int UINT
Definition: ndis.h:50
WORD wTrackNr
Definition: mcimidi.c:55
#define MB_OK
Definition: winuser.h:784
#define MCI_SEQ_FILE
Definition: mmsystem.h:847
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
#define MCI_CLOSE
Definition: mmsystem.h:647
#define MCI_SEQ_DIV_SMPTE_30
Definition: mmsystem.h:845
#define MCI_GETDEVCAPS
Definition: mmsystem.h:654
#define MCI_TRACK
Definition: mmsystem.h:733
#define MCI_TRUE
Definition: mmddk.h:341
#define MultiByteToWideChar
Definition: compat.h:100
UINT MCIDEVICEID
Definition: mmsystem.h:959
#define MCI_SEQ_DIV_SMPTE_25
Definition: mmsystem.h:843
#define MCIERR_UNRECOGNIZED_COMMAND
Definition: mmsystem.h:571
#define HRESULT_CODE(hr)
Definition: winerror.h:76
#define MCIERR_HARDWARE
Definition: mmsystem.h:572
#define MCI_INFO_COPYRIGHT
Definition: mmsystem.h:757
WORD dwStatus
Definition: mcimidi.c:71
uint32_t * LPDWORD
Definition: typedefs.h:57
#define MCI_GETDEVCAPS_CAN_EJECT
Definition: mmsystem.h:765
LPWSTR lpstrElementName
Definition: mcimidi.c:67
#define MCI_MODE_PAUSE
Definition: mmsystem.h:699
#define MCI_PAUSE
Definition: mmsystem.h:652
#define MCI_FROM
Definition: mmsystem.h:731
#define HIWORD(l)
Definition: typedefs.h:246
WORD wStartedPlaying
Definition: mcimidi.c:76
#define MCIERR_DEVICE_OPEN
Definition: mmsystem.h:575
struct tagWINE_MCIMIDI WINE_MCIMIDI
#define MCI_DEVTYPE_SEQUENCER
Definition: mmsystem.h:690
#define DRV_INSTALL
Definition: mmsystem.h:127
LRESULT WINAPI DefDriverProc(DWORD_PTR dwDriverIdentifier, HDRVR hDrv, UINT Msg, LPARAM lParam1, LPARAM lParam2)
Definition: driver.c:554
static CRYPT_DATA_BLOB b2[]
Definition: msg.c:582
WINE_DEFAULT_DEBUG_CHANNEL(mcimidi)
#define MCI_SEQ_STATUS_SLAVE
Definition: mmsystem.h:854
#define MCI_SEQ_FILE_S
Definition: mmddk.h:362
DWORD dwMciTimeFormat
Definition: mcimidi.c:72
static DWORD MIDI_mciSet(WINE_MCIMIDI *wmm, DWORD dwFlags, LPMCI_SEQ_SET_PARMS lpParms)
Definition: mcimidi.c:1231
MCIDEVICEID wDeviceID
Definition: mmsystem.h:1530
static DWORD MIDI_mciReadByte(WINE_MCIMIDI *wmm, BYTE *lpbyt)
Definition: mcimidi.c:178
#define MCIERR_INVALID_DEVICE_ID
Definition: mmsystem.h:569
#define MCI_SET_AUDIO_ALL
Definition: mmsystem.h:779
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define MCI_STATUS_TIME_FORMAT
Definition: mmsystem.h:749
LONG_PTR LRESULT
Definition: windef.h:209
#define MCI_NOTIFY
Definition: mmsystem.h:729
#define INFINITE
Definition: serial.h:102
DWORD dwStartTicks
Definition: mcimidi.c:82
#define MCI_STATUS_MEDIA_PRESENT
Definition: mmsystem.h:748
#define MCIERR_SEQ_PORT_NONEXISTENT
Definition: mmsystem.h:633
#define MCIERR_NULL_PARAMETER_BLOCK
Definition: mmsystem.h:605
#define TRACE_ON(x)
Definition: compat.h:65
#define LOWORD(l)
Definition: pedump.c:82
UINT WINAPI midiOutGetNumDevs(void)
Definition: winmm.c:809
static DWORD MIDI_ConvertTimeFormatToMS(WINE_MCIMIDI *wmm, DWORD val)
Definition: mcimidi.c:556
#define HeapFree(x, y, z)
Definition: compat.h:394
#define MCI_SEEK
Definition: mmsystem.h:650
static DWORD MIDI_mciReadLong(WINE_MCIMIDI *wmm, LPDWORD lpdw)
Definition: mcimidi.c:209
HANDLE hCallback
Definition: mcimidi.c:64
#define MCI_TO
Definition: mmsystem.h:732
HANDLE hThread
Definition: mcimidi.c:65
static DWORD MIDI_ConvertMSToTimeFormat(WINE_MCIMIDI *wmm, DWORD _val)
Definition: mcimidi.c:591
LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch)
Definition: mmio.c:732
#define MCI_SET_DOOR_OPEN
Definition: mmsystem.h:772
#define MCIERR_SEQ_PORT_INUSE
Definition: mmsystem.h:632
#define MCI_FORMAT_RETURN_BASE
Definition: mmddk.h:343
DWORD dwTempo
Definition: mcimidi.c:77
#define MCI_STATUS_READY
Definition: mmsystem.h:750
#define MCI_GETDEVCAPS_CAN_PLAY
Definition: mmsystem.h:766