wineoss: Handle MIDI running status.
[wine.git] / dlls / wineoss.drv / ossmidi.c
blob1fd9cc216a147dfead3a5c15aaa56b8518647c91
1 /*
2 * MIDI driver for OSS (unixlib)
4 * Copyright 1994 Martin Ayotte
5 * Copyright 1998 Luiz Otavio L. Zorzella (init procedures)
6 * Copyright 1998, 1999 Eric POUECH
7 * Copyright 2022 Huw Davies
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #if 0
25 #pragma makedep unix
26 #endif
28 #include "config.h"
30 #include <stdarg.h>
31 #include <string.h>
32 #include <stdio.h>
33 #include <stdint.h>
34 #include <time.h>
35 #include <unistd.h>
36 #include <poll.h>
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <sys/ioctl.h>
42 #include <sys/soundcard.h>
43 #include <pthread.h>
45 #include "ntstatus.h"
46 #define WIN32_NO_STATUS
47 #include "winternl.h"
48 #include "audioclient.h"
49 #include "mmddk.h"
51 #include "wine/debug.h"
52 #include "wine/unixlib.h"
54 #include "unixlib.h"
56 struct midi_dest
58 BOOL bEnabled;
59 MIDIOPENDESC midiDesc;
60 BYTE runningStatus;
61 WORD wFlags;
62 MIDIHDR *lpQueueHdr;
63 void *lpExtra; /* according to port type (MIDI, FM...), extra data when needed */
64 MIDIOUTCAPSW caps;
65 int fd;
68 struct midi_src
70 int state; /* -1 disabled, 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */
71 MIDIOPENDESC midiDesc;
72 WORD wFlags;
73 MIDIHDR *lpQueueHdr;
74 unsigned char incoming[3];
75 unsigned char incPrev;
76 char incLen;
77 UINT startTime;
78 MIDIINCAPSW caps;
79 int fd;
82 static pthread_mutex_t in_buffer_mutex = PTHREAD_MUTEX_INITIALIZER;
84 static unsigned int num_dests, num_srcs, num_synths, seq_refs;
85 static struct midi_dest dests[MAX_MIDIOUTDRV];
86 static struct midi_src srcs[MAX_MIDIINDRV];
87 static int load_count;
89 static unsigned int num_midi_in_started;
90 static int rec_cancel_pipe[2];
91 static pthread_t rec_thread_id;
93 static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
94 static pthread_cond_t notify_read_cond = PTHREAD_COND_INITIALIZER;
95 static pthread_cond_t notify_write_cond = PTHREAD_COND_INITIALIZER;
96 static BOOL notify_quit;
97 #define NOTIFY_BUFFER_SIZE 64 + 1 /* + 1 for the sentinel */
98 static struct notify_context notify_buffer[NOTIFY_BUFFER_SIZE];
99 static struct notify_context *notify_read = notify_buffer, *notify_write = notify_buffer;
101 typedef struct sVoice
103 int note; /* 0 means not used */
104 int channel;
105 unsigned cntMark : 30,
106 status : 2;
107 #define sVS_UNUSED 0
108 #define sVS_PLAYING 1
109 #define sVS_SUSTAINED 2
110 } sVoice;
112 typedef struct sChannel
114 int program;
116 int bender;
117 int benderRange;
118 /* controllers */
119 int bank; /* CTL_BANK_SELECT */
120 int volume; /* CTL_MAIN_VOLUME */
121 int balance; /* CTL_BALANCE */
122 int expression; /* CTL_EXPRESSION */
123 int sustain; /* CTL_SUSTAIN */
125 unsigned char nrgPmtMSB; /* Non register Parameters */
126 unsigned char nrgPmtLSB;
127 unsigned char regPmtMSB; /* Non register Parameters */
128 unsigned char regPmtLSB;
129 } sChannel;
131 typedef struct sFMextra
133 unsigned counter;
134 int drumSetMask;
135 sChannel channel[16]; /* MIDI has only 16 channels */
136 sVoice voice[1]; /* dyn allocated according to sound card */
137 /* do not append fields below voice[1] since the size of this structure
138 * depends on the number of available voices on the FM synth...
140 } sFMextra;
142 #define IS_DRUM_CHANNEL(_xtra, _chn) ((_xtra)->drumSetMask & (1 << (_chn)))
144 WINE_DEFAULT_DEBUG_CHANNEL(midi);
146 static int oss_to_win_device_type(int type)
148 /* MOD_MIDIPORT output port
149 * MOD_SYNTH generic internal synth
150 * MOD_SQSYNTH square wave internal synth
151 * MOD_FMSYNTH FM internal synth
152 * MOD_MAPPER MIDI mapper
153 * MOD_WAVETABLE hardware wavetable internal synth
154 * MOD_SWSYNTH software internal synth
157 /* FIXME Is this really the correct equivalence from UNIX to
158 Windows Sound type */
160 switch (type)
162 case SYNTH_TYPE_FM: return MOD_FMSYNTH;
163 case SYNTH_TYPE_SAMPLE: return MOD_SYNTH;
164 case SYNTH_TYPE_MIDI: return MOD_MIDIPORT;
165 default:
166 ERR("Cannot determine the type of this midi device. "
167 "Assuming FM Synth\n");
168 return MOD_FMSYNTH;
172 static void in_buffer_lock(void)
174 pthread_mutex_lock(&in_buffer_mutex);
177 static void in_buffer_unlock(void)
179 pthread_mutex_unlock(&in_buffer_mutex);
182 static uint64_t get_time_msec(void)
184 struct timespec now = {0, 0};
186 #ifdef CLOCK_MONOTONIC_RAW
187 if (!clock_gettime(CLOCK_MONOTONIC_RAW, &now))
188 return (uint64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000;
189 #endif
190 clock_gettime(CLOCK_MONOTONIC, &now);
191 return (uint64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000;
195 * notify buffer: The notification ring buffer is implemented so that
196 * there is always at least one unused sentinel before the current
197 * read position in order to allow detection of the full vs empty
198 * state.
200 static struct notify_context *notify_buffer_next(struct notify_context *notify)
202 if (++notify >= notify_buffer + ARRAY_SIZE(notify_buffer))
203 notify = notify_buffer;
205 return notify;
208 static BOOL notify_buffer_empty(void)
210 return notify_read == notify_write;
213 static BOOL notify_buffer_full(void)
215 return notify_buffer_next(notify_write) == notify_read;
218 static BOOL notify_buffer_add(struct notify_context *notify)
220 if (notify_buffer_full()) return FALSE;
222 *notify_write = *notify;
223 notify_write = notify_buffer_next(notify_write);
224 return TRUE;
227 static BOOL notify_buffer_remove(struct notify_context *notify)
229 if (notify_buffer_empty()) return FALSE;
231 *notify = *notify_read;
232 notify_read = notify_buffer_next(notify_read);
233 return TRUE;
236 static void notify_post(struct notify_context *notify)
238 pthread_mutex_lock(&notify_mutex);
240 if (notify)
242 while (notify_buffer_full())
243 pthread_cond_wait(&notify_write_cond, &notify_mutex);
245 notify_buffer_add(notify);
247 else notify_quit = TRUE;
248 pthread_cond_signal(&notify_read_cond);
250 pthread_mutex_unlock(&notify_mutex);
253 static void set_in_notify(struct notify_context *notify, struct midi_src *src, WORD dev_id, WORD msg,
254 UINT_PTR param_1, UINT_PTR param_2)
256 notify->send_notify = TRUE;
257 notify->dev_id = dev_id;
258 notify->msg = msg;
259 notify->param_1 = param_1;
260 notify->param_2 = param_2;
261 notify->callback = src->midiDesc.dwCallback;
262 notify->flags = src->wFlags;
263 notify->device = src->midiDesc.hMidi;
264 notify->instance = src->midiDesc.dwInstance;
267 static int seq_open(void)
269 static int midi_warn = 1;
270 static int fd = -1;
272 if (seq_refs <= 0)
274 const char* device = getenv("MIDIDEV");
276 if (!device) device = "/dev/sequencer";
277 fd = open(device, O_RDWR, 0);
278 if (fd == -1)
280 if (midi_warn)
282 WARN("Can't open MIDI device '%s' ! (%s). If your program needs this (probably not): %s\n",
283 device, strerror(errno),
284 errno == ENOENT ? "create it ! (\"man MAKEDEV\" ?)" :
285 errno == ENODEV ? "load MIDI sequencer kernel driver !" :
286 errno == EACCES ? "grant access ! (\"man chmod\")" : "");
288 midi_warn = 0;
289 return -1;
291 fcntl(fd, F_SETFD, 1); /* set close on exec flag */
292 ioctl(fd, SNDCTL_SEQ_RESET);
294 seq_refs++;
295 return fd;
298 static int seq_close(int fd)
300 if (--seq_refs == 0)
301 close(fd);
303 return 0;
306 static UINT midi_init(void)
308 int i, status, synth_devs = 255, midi_devs = 255, fd, len;
309 struct synth_info sinfo;
310 struct midi_info minfo;
311 struct midi_dest *dest;
312 struct midi_src *src;
314 TRACE("(%i)\n", load_count);
316 if (load_count++)
317 return 1;
319 /* try to open device */
320 fd = seq_open();
321 if (fd == -1)
322 return -1;
324 /* find how many Synth devices are there in the system */
325 status = ioctl(fd, SNDCTL_SEQ_NRSYNTHS, &synth_devs);
326 if (status == -1)
328 ERR("ioctl for nr synth failed.\n");
329 seq_close(fd);
330 return -1;
333 if (synth_devs > MAX_MIDIOUTDRV)
335 ERR("MAX_MIDIOUTDRV (%d) was enough for the number of devices (%d). "
336 "Some FM devices will not be available.\n", MAX_MIDIOUTDRV, synth_devs);
337 synth_devs = MAX_MIDIOUTDRV;
340 for (i = 0, dest = dests; i < synth_devs; i++, dest++)
342 /* Manufac ID. We do not have access to this with soundcard.h
343 * Does not seem to be a problem, because in mmsystem.h only
344 * Microsoft's ID is listed.
346 dest->caps.wMid = 0x00FF;
347 dest->caps.wPid = 0x0001; /* FIXME Product ID */
348 /* Product Version. We simply say "1" */
349 dest->caps.vDriverVersion = 0x001;
350 /* The following are mandatory for MOD_MIDIPORT */
351 dest->caps.wChannelMask = 0xFFFF;
352 dest->caps.wVoices = 0;
353 dest->caps.wNotes = 0;
354 dest->caps.dwSupport = 0;
356 sinfo.device = i;
357 status = ioctl(fd, SNDCTL_SYNTH_INFO, &sinfo);
358 if (status == -1)
360 char buf[255];
362 ERR("ioctl for synth info failed on %d, disabling it.\n", i);
364 sprintf(buf, "Wine OSS Midi Out #%d disabled", i);
365 len = ntdll_umbstowcs(buf, strlen(buf) + 1, dest->caps.szPname, ARRAY_SIZE(dest->caps.szPname));
366 dest->caps.szPname[len - 1] = '\0';
367 dest->caps.wTechnology = MOD_MIDIPORT;
368 dest->bEnabled = FALSE;
370 else
372 len = ntdll_umbstowcs(sinfo.name, strlen(sinfo.name) + 1, dest->caps.szPname, ARRAY_SIZE(dest->caps.szPname));
373 dest->caps.szPname[len - 1] = '\0';
374 dest->caps.wTechnology = oss_to_win_device_type(sinfo.synth_type);
376 if (dest->caps.wTechnology != MOD_MIDIPORT)
378 /* FIXME Do we have this information?
379 * Assuming the soundcards can handle
380 * MIDICAPS_VOLUME and MIDICAPS_LRVOLUME but
381 * not MIDICAPS_CACHE.
383 dest->caps.dwSupport = MIDICAPS_VOLUME | MIDICAPS_LRVOLUME;
384 dest->caps.wVoices = sinfo.nr_voices;
386 /* FIXME Is it possible to know the maximum
387 * number of simultaneous notes of a soundcard ?
388 * I believe we don't have this information, but
389 * it's probably equal or more than wVoices
391 dest->caps.wNotes = sinfo.nr_voices;
393 dest->bEnabled = TRUE;
395 /* We also have the information sinfo.synth_subtype, not used here
397 if (sinfo.capabilities & SYNTH_CAP_INPUT)
398 FIXME("Synthesizer supports MIDI in. Not yet supported.\n");
400 TRACE("SynthOut[%d]\tOSS info: synth type=%d/%d capa=%x\n",
401 i, sinfo.synth_type, sinfo.synth_subtype, (unsigned)sinfo.capabilities);
404 TRACE("SynthOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%d\n",
405 i, wine_dbgstr_w(dest->caps.szPname), dest->caps.wTechnology,
406 dest->caps.wVoices, dest->caps.wNotes, dest->caps.wChannelMask,
407 (unsigned)dest->caps.dwSupport);
410 /* find how many MIDI devices are there in the system */
411 status = ioctl(fd, SNDCTL_SEQ_NRMIDIS, &midi_devs);
412 if (status == -1)
414 ERR("ioctl on nr midi failed.\n");
415 midi_devs = 0;
416 goto wrapup;
419 /* FIXME: the two restrictions below could be loosened in some cases */
420 if (synth_devs + midi_devs > MAX_MIDIOUTDRV)
422 ERR("MAX_MIDIOUTDRV was not enough for the number of devices. "
423 "Some MIDI devices will not be available.\n");
424 midi_devs = MAX_MIDIOUTDRV - synth_devs;
427 if (midi_devs > MAX_MIDIINDRV)
429 ERR("MAX_MIDIINDRV (%d) was not enough for the number of devices (%d). "
430 "Some MIDI devices will not be available.\n", MAX_MIDIINDRV, midi_devs);
431 midi_devs = MAX_MIDIINDRV;
434 dest = dests + synth_devs;
435 src = srcs;
436 for (i = 0; i < midi_devs; i++, dest++, src++)
438 minfo.device = i;
439 status = ioctl(fd, SNDCTL_MIDI_INFO, &minfo);
440 if (status == -1) WARN("ioctl on midi info for device %d failed.\n", i);
442 /* Manufacturer ID. We do not have access to this with soundcard.h
443 Does not seem to be a problem, because in mmsystem.h only Microsoft's ID is listed
445 dest->caps.wMid = 0x00FF;
446 dest->caps.wPid = 0x0001; /* FIXME Product ID */
447 /* Product Version. We simply say "1" */
448 dest->caps.vDriverVersion = 0x001;
449 if (status == -1)
451 char buf[255];
453 sprintf(buf, "Wine OSS Midi Out #%d disabled", synth_devs + i);
454 len = ntdll_umbstowcs(buf, strlen(buf) + 1, dest->caps.szPname, ARRAY_SIZE(dest->caps.szPname));
455 dest->caps.szPname[len - 1] = '\0';
456 dest->bEnabled = FALSE;
458 else
460 len = ntdll_umbstowcs(minfo.name, strlen(minfo.name) + 1, dest->caps.szPname, ARRAY_SIZE(dest->caps.szPname));
461 dest->caps.szPname[len - 1] = '\0';
462 dest->bEnabled = TRUE;
464 dest->caps.wTechnology = MOD_MIDIPORT;
465 dest->caps.wVoices = 0;
466 dest->caps.wNotes = 0;
467 dest->caps.wChannelMask = 0xFFFF;
468 dest->caps.dwSupport = 0;
470 /* Manufac ID. We do not have access to this with soundcard.h
471 Does not seem to be a problem, because in mmsystem.h only
472 Microsoft's ID is listed */
473 src->caps.wMid = 0x00FF;
474 src->caps.wPid = 0x0001; /* FIXME Product ID */
475 /* Product Version. We simply say "1" */
476 src->caps.vDriverVersion = 0x001;
477 if (status == -1)
479 char buf[ARRAY_SIZE(dest->caps.szPname)];
481 sprintf(buf, "Wine OSS Midi In #%d disabled", synth_devs + i);
482 len = ntdll_umbstowcs(buf, strlen(buf) + 1, src->caps.szPname, ARRAY_SIZE(src->caps.szPname));
483 src->caps.szPname[len - 1] = '\0';
484 src->state = -1;
486 else
488 len = ntdll_umbstowcs(minfo.name, strlen(minfo.name) + 1, src->caps.szPname, ARRAY_SIZE(src->caps.szPname));
489 src->caps.szPname[len - 1] = '\0';
490 src->state = 0;
492 src->caps.dwSupport = 0; /* mandatory with MIDIINCAPS */
494 TRACE("OSS info: midi[%d] dev-type=%d capa=%x\n"
495 "\tMidiOut[%d] name='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%d\n"
496 "\tMidiIn [%d] name='%s' support=%d\n",
497 i, minfo.dev_type, (unsigned)minfo.capabilities,
498 synth_devs + i, wine_dbgstr_w(dest->caps.szPname), dest->caps.wTechnology,
499 dest->caps.wVoices, dest->caps.wNotes, dest->caps.wChannelMask, (unsigned)dest->caps.dwSupport,
500 i, wine_dbgstr_w(src->caps.szPname), (unsigned)src->caps.dwSupport);
503 wrapup:
504 /* windows does not seem to differentiate Synth from MIDI devices */
505 num_synths = synth_devs;
506 num_dests = synth_devs + midi_devs;
507 num_srcs = midi_devs;
509 /* close file and exit */
510 seq_close(fd);
512 return 0;
515 static UINT midi_exit(void)
517 TRACE("(%i)\n", load_count);
519 if (--load_count)
520 return 1;
522 return 0;
525 NTSTATUS midi_release(void *args)
527 /* stop the notify_wait thread */
528 notify_post(NULL);
530 return STATUS_SUCCESS;
533 /* FIXME: this is a bad idea, it's even not static... */
534 SEQ_DEFINEBUF(1024);
536 /* FIXME: this is not reentrant, not static - because of global variable
537 * _seqbuf and al.
539 /**************************************************************************
540 * seqbuf_dump [internal]
542 * Used by SEQ_DUMPBUF to flush the buffer.
545 void seqbuf_dump(void)
547 int fd;
549 /* The device is already open, but there's no way to pass the
550 fd to this function. Rather than rely on a global variable
551 we pretend to open the seq again. */
552 fd = seq_open();
553 if (_seqbufptr)
555 if (write(fd, _seqbuf, _seqbufptr) == -1)
557 WARN("Can't write data to sequencer %d, errno %d (%s)!\n",
558 fd, errno, strerror(errno));
560 /* FIXME: In any case buffer is lost so that if many errors occur the buffer
561 * will not overrun */
562 _seqbufptr = 0;
564 seq_close(fd);
567 extern const unsigned char midiFMInstrumentPatches[16 * 128];
568 extern const unsigned char midiFMDrumsPatches[16 * 128];
570 static int midi_out_fm_load(WORD dev_id, int fd)
572 struct sbi_instrument sbi;
573 int i;
575 sbi.device = dev_id;
576 sbi.key = FM_PATCH;
578 memset(sbi.operators + 16, 0, 16);
579 for (i = 0; i < 128; i++)
581 sbi.channel = i;
582 memcpy(sbi.operators, midiFMInstrumentPatches + i * 16, 16);
584 if (write(fd, &sbi, sizeof(sbi)) == -1)
586 WARN("Couldn't write patch for instrument %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno));
587 return -1;
590 for (i = 0; i < 128; i++)
592 sbi.channel = 128 + i;
593 memcpy(sbi.operators, midiFMDrumsPatches + i * 16, 16);
595 if (write(fd, &sbi, sizeof(sbi)) == -1)
597 WARN("Couldn't write patch for drum %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno));
598 return -1;
601 return 0;
604 static void midi_out_fm_reset(WORD dev_id)
606 struct midi_dest *dest = dests + dev_id;
607 sFMextra *extra = dest->lpExtra;
608 sVoice *voice = extra->voice;
609 sChannel *channel = extra->channel;
610 int i;
612 for (i = 0; i < dest->caps.wVoices; i++)
614 if (voice[i].status != sVS_UNUSED)
615 SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64);
616 SEQ_KEY_PRESSURE(dev_id, i, 127, 0);
617 SEQ_CONTROL(dev_id, i, SEQ_VOLMODE, VOL_METHOD_LINEAR);
618 voice[i].note = 0;
619 voice[i].channel = -1;
620 voice[i].cntMark = 0;
621 voice[i].status = sVS_UNUSED;
623 for (i = 0; i < 16; i++)
625 channel[i].program = 0;
626 channel[i].bender = 8192;
627 channel[i].benderRange = 2;
628 channel[i].bank = 0;
629 channel[i].volume = 127;
630 channel[i].balance = 64;
631 channel[i].expression = 0;
632 channel[i].sustain = 0;
634 extra->counter = 0;
635 extra->drumSetMask = 1 << 9; /* channel 10 is normally drums, sometimes 16 also */
636 SEQ_DUMPBUF();
639 static void set_out_notify(struct notify_context *notify, struct midi_dest *dest, WORD dev_id, WORD msg,
640 UINT_PTR param_1, UINT_PTR param_2)
642 notify->send_notify = TRUE;
643 notify->dev_id = dev_id;
644 notify->msg = msg;
645 notify->param_1 = param_1;
646 notify->param_2 = param_2;
647 notify->callback = dest->midiDesc.dwCallback;
648 notify->flags = dest->wFlags;
649 notify->device = dest->midiDesc.hMidi;
650 notify->instance = dest->midiDesc.dwInstance;
653 static UINT midi_out_open(WORD dev_id, MIDIOPENDESC *midi_desc, UINT flags, struct notify_context *notify)
655 struct midi_dest *dest;
656 int fd = -1;
658 TRACE("(%04X, %p, %08X);\n", dev_id, midi_desc, flags);
659 if (midi_desc == NULL)
661 WARN("Invalid Parameter !\n");
662 return MMSYSERR_INVALPARAM;
664 if (dev_id >= num_dests)
666 TRACE("MAX_MIDIOUTDRV reached !\n");
667 return MMSYSERR_BADDEVICEID;
669 dest = dests + dev_id;
670 if (dest->midiDesc.hMidi != 0)
672 WARN("device already open !\n");
673 return MMSYSERR_ALLOCATED;
675 if (!dest->bEnabled)
677 WARN("device disabled !\n");
678 return MIDIERR_NODEVICE;
680 if ((flags & ~CALLBACK_TYPEMASK) != 0)
682 WARN("bad flags\n");
683 return MMSYSERR_INVALFLAG;
686 dest->lpExtra = NULL;
688 switch (dest->caps.wTechnology)
690 case MOD_FMSYNTH:
692 void *extra;
694 extra = malloc(offsetof(struct sFMextra, voice[dest->caps.wVoices]));
695 if (!extra)
697 WARN("can't alloc extra data !\n");
698 return MMSYSERR_NOMEM;
700 dest->lpExtra = extra;
701 fd = seq_open();
702 if (fd < 0)
704 dest->lpExtra = NULL;
705 free(extra);
706 return MMSYSERR_ERROR;
708 if (midi_out_fm_load(dev_id, fd) < 0)
710 seq_close(fd);
711 dest->lpExtra = NULL;
712 free(extra);
713 return MMSYSERR_ERROR;
715 midi_out_fm_reset(dev_id);
716 break;
718 case MOD_MIDIPORT:
719 case MOD_SYNTH:
720 fd = seq_open();
721 if (fd < 0)
722 return MMSYSERR_ALLOCATED;
723 break;
724 default:
725 WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology);
726 return MMSYSERR_NOTENABLED;
729 dest->runningStatus = 0;
730 dest->wFlags = HIWORD(flags & CALLBACK_TYPEMASK);
732 dest->lpQueueHdr= NULL;
733 dest->midiDesc = *midi_desc;
734 dest->fd = fd;
736 set_out_notify(notify, dest, dev_id, MOM_OPEN, 0, 0);
737 TRACE("Successful !\n");
738 return MMSYSERR_NOERROR;
741 static UINT midi_out_close(WORD dev_id, struct notify_context *notify)
743 struct midi_dest *dest;
745 TRACE("(%04X);\n", dev_id);
747 if (dev_id >= num_dests)
749 TRACE("MAX_MIDIOUTDRV reached !\n");
750 return MMSYSERR_BADDEVICEID;
752 dest = dests + dev_id;
754 if (dest->midiDesc.hMidi == 0)
756 WARN("device not opened !\n");
757 return MMSYSERR_ERROR;
759 /* FIXME: should test that no pending buffer is still in the queue for
760 * playing */
762 if (dest->fd == -1)
764 WARN("can't close !\n");
765 return MMSYSERR_ERROR;
768 switch (dest->caps.wTechnology)
770 case MOD_FMSYNTH:
771 case MOD_SYNTH:
772 case MOD_MIDIPORT:
773 seq_close(dest->fd);
774 break;
775 default:
776 WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology);
777 return MMSYSERR_NOTENABLED;
780 free(dest->lpExtra);
781 dest->lpExtra = NULL;
782 dest->fd = -1;
784 set_out_notify(notify, dest, dev_id, MOM_CLOSE, 0, 0);
785 dest->midiDesc.hMidi = 0;
786 return MMSYSERR_NOERROR;
789 static UINT midi_out_fm_data(WORD dev_id, UINT data)
791 struct midi_dest *dest = dests + dev_id;
792 BYTE evt = LOBYTE(LOWORD(data)), d1, d2;
793 sFMextra *extra = dest->lpExtra;
794 sVoice *voice = extra->voice;
795 sChannel *channel = extra->channel;
796 int chn = (evt & 0x0F), i, nv;
798 if (evt & 0x80)
800 d1 = HIBYTE(LOWORD(data));
801 d2 = LOBYTE(HIWORD(data));
802 if (evt < 0xF0)
803 dest->runningStatus = evt;
805 else if (dest->runningStatus)
807 evt = dest->runningStatus;
808 d1 = LOBYTE(LOWORD(data));
809 d2 = HIBYTE(LOWORD(data));
811 else
813 FIXME("ooch %x\n", data);
814 return MMSYSERR_NOERROR;
817 /* FIXME: chorus depth controller is not used */
819 switch (evt & 0xF0)
821 case MIDI_NOTEOFF:
822 for (i = 0; i < dest->caps.wVoices; i++)
824 /* don't stop sustained notes */
825 if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1)
827 voice[i].status = sVS_UNUSED;
828 SEQ_STOP_NOTE(dev_id, i, d1, d2);
831 break;
832 case MIDI_NOTEON:
833 if (d2 == 0) /* note off if velocity == 0 */
835 for (i = 0; i < dest->caps.wVoices; i++) /* don't stop sustained notes */
837 if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1)
839 voice[i].status = sVS_UNUSED;
840 SEQ_STOP_NOTE(dev_id, i, d1, 64);
843 break;
845 /* finding out in this order :
846 * - an empty voice
847 * - if replaying the same note on the same channel
848 * - the older voice (LRU)
850 for (i = nv = 0; i < dest->caps.wVoices; i++)
852 if (voice[i].status == sVS_UNUSED || (voice[i].note == d1 && voice[i].channel == chn))
854 nv = i;
855 break;
857 if (voice[i].cntMark < voice[0].cntMark)
858 nv = i;
860 TRACE("playing on voice=%d, pgm=%d, pan=0x%02X, vol=0x%02X, bender=0x%02X, note=0x%02X, vel=0x%02X\n",
861 nv, channel[chn].program, channel[chn].balance, channel[chn].volume, channel[chn].bender, d1, d2);
863 SEQ_SET_PATCH(dev_id, nv, IS_DRUM_CHANNEL(extra, chn) ?
864 (128 + d1) : channel[chn].program);
865 SEQ_BENDER_RANGE(dev_id, nv, channel[chn].benderRange * 100);
866 SEQ_BENDER(dev_id, nv, channel[chn].bender);
867 SEQ_CONTROL(dev_id, nv, CTL_PAN, channel[chn].balance);
868 SEQ_CONTROL(dev_id, nv, CTL_EXPRESSION, channel[chn].expression);
869 SEQ_START_NOTE(dev_id, nv, d1, d2);
870 voice[nv].status = channel[chn].sustain ? sVS_SUSTAINED : sVS_PLAYING;
871 voice[nv].note = d1;
872 voice[nv].channel = chn;
873 voice[nv].cntMark = extra->counter++;
874 break;
875 case MIDI_KEY_PRESSURE:
876 for (i = 0; i < dest->caps.wVoices; i++)
877 if (voice[i].status != sVS_UNUSED && voice[i].channel == chn && voice[i].note == d1)
878 SEQ_KEY_PRESSURE(dev_id, i, d1, d2);
879 break;
880 case MIDI_CTL_CHANGE:
881 switch (d1)
883 case CTL_BANK_SELECT: channel[chn].bank = d2; break;
884 case CTL_MAIN_VOLUME: channel[chn].volume = d2; break;
885 case CTL_PAN: channel[chn].balance = d2; break;
886 case CTL_EXPRESSION: channel[chn].expression = d2; break;
887 case CTL_SUSTAIN: channel[chn].sustain = d2;
888 if (d2)
890 for (i = 0; i < dest->caps.wVoices; i++)
891 if (voice[i].status == sVS_PLAYING && voice[i].channel == chn)
892 voice[i].status = sVS_SUSTAINED;
894 else
896 for (i = 0; i < dest->caps.wVoices; i++)
898 if (voice[i].status == sVS_SUSTAINED && voice[i].channel == chn)
900 voice[i].status = sVS_UNUSED;
901 SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64);
905 break;
906 case CTL_NONREG_PARM_NUM_LSB: channel[chn].nrgPmtLSB = d2; break;
907 case CTL_NONREG_PARM_NUM_MSB: channel[chn].nrgPmtMSB = d2; break;
908 case CTL_REGIST_PARM_NUM_LSB: channel[chn].regPmtLSB = d2; break;
909 case CTL_REGIST_PARM_NUM_MSB: channel[chn].regPmtMSB = d2; break;
910 case CTL_DATA_ENTRY:
911 switch ((channel[chn].regPmtMSB << 8) | channel[chn].regPmtLSB)
913 case 0x0000:
914 if (channel[chn].benderRange != d2)
916 channel[chn].benderRange = d2;
917 for (i = 0; i < dest->caps.wVoices; i++)
918 if (voice[i].channel == chn)
919 SEQ_BENDER_RANGE(dev_id, i, channel[chn].benderRange);
921 break;
923 case 0x7F7F:
924 channel[chn].benderRange = 2;
925 for (i = 0; i < dest->caps.wVoices; i++)
926 if (voice[i].channel == chn)
927 SEQ_BENDER_RANGE(dev_id, i, channel[chn].benderRange);
928 break;
929 default:
930 TRACE("Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n",
931 channel[chn].regPmtMSB, channel[chn].regPmtLSB,
932 channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB, d2);
933 break;
935 break;
937 case 0x78: /* all sounds off */
938 /* FIXME: I don't know if I have to take care of the channel for this control? */
939 for (i = 0; i < dest->caps.wVoices; i++)
941 if (voice[i].status != sVS_UNUSED && voice[i].channel == chn)
943 voice[i].status = sVS_UNUSED;
944 SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64);
947 break;
948 case 0x7B: /* all notes off */
949 /* FIXME: I don't know if I have to take care of the channel for this control? */
950 for (i = 0; i < dest->caps.wVoices; i++)
952 if (voice[i].status == sVS_PLAYING && voice[i].channel == chn)
954 voice[i].status = sVS_UNUSED;
955 SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64);
958 break;
959 default:
960 TRACE("Dropping MIDI control event 0x%02x(%02x) on channel %d\n", d1, d2, chn);
961 break;
963 break;
964 case MIDI_PGM_CHANGE:
965 channel[chn].program = d1;
966 break;
967 case MIDI_CHN_PRESSURE:
968 for (i = 0; i < dest->caps.wVoices; i++)
969 if (voice[i].status != sVS_UNUSED && voice[i].channel == chn)
970 SEQ_KEY_PRESSURE(dev_id, i, voice[i].note, d1);
972 break;
973 case MIDI_PITCH_BEND:
974 channel[chn].bender = (d2 << 7) + d1;
975 for (i = 0; i < dest->caps.wVoices; i++)
976 if (voice[i].channel == chn)
977 SEQ_BENDER(dev_id, i, channel[chn].bender);
978 break;
979 case MIDI_SYSTEM_PREFIX:
980 switch (evt & 0x0F)
982 case 0x0F: /* Reset */
983 midi_out_fm_reset(dev_id);
984 dest->runningStatus = 0;
985 break;
986 default:
987 WARN("Unsupported (yet) system event %02x\n", evt & 0x0F);
989 if (evt <= 0xF7)
990 dest->runningStatus = 0;
991 break;
992 default:
993 WARN("Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0);
994 return MMSYSERR_NOTENABLED;
997 SEQ_DUMPBUF();
998 return MMSYSERR_NOERROR;
1001 static UINT midi_out_port_data(WORD dev_id, UINT data)
1003 struct midi_dest *dest = dests + dev_id;
1004 BYTE evt = LOBYTE(LOWORD(data)), d1, d2;
1005 int dev = dev_id - num_synths;
1007 if (dev < 0)
1009 WARN("Internal error on devID (%u) !\n", dev_id);
1010 return MIDIERR_NODEVICE;
1013 if (evt & 0x80)
1015 d1 = HIBYTE(LOWORD(data));
1016 d2 = LOBYTE(HIWORD(data));
1018 else if (dest->runningStatus)
1020 evt = dest->runningStatus;
1021 d1 = LOBYTE(LOWORD(data));
1022 d2 = HIBYTE(LOWORD(data));
1024 else
1026 FIXME("ooch %x\n", data);
1027 return MMSYSERR_NOERROR;
1030 switch (evt & 0xF0)
1032 case MIDI_NOTEOFF:
1033 case MIDI_NOTEON:
1034 case MIDI_KEY_PRESSURE:
1035 case MIDI_CTL_CHANGE:
1036 case MIDI_PITCH_BEND:
1037 if (LOBYTE(LOWORD(data)) >= 0x80)
1039 SEQ_MIDIOUT(dev, evt);
1040 dest->runningStatus = evt;
1042 SEQ_MIDIOUT(dev, d1);
1043 SEQ_MIDIOUT(dev, d2);
1044 break;
1045 case MIDI_PGM_CHANGE:
1046 case MIDI_CHN_PRESSURE:
1047 if (LOBYTE(LOWORD(data)) >= 0x80)
1049 SEQ_MIDIOUT(dev, evt);
1050 dest->runningStatus = evt;
1052 SEQ_MIDIOUT(dev, d1);
1053 break;
1054 case MIDI_SYSTEM_PREFIX:
1055 switch (evt & 0x0F)
1057 case 0x00: /* System Exclusive, don't do it on MODM_DATA, should require MODM_LONGDATA */
1058 case 0x04: /* Undefined. */
1059 case 0x05: /* Undefined. */
1060 case 0x07: /* End of Exclusive. */
1061 case 0x09: /* Undefined. */
1062 case 0x0D: /* Undefined. */
1063 break;
1064 case 0x06: /* Tune Request */
1065 case 0x08: /* Timing Clock. */
1066 case 0x0A: /* Start. */
1067 case 0x0B: /* Continue */
1068 case 0x0C: /* Stop */
1069 case 0x0E: /* Active Sensing. */
1070 SEQ_MIDIOUT(dev, evt);
1071 break;
1072 case 0x0F: /* Reset */
1073 SEQ_MIDIOUT(dev, MIDI_SYSTEM_PREFIX);
1074 SEQ_MIDIOUT(dev, 0x7e);
1075 SEQ_MIDIOUT(dev, 0x7f);
1076 SEQ_MIDIOUT(dev, 0x09);
1077 SEQ_MIDIOUT(dev, 0x01);
1078 SEQ_MIDIOUT(dev, 0xf7);
1079 dest->runningStatus = 0;
1080 break;
1081 case 0x01: /* MTC Quarter frame */
1082 case 0x03: /* Song Select. */
1083 SEQ_MIDIOUT(dev, evt);
1084 SEQ_MIDIOUT(dev, d1);
1085 break;
1086 case 0x02: /* Song Position Pointer. */
1087 SEQ_MIDIOUT(dev, evt);
1088 SEQ_MIDIOUT(dev, d1);
1089 SEQ_MIDIOUT(dev, d2);
1091 if (evt <= 0xF7) /* System Exclusive, System Common Message */
1092 dest->runningStatus = 0;
1093 break;
1096 SEQ_DUMPBUF();
1097 return MMSYSERR_NOERROR;
1100 static UINT midi_out_data(WORD dev_id, UINT data)
1102 struct midi_dest *dest;
1104 TRACE("(%04X, %08X);\n", dev_id, data);
1106 if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID;
1107 dest = dests + dev_id;
1108 if (!dest->bEnabled) return MIDIERR_NODEVICE;
1110 if (dest->fd == -1)
1112 WARN("can't play !\n");
1113 return MIDIERR_NODEVICE;
1115 switch (dest->caps.wTechnology)
1117 case MOD_FMSYNTH:
1118 return midi_out_fm_data(dev_id, data);
1119 case MOD_MIDIPORT:
1120 return midi_out_port_data(dev_id, data);
1123 WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology);
1124 return MMSYSERR_NOTENABLED;
1127 static UINT midi_out_long_data(WORD dev_id, MIDIHDR *hdr, UINT hdr_size, struct notify_context *notify)
1129 struct midi_dest *dest;
1130 BYTE *data;
1131 unsigned int count;
1133 TRACE("(%04X, %p, %08X);\n", dev_id, hdr, hdr_size);
1135 /* Note: MS doc does not say much about the dwBytesRecorded member of the MIDIHDR structure
1136 * but it seems to be used only for midi input.
1137 * Taking a look at the WAVEHDR structure (which is quite similar) confirms this assumption.
1140 if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID;
1141 dest = dests + dev_id;
1142 if (!dest->bEnabled) return MIDIERR_NODEVICE;
1144 if (dest->fd == -1)
1146 WARN("can't play !\n");
1147 return MIDIERR_NODEVICE;
1150 data = (BYTE *)hdr->lpData;
1152 if (data == NULL)
1153 return MIDIERR_UNPREPARED;
1154 if (!(hdr->dwFlags & MHDR_PREPARED))
1155 return MIDIERR_UNPREPARED;
1156 if (hdr->dwFlags & MHDR_INQUEUE)
1157 return MIDIERR_STILLPLAYING;
1158 hdr->dwFlags &= ~MHDR_DONE;
1159 hdr->dwFlags |= MHDR_INQUEUE;
1161 /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive
1162 * data, or can it also contain raw MIDI data, to be split up and sent to
1163 * modShortData() ?
1164 * If the latter is true, then the following WARNing will fire up
1166 if (data[0] != 0xF0 || data[hdr->dwBufferLength - 1] != 0xF7)
1167 WARN("The allegedly system exclusive buffer is not correct\n\tPlease report with MIDI file\n");
1169 TRACE("dwBufferLength=%u !\n", (unsigned)hdr->dwBufferLength);
1170 TRACE(" %02X %02X %02X ... %02X %02X %02X\n",
1171 data[0], data[1], data[2], data[hdr->dwBufferLength - 3],
1172 data[hdr->dwBufferLength - 2], data[hdr->dwBufferLength - 1]);
1174 switch (dest->caps.wTechnology)
1176 case MOD_FMSYNTH:
1177 /* FIXME: I don't think there is much to do here */
1178 break;
1179 case MOD_MIDIPORT:
1180 if (data[0] != 0xF0)
1182 /* Send end of System Exclusive */
1183 SEQ_MIDIOUT(dev_id - num_synths, 0xF0);
1184 WARN("Adding missing 0xF0 marker at the beginning of system exclusive byte stream\n");
1186 for (count = 0; count < hdr->dwBufferLength; count++)
1187 SEQ_MIDIOUT(dev_id - num_synths, data[count]);
1188 if (data[count - 1] != 0xF7)
1190 /* Send end of System Exclusive */
1191 SEQ_MIDIOUT(dev_id - num_synths, 0xF7);
1192 WARN("Adding missing 0xF7 marker at the end of system exclusive byte stream\n");
1194 SEQ_DUMPBUF();
1195 break;
1196 default:
1197 WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology);
1198 return MMSYSERR_NOTENABLED;
1201 dest->runningStatus = 0;
1202 hdr->dwFlags &= ~MHDR_INQUEUE;
1203 hdr->dwFlags |= MHDR_DONE;
1204 set_out_notify(notify, dest, dev_id, MOM_DONE, (UINT_PTR)hdr, 0);
1205 return MMSYSERR_NOERROR;
1208 static UINT midi_out_prepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
1210 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1212 if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData)
1213 return MMSYSERR_INVALPARAM;
1214 if (hdr->dwFlags & MHDR_PREPARED)
1215 return MMSYSERR_NOERROR;
1217 hdr->lpNext = 0;
1218 hdr->dwFlags |= MHDR_PREPARED;
1219 hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE);
1220 return MMSYSERR_NOERROR;
1223 static UINT midi_out_unprepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
1225 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1227 if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData)
1228 return MMSYSERR_INVALPARAM;
1229 if (!(hdr->dwFlags & MHDR_PREPARED))
1230 return MMSYSERR_NOERROR;
1231 if (hdr->dwFlags & MHDR_INQUEUE)
1232 return MIDIERR_STILLPLAYING;
1234 hdr->dwFlags &= ~MHDR_PREPARED;
1235 return MMSYSERR_NOERROR;
1238 static UINT midi_out_get_devcaps(WORD dev_id, MIDIOUTCAPSW *caps, UINT size)
1240 TRACE("(%04X, %p, %08X);\n", dev_id, caps, size);
1242 if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID;
1243 if (!caps) return MMSYSERR_INVALPARAM;
1245 memcpy(caps, &dests[dev_id].caps, min(size, sizeof(*caps)));
1247 return MMSYSERR_NOERROR;
1250 static UINT midi_out_get_volume(WORD dev_id, UINT *volume)
1252 if (!volume) return MMSYSERR_INVALPARAM;
1253 if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID;
1255 *volume = 0xFFFFFFFF;
1256 return (dests[dev_id].caps.dwSupport & MIDICAPS_VOLUME) ? 0 : MMSYSERR_NOTSUPPORTED;
1259 static UINT midi_out_reset(WORD dev_id)
1261 struct midi_dest *dest;
1262 unsigned chn;
1264 TRACE("(%04X);\n", dev_id);
1266 if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID;
1267 dest = dests + dev_id;
1268 if (!dest->bEnabled) return MIDIERR_NODEVICE;
1270 /* stop all notes */
1271 for (chn = 0; chn < 16; chn++)
1273 /* turn off every note */
1274 midi_out_data(dev_id, 0x7800 | MIDI_CTL_CHANGE | chn);
1275 /* remove sustain on all channels */
1276 midi_out_data(dev_id, (CTL_SUSTAIN << 8) | MIDI_CTL_CHANGE | chn);
1278 dest->runningStatus = 0;
1279 /* FIXME: the LongData buffers must also be returned to the app */
1280 return MMSYSERR_NOERROR;
1283 static void handle_sysex_data(struct midi_src *src, unsigned char value, UINT time)
1285 struct notify_context notify;
1286 MIDIHDR *hdr;
1287 BOOL done = FALSE;
1289 src->state |= 2;
1290 src->incLen = 0;
1292 in_buffer_lock();
1294 hdr = src->lpQueueHdr;
1295 if (hdr)
1297 BYTE *data = (BYTE *)hdr->lpData;
1299 data[hdr->dwBytesRecorded++] = value;
1300 if (hdr->dwBytesRecorded == hdr->dwBufferLength)
1301 done = TRUE;
1304 if (value == 0xf7) /* end */
1306 src->state &= ~2;
1307 done = TRUE;
1310 if (done && hdr)
1312 src->lpQueueHdr = hdr->lpNext;
1313 hdr->dwFlags &= ~MHDR_INQUEUE;
1314 hdr->dwFlags |= MHDR_DONE;
1315 set_in_notify(&notify, src, src - srcs, MIM_LONGDATA, (UINT_PTR)hdr, time);
1316 notify_post(&notify);
1319 in_buffer_unlock();
1322 static void handle_regular_data(struct midi_src *src, unsigned char value, UINT time)
1324 struct notify_context notify;
1325 UINT to_send = 0;
1327 #define IS_CMD(_x) (((_x) & 0x80) == 0x80)
1328 #define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0)
1330 if (!IS_CMD(value) && src->incLen == 0) /* try to reuse old cmd */
1332 if (IS_CMD(src->incPrev) && !IS_SYS_CMD(src->incPrev))
1334 src->incoming[0] = src->incPrev;
1335 src->incLen = 1;
1337 else
1339 /* FIXME: should generate MIM_ERROR notification */
1340 return;
1343 src->incoming[(int)src->incLen++] = value;
1344 if (src->incLen == 1 && !IS_SYS_CMD(src->incoming[0]))
1345 /* store new cmd, just in case */
1346 src->incPrev = src->incoming[0];
1348 #undef IS_CMD
1349 #undef IS_SYS_CMD
1351 switch (src->incoming[0] & 0xF0)
1353 case MIDI_NOTEOFF:
1354 case MIDI_NOTEON:
1355 case MIDI_KEY_PRESSURE:
1356 case MIDI_CTL_CHANGE:
1357 case MIDI_PITCH_BEND:
1358 if (src->incLen == 3)
1359 to_send = (src->incoming[2] << 16) | (src->incoming[1] << 8) |
1360 src->incoming[0];
1361 break;
1362 case MIDI_PGM_CHANGE:
1363 case MIDI_CHN_PRESSURE:
1364 if (src->incLen == 2)
1365 to_send = (src->incoming[1] << 8) | src->incoming[0];
1366 break;
1367 case MIDI_SYSTEM_PREFIX:
1368 if (src->incLen == 1)
1369 to_send = src->incoming[0];
1370 break;
1373 if (to_send)
1375 src->incLen = 0;
1376 set_in_notify(&notify, src, src - srcs, MIM_DATA, to_send, time);
1377 notify_post(&notify);
1381 static void handle_midi_data(unsigned char *buffer, unsigned int len)
1383 unsigned int time = get_time_msec(), i;
1384 struct midi_src *src;
1385 unsigned char value;
1386 WORD dev_id;
1388 for (i = 0; i < len; i += (buffer[i] & 0x80) ? 8 : 4)
1390 if (buffer[i] != SEQ_MIDIPUTC) continue;
1392 dev_id = buffer[i + 2];
1393 value = buffer[i + 1];
1395 if (dev_id >= num_srcs) continue;
1396 src = srcs + dev_id;
1397 if (src->state <= 0) continue;
1399 if (value == 0xf0 || src->state & 2) /* system exclusive */
1400 handle_sysex_data(src, value, time - src->startTime);
1401 else
1402 handle_regular_data(src, value, time - src->startTime);
1406 static void *rec_thread_proc(void *arg)
1408 int fd = PtrToLong(arg);
1409 unsigned char buffer[256];
1410 int len;
1411 struct pollfd pollfd[2];
1413 pollfd[0].fd = rec_cancel_pipe[0];
1414 pollfd[0].events = POLLIN;
1415 pollfd[1].fd = fd;
1416 pollfd[1].events = POLLIN;
1418 while (1)
1420 /* Check if an event is present */
1421 if (poll(pollfd, ARRAY_SIZE(pollfd), -1) <= 0)
1422 continue;
1424 if (pollfd[0].revents & POLLIN) /* cancelled */
1425 break;
1427 len = read(fd, buffer, sizeof(buffer));
1429 if (len > 0 && len % 4 == 0)
1430 handle_midi_data(buffer, len);
1432 return NULL;
1435 static UINT midi_in_open(WORD dev_id, MIDIOPENDESC *desc, UINT flags, struct notify_context *notify)
1437 struct midi_src *src;
1438 int fd;
1440 TRACE("(%04X, %p, %08X);\n", dev_id, desc, flags);
1442 if (desc == NULL)
1444 WARN("Invalid Parameter !\n");
1445 return MMSYSERR_INVALPARAM;
1448 /* FIXME :
1449 * how to check that content of lpDesc is correct ?
1451 if (dev_id >= num_srcs)
1453 WARN("wDevID too large (%u) !\n", dev_id);
1454 return MMSYSERR_BADDEVICEID;
1456 src = srcs + dev_id;
1457 if (src->state == -1)
1459 WARN("device disabled\n");
1460 return MIDIERR_NODEVICE;
1462 if (src->midiDesc.hMidi != 0)
1464 WARN("device already open !\n");
1465 return MMSYSERR_ALLOCATED;
1467 if ((flags & MIDI_IO_STATUS) != 0)
1469 WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n");
1470 flags &= ~MIDI_IO_STATUS;
1472 if ((flags & ~CALLBACK_TYPEMASK) != 0)
1474 FIXME("Bad flags\n");
1475 return MMSYSERR_INVALFLAG;
1478 fd = seq_open();
1479 if (fd < 0)
1480 return MMSYSERR_ERROR;
1482 if (num_midi_in_started++ == 0)
1484 pipe(rec_cancel_pipe);
1485 if (pthread_create(&rec_thread_id, NULL, rec_thread_proc, LongToPtr(fd)))
1487 close(rec_cancel_pipe[0]);
1488 close(rec_cancel_pipe[1]);
1489 num_midi_in_started = 0;
1490 WARN("Couldn't create thread for midi-in\n");
1491 seq_close(fd);
1492 return MMSYSERR_ERROR;
1494 TRACE("Created thread for midi-in\n");
1497 src->wFlags = HIWORD(flags & CALLBACK_TYPEMASK);
1499 src->lpQueueHdr = NULL;
1500 src->midiDesc = *desc;
1501 src->state = 0;
1502 src->incLen = 0;
1503 src->startTime = 0;
1504 src->fd = fd;
1506 set_in_notify(notify, src, dev_id, MIM_OPEN, 0, 0);
1507 return MMSYSERR_NOERROR;
1510 static UINT midi_in_close(WORD dev_id, struct notify_context *notify)
1512 struct midi_src *src;
1514 TRACE("(%04X);\n", dev_id);
1516 if (dev_id >= num_srcs)
1518 WARN("dev_id too big (%u) !\n", dev_id);
1519 return MMSYSERR_BADDEVICEID;
1521 src = srcs + dev_id;
1522 if (src->midiDesc.hMidi == 0)
1524 WARN("device not opened !\n");
1525 return MMSYSERR_ERROR;
1527 if (src->lpQueueHdr != 0)
1528 return MIDIERR_STILLPLAYING;
1530 if (src->fd == -1)
1532 WARN("ooops !\n");
1533 return MMSYSERR_ERROR;
1535 if (--num_midi_in_started == 0)
1537 TRACE("Stopping thread for midi-in\n");
1538 write(rec_cancel_pipe[1], "x", 1);
1539 pthread_join(rec_thread_id, NULL);
1540 close(rec_cancel_pipe[0]);
1541 close(rec_cancel_pipe[1]);
1542 TRACE("Stopped thread for midi-in\n");
1544 seq_close(src->fd);
1545 src->fd = -1;
1547 set_in_notify(notify, src, dev_id, MIM_CLOSE, 0, 0);
1548 src->midiDesc.hMidi = 0;
1550 return MMSYSERR_NOERROR;
1553 static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
1555 struct midi_src *src;
1556 MIDIHDR **next;
1558 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1560 if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID;
1561 src = srcs + dev_id;
1562 if (src->state == -1) return MIDIERR_NODEVICE;
1564 if (!hdr || hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr->dwBufferLength)
1565 return MMSYSERR_INVALPARAM;
1566 if (hdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
1567 if (!(hdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
1569 in_buffer_lock();
1571 hdr->dwFlags &= ~WHDR_DONE;
1572 hdr->dwFlags |= MHDR_INQUEUE;
1573 hdr->dwBytesRecorded = 0;
1574 hdr->lpNext = NULL;
1576 next = &src->lpQueueHdr;
1577 while (*next) next = &(*next)->lpNext;
1578 *next = hdr;
1580 in_buffer_unlock();
1582 return MMSYSERR_NOERROR;
1585 static UINT midi_in_prepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
1587 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1589 if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData)
1590 return MMSYSERR_INVALPARAM;
1591 if (hdr->dwFlags & MHDR_PREPARED)
1592 return MMSYSERR_NOERROR;
1594 hdr->lpNext = NULL;
1595 hdr->dwFlags |= MHDR_PREPARED;
1596 hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE);
1598 return MMSYSERR_NOERROR;
1601 static UINT midi_in_unprepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size)
1603 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1605 if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData)
1606 return MMSYSERR_INVALPARAM;
1607 if (!(hdr->dwFlags & MHDR_PREPARED))
1608 return MMSYSERR_NOERROR;
1609 if (hdr->dwFlags & MHDR_INQUEUE)
1610 return MIDIERR_STILLPLAYING;
1612 hdr->dwFlags &= ~MHDR_PREPARED;
1614 return MMSYSERR_NOERROR;
1617 static UINT midi_in_get_devcaps(WORD dev_id, MIDIINCAPSW *caps, UINT size)
1619 TRACE("(%04X, %p, %08X);\n", dev_id, caps, size);
1621 if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID;
1622 if (!caps) return MMSYSERR_INVALPARAM;
1624 memcpy(caps, &srcs[dev_id].caps, min(size, sizeof(*caps)));
1626 return MMSYSERR_NOERROR;
1629 static UINT midi_in_start(WORD dev_id)
1631 struct midi_src *src;
1633 TRACE("(%04X);\n", dev_id);
1635 if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID;
1636 src = srcs + dev_id;
1637 if (src->state == -1) return MIDIERR_NODEVICE;
1639 src->state = 1;
1640 src->startTime = get_time_msec();
1641 return MMSYSERR_NOERROR;
1644 static UINT midi_in_stop(WORD dev_id)
1646 struct midi_src *src;
1648 TRACE("(%04X);\n", dev_id);
1650 if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID;
1651 src = srcs + dev_id;
1652 if (src->state == -1) return MIDIERR_NODEVICE;
1654 src->state = 0;
1655 return MMSYSERR_NOERROR;
1658 static UINT midi_in_reset(WORD dev_id, struct notify_context *notify)
1660 UINT cur_time = get_time_msec();
1661 UINT err = MMSYSERR_NOERROR;
1662 struct midi_src *src;
1663 MIDIHDR *hdr;
1665 TRACE("(%04X);\n", dev_id);
1667 if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID;
1668 src = srcs + dev_id;
1669 if (src->state == -1) return MIDIERR_NODEVICE;
1671 in_buffer_lock();
1673 if (src->lpQueueHdr)
1675 hdr = src->lpQueueHdr;
1676 src->lpQueueHdr = hdr->lpNext;
1677 hdr->dwFlags &= ~MHDR_INQUEUE;
1678 hdr->dwFlags |= MHDR_DONE;
1679 set_in_notify(notify, src, dev_id, MIM_LONGDATA, (UINT_PTR)hdr, cur_time - src->startTime);
1680 if (src->lpQueueHdr) err = ERROR_RETRY; /* ask the client to call again */
1683 in_buffer_unlock();
1685 return err;
1688 NTSTATUS midi_out_message(void *args)
1690 struct midi_out_message_params *params = args;
1692 params->notify->send_notify = FALSE;
1694 switch (params->msg)
1696 case DRVM_INIT:
1697 *params->err = midi_init();
1698 break;
1699 case DRVM_EXIT:
1700 *params->err = midi_exit();
1701 break;
1702 case DRVM_ENABLE:
1703 case DRVM_DISABLE:
1704 /* FIXME: Pretend this is supported */
1705 *params->err = MMSYSERR_NOERROR;
1706 break;
1707 case MODM_OPEN:
1708 *params->err = midi_out_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify);
1709 break;
1710 case MODM_CLOSE:
1711 *params->err = midi_out_close(params->dev_id, params->notify);
1712 break;
1713 case MODM_DATA:
1714 *params->err = midi_out_data(params->dev_id, params->param_1);
1715 break;
1716 case MODM_LONGDATA:
1717 *params->err = midi_out_long_data(params->dev_id, (MIDIHDR *)params->param_1, params->param_2, params->notify);
1718 break;
1719 case MODM_PREPARE:
1720 *params->err = midi_out_prepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
1721 break;
1722 case MODM_UNPREPARE:
1723 *params->err = midi_out_unprepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
1724 break;
1725 case MODM_GETDEVCAPS:
1726 *params->err = midi_out_get_devcaps(params->dev_id, (MIDIOUTCAPSW *)params->param_1, params->param_2);
1727 break;
1728 case MODM_GETNUMDEVS:
1729 *params->err = num_dests;
1730 break;
1731 case MODM_GETVOLUME:
1732 *params->err = midi_out_get_volume(params->dev_id, (UINT *)params->param_1);
1733 break;
1734 case MODM_SETVOLUME:
1735 *params->err = 0;
1736 break;
1737 case MODM_RESET:
1738 *params->err = midi_out_reset(params->dev_id);
1739 break;
1740 default:
1741 TRACE("Unsupported message\n");
1742 *params->err = MMSYSERR_NOTSUPPORTED;
1745 return STATUS_SUCCESS;
1748 NTSTATUS midi_in_message(void *args)
1750 struct midi_in_message_params *params = args;
1752 params->notify->send_notify = FALSE;
1754 switch (params->msg)
1756 case DRVM_INIT:
1757 *params->err = midi_init();
1758 break;
1759 case DRVM_EXIT:
1760 *params->err = midi_exit();
1761 break;
1762 case DRVM_ENABLE:
1763 case DRVM_DISABLE:
1764 /* FIXME: Pretend this is supported */
1765 *params->err = MMSYSERR_NOERROR;
1766 break;
1767 case MIDM_OPEN:
1768 *params->err = midi_in_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify);
1769 break;
1770 case MIDM_CLOSE:
1771 *params->err = midi_in_close(params->dev_id, params->notify);
1772 break;
1773 case MIDM_ADDBUFFER:
1774 *params->err = midi_in_add_buffer(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
1775 break;
1776 case MIDM_PREPARE:
1777 *params->err = midi_in_prepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
1778 break;
1779 case MIDM_UNPREPARE:
1780 *params->err = midi_in_unprepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2);
1781 break;
1782 case MIDM_GETDEVCAPS:
1783 *params->err = midi_in_get_devcaps(params->dev_id, (MIDIINCAPSW *)params->param_1, params->param_2);
1784 break;
1785 case MIDM_GETNUMDEVS:
1786 *params->err = num_srcs;
1787 break;
1788 case MIDM_START:
1789 *params->err = midi_in_start(params->dev_id);
1790 break;
1791 case MIDM_STOP:
1792 *params->err = midi_in_stop(params->dev_id);
1793 break;
1794 case MIDM_RESET:
1795 *params->err = midi_in_reset(params->dev_id, params->notify);
1796 break;
1797 default:
1798 TRACE("Unsupported message\n");
1799 *params->err = MMSYSERR_NOTSUPPORTED;
1802 return STATUS_SUCCESS;
1805 NTSTATUS midi_notify_wait(void *args)
1807 struct midi_notify_wait_params *params = args;
1809 pthread_mutex_lock(&notify_mutex);
1811 while (!notify_quit && notify_buffer_empty())
1812 pthread_cond_wait(&notify_read_cond, &notify_mutex);
1814 *params->quit = notify_quit;
1815 if (!notify_quit)
1817 notify_buffer_remove(params->notify);
1818 pthread_cond_signal(&notify_write_cond);
1820 pthread_mutex_unlock(&notify_mutex);
1822 return STATUS_SUCCESS;
1825 #ifdef _WIN64
1827 typedef UINT PTR32;
1829 struct notify_context32
1831 BOOL send_notify;
1832 WORD dev_id;
1833 WORD msg;
1834 UINT param_1;
1835 UINT param_2;
1836 UINT callback;
1837 UINT flags;
1838 PTR32 device;
1839 UINT instance;
1842 static void notify_to_notify32(struct notify_context32 *notify32,
1843 const struct notify_context *notify)
1845 notify32->send_notify = notify->send_notify;
1846 notify32->dev_id = notify->dev_id;
1847 notify32->msg = notify->msg;
1848 notify32->param_1 = notify->param_1;
1849 notify32->param_2 = notify->param_2;
1850 notify32->callback = notify->callback;
1851 notify32->flags = notify->flags;
1852 notify32->device = PtrToUlong(notify->device);
1853 notify32->instance = notify->instance;
1856 struct midi_open_desc32
1858 PTR32 hMidi;
1859 UINT dwCallback;
1860 UINT dwInstance;
1861 UINT dnDevNode;
1862 UINT cIds;
1863 MIDIOPENSTRMID rgIds;
1866 struct midi_hdr32
1868 PTR32 lpData;
1869 UINT dwBufferLength;
1870 UINT dwBytesRecorded;
1871 UINT dwUser;
1872 UINT dwFlags;
1873 PTR32 lpNext;
1874 UINT reserved;
1875 UINT dwOffset;
1876 UINT dwReserved[8];
1879 static UINT wow64_midi_out_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
1881 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1883 if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
1884 return MMSYSERR_INVALPARAM;
1885 if (hdr->dwFlags & MHDR_PREPARED)
1886 return MMSYSERR_NOERROR;
1888 hdr->lpNext = 0;
1889 hdr->dwFlags |= MHDR_PREPARED;
1890 hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE);
1891 return MMSYSERR_NOERROR;
1894 static UINT wow64_midi_out_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
1896 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
1898 if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
1899 return MMSYSERR_INVALPARAM;
1900 if (!(hdr->dwFlags & MHDR_PREPARED))
1901 return MMSYSERR_NOERROR;
1902 if (hdr->dwFlags & MHDR_INQUEUE)
1903 return MIDIERR_STILLPLAYING;
1905 hdr->dwFlags &= ~MHDR_PREPARED;
1906 return MMSYSERR_NOERROR;
1909 NTSTATUS wow64_midi_out_message(void *args)
1911 struct
1913 UINT dev_id;
1914 UINT msg;
1915 UINT user;
1916 UINT param_1;
1917 UINT param_2;
1918 PTR32 err;
1919 PTR32 notify;
1920 } *params32 = args;
1921 struct notify_context32 *notify32 = ULongToPtr(params32->notify);
1922 struct midi_open_desc32 *desc32;
1923 struct midi_hdr32 *hdr32;
1924 struct notify_context notify;
1925 MIDIOPENDESC open_desc;
1926 MIDIHDR hdr;
1927 struct midi_out_message_params params =
1929 .dev_id = params32->dev_id,
1930 .msg = params32->msg,
1931 .user = params32->user,
1932 .param_1 = params32->param_1,
1933 .param_2 = params32->param_2,
1934 .err = ULongToPtr(params32->err),
1935 .notify = &notify
1937 notify32->send_notify = FALSE;
1939 switch (params32->msg)
1941 case MODM_OPEN:
1942 desc32 = ULongToPtr(params32->param_1);
1944 open_desc.hMidi = ULongToPtr(desc32->hMidi);
1945 open_desc.dwCallback = desc32->dwCallback;
1946 open_desc.dwInstance = desc32->dwInstance;
1947 open_desc.dnDevNode = desc32->dnDevNode;
1948 open_desc.cIds = desc32->cIds;
1949 open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID;
1950 open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID;
1952 params.param_1 = (UINT_PTR)&open_desc;
1953 break;
1955 case MODM_LONGDATA:
1956 hdr32 = ULongToPtr(params32->param_1);
1958 memset(&hdr, 0, sizeof(hdr));
1959 hdr.lpData = ULongToPtr(hdr32->lpData);
1960 hdr.dwBufferLength = hdr32->dwBufferLength;
1961 hdr.dwFlags = hdr32->dwFlags;
1963 params.param_1 = (UINT_PTR)&hdr;
1964 params.param_2 = sizeof(hdr);
1965 break;
1967 case MODM_PREPARE: /* prepare and unprepare are easier to handle explicitly */
1968 hdr32 = ULongToPtr(params32->param_1);
1970 *params.err = wow64_midi_out_prepare(params32->dev_id, hdr32, params32->param_2);
1971 return STATUS_SUCCESS;
1973 case MODM_UNPREPARE:
1974 hdr32 = ULongToPtr(params32->param_1);
1976 *params.err = wow64_midi_out_unprepare(params32->dev_id, hdr32, params32->param_2);
1977 return STATUS_SUCCESS;
1980 midi_out_message(&params);
1982 switch (params32->msg)
1984 case MODM_LONGDATA:
1985 hdr32 = ULongToPtr(params32->param_1);
1987 hdr32->dwFlags = hdr.dwFlags;
1988 break;
1991 if (notify.send_notify)
1993 notify_to_notify32(notify32, &notify);
1995 if (notify.msg == MOM_DONE)
1996 notify32->param_1 = params32->param_1; /* restore the 32-bit hdr */
1998 return STATUS_SUCCESS;
2001 static UINT wow64_midi_in_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
2003 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
2005 if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
2006 return MMSYSERR_INVALPARAM;
2007 if (hdr->dwFlags & MHDR_PREPARED)
2008 return MMSYSERR_NOERROR;
2010 hdr->lpNext = 0;
2011 hdr->dwFlags |= MHDR_PREPARED;
2012 hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE);
2014 return MMSYSERR_NOERROR;
2017 static UINT wow64_midi_in_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size)
2019 TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size);
2021 if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData)
2022 return MMSYSERR_INVALPARAM;
2023 if (!(hdr->dwFlags & MHDR_PREPARED))
2024 return MMSYSERR_NOERROR;
2025 if (hdr->dwFlags & MHDR_INQUEUE)
2026 return MIDIERR_STILLPLAYING;
2028 hdr->dwFlags &= ~MHDR_PREPARED;
2030 return MMSYSERR_NOERROR;
2033 NTSTATUS wow64_midi_in_message(void *args)
2035 struct
2037 UINT dev_id;
2038 UINT msg;
2039 UINT user;
2040 UINT param_1;
2041 UINT param_2;
2042 PTR32 err;
2043 PTR32 notify;
2044 } *params32 = args;
2045 struct notify_context32 *notify32 = ULongToPtr(params32->notify);
2046 struct midi_open_desc32 *desc32;
2047 struct midi_hdr32 *hdr32;
2048 struct notify_context notify;
2049 MIDIOPENDESC open_desc;
2050 MIDIHDR *hdr = NULL;
2051 struct midi_in_message_params params =
2053 .dev_id = params32->dev_id,
2054 .msg = params32->msg,
2055 .user = params32->user,
2056 .param_1 = params32->param_1,
2057 .param_2 = params32->param_2,
2058 .err = ULongToPtr(params32->err),
2059 .notify = &notify
2061 notify32->send_notify = FALSE;
2063 switch (params32->msg)
2065 case MIDM_OPEN:
2066 desc32 = ULongToPtr(params32->param_1);
2068 open_desc.hMidi = ULongToPtr(desc32->hMidi);
2069 open_desc.dwCallback = desc32->dwCallback;
2070 open_desc.dwInstance = desc32->dwInstance;
2071 open_desc.dnDevNode = desc32->dnDevNode;
2072 open_desc.cIds = desc32->cIds;
2073 open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID;
2074 open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID;
2076 params.param_1 = (UINT_PTR)&open_desc;
2077 break;
2079 case MIDM_ADDBUFFER:
2080 hdr32 = ULongToPtr(params32->param_1);
2082 hdr = calloc(1, sizeof(*hdr));
2083 hdr->lpData = ULongToPtr(hdr32->lpData);
2084 hdr->dwBufferLength = hdr32->dwBufferLength;
2085 hdr->dwFlags = hdr32->dwFlags;
2086 hdr->dwReserved[7] = params32->param_1; /* keep hdr32 for MIM_LONGDATA notification */
2088 params.param_1 = (UINT_PTR)hdr;
2089 params.param_2 = sizeof(*hdr);
2090 break;
2092 case MIDM_PREPARE: /* prepare and unprepare are easier to handle explicitly */
2093 hdr32 = ULongToPtr(params32->param_1);
2095 *params.err = wow64_midi_in_prepare(params32->dev_id, hdr32, params32->param_2);
2096 return STATUS_SUCCESS;
2098 case MIDM_UNPREPARE:
2099 hdr32 = ULongToPtr(params32->param_1);
2101 *params.err = wow64_midi_in_unprepare(params32->dev_id, hdr32, params32->param_2);
2102 return STATUS_SUCCESS;
2105 midi_in_message(&params);
2107 switch (params32->msg)
2109 case MIDM_ADDBUFFER:
2110 hdr32 = ULongToPtr(params32->param_1);
2112 if (!*params.err)
2114 hdr32->dwFlags = hdr->dwFlags;
2115 hdr32->dwBytesRecorded = hdr->dwBytesRecorded;
2116 hdr32->lpNext = 0;
2118 else
2119 free(hdr);
2120 break;
2123 if (notify.send_notify)
2125 notify_to_notify32(notify32, &notify);
2127 if (notify.msg == MIM_LONGDATA)
2129 hdr = (MIDIHDR *)notify.param_1;
2130 notify32->param_1 = hdr->dwReserved[7];
2131 hdr32 = ULongToPtr(notify32->param_1);
2132 hdr32->dwBytesRecorded = hdr->dwBytesRecorded;
2133 hdr32->dwFlags = hdr->dwFlags;
2134 free(hdr);
2137 return STATUS_SUCCESS;
2140 NTSTATUS wow64_midi_notify_wait(void *args)
2142 struct
2144 PTR32 quit;
2145 PTR32 notify;
2146 } *params32 = args;
2147 struct notify_context32 *notify32 = ULongToPtr(params32->notify);
2148 struct midi_hdr32 *hdr32;
2149 struct notify_context notify;
2150 MIDIHDR *hdr;
2151 struct midi_notify_wait_params params =
2153 .quit = ULongToPtr(params32->quit),
2154 .notify = &notify
2156 notify32->send_notify = FALSE;
2158 midi_notify_wait(&params);
2160 if (!*params.quit && notify.send_notify)
2162 notify_to_notify32(notify32, &notify);
2164 if (notify.msg == MIM_LONGDATA)
2166 hdr = (MIDIHDR *)notify.param_1;
2167 notify32->param_1 = hdr->dwReserved[7];
2168 hdr32 = ULongToPtr(notify32->param_1);
2169 hdr32->dwBytesRecorded = hdr->dwBytesRecorded;
2170 hdr32->dwFlags = hdr->dwFlags;
2171 free(hdr);
2174 return STATUS_SUCCESS;
2177 #endif /* _WIN64 */