Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1 | /* -*- tab-width: 8; c-basic-offset: 4 -*- */ |
| 2 | |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 3 | /* |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 4 | * Sample MIDI Wine Driver for Open Sound System (basically Linux) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 5 | * |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 6 | * Copyright 1994 Martin Ayotte |
| 7 | * Copyright 1998 Luiz Otavio L. Zorzella (init procedures) |
| 8 | * Copyright 1998/1999 Eric POUECH : |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 9 | * 98/7 changes for making this MIDI driver work on OSS |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 10 | * current support is limited to MIDI ports of OSS systems |
| 11 | * 98/9 rewriting MCI code for MIDI |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 12 | * 98/11 splitted in midi.c and mcimidi.c |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 13 | */ |
| 14 | |
Alexandre Julliard | 23946ad | 1997-06-16 17:43:53 +0000 | [diff] [blame] | 15 | #include <string.h> |
Alexandre Julliard | 7cbe657 | 1995-01-09 18:21:16 +0000 | [diff] [blame] | 16 | #include <unistd.h> |
| 17 | #include <fcntl.h> |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 18 | #include <sys/ioctl.h> |
Michael Veksler | ff5ae3d | 1999-04-22 15:26:11 +0000 | [diff] [blame] | 19 | #include "winuser.h" |
Eric Pouech | 37c0217 | 1999-09-05 16:44:38 +0000 | [diff] [blame] | 20 | #include "mmddk.h" |
| 21 | #include "oss.h" |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 22 | #include "driver.h" |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 23 | #include "debugtools.h" |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 24 | #include "heap.h" |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 25 | #include "ldt.h" |
Marcus Meissner | 61afa33 | 1999-02-22 10:16:00 +0000 | [diff] [blame] | 26 | |
Patrik Stridvall | b4b9fae | 1999-04-19 14:56:29 +0000 | [diff] [blame] | 27 | DEFAULT_DEBUG_CHANNEL(midi) |
| 28 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 29 | #ifdef HAVE_OSS_MIDI |
| 30 | |
Eric Pouech | 37c0217 | 1999-09-05 16:44:38 +0000 | [diff] [blame] | 31 | #define MIDI_SEQ "/dev/sequencer" |
| 32 | |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 33 | typedef struct { |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 34 | int state; |
| 35 | DWORD bufsize; |
| 36 | LPMIDIOPENDESC midiDesc; |
| 37 | WORD wFlags; |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 38 | LPMIDIHDR lpQueueHdr; |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 39 | DWORD dwTotalPlayed; |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 40 | unsigned char incoming[3]; |
| 41 | unsigned char incPrev; |
| 42 | char incLen; |
| 43 | DWORD startTime; |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 44 | } WINE_MIDIIN; |
| 45 | |
| 46 | typedef struct { |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 47 | int state; |
| 48 | DWORD bufsize; |
| 49 | LPMIDIOPENDESC midiDesc; |
| 50 | WORD wFlags; |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 51 | LPMIDIHDR lpQueueHdr; |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 52 | DWORD dwTotalPlayed; |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 53 | void* lpExtra; /* according to port type (MIDI, FM...), extra data when needed */ |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 54 | } WINE_MIDIOUT; |
| 55 | |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 56 | static WINE_MIDIIN MidiInDev [MAX_MIDIINDRV ]; |
| 57 | static WINE_MIDIOUT MidiOutDev[MAX_MIDIOUTDRV]; |
Alexandre Julliard | 54c2711 | 1998-03-29 19:44:57 +0000 | [diff] [blame] | 58 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 59 | /* this is the total number of MIDI out devices found */ |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 60 | static int MODM_NUMDEVS = 0; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 61 | /* this is the number of FM synthetizers (index from 0 to |
| 62 | NUMFMSYNTHDEVS - 1) */ |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 63 | static int MODM_NUMFMSYNTHDEVS = 0; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 64 | /* this is the number of Midi ports (index from NUMFMSYNTHDEVS to |
| 65 | NUMFMSYNTHDEVS + NUMMIDIDEVS - 1) */ |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 66 | static int MODM_NUMMIDIDEVS = 0; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 67 | |
| 68 | /* this is the total number of MIDI out devices found */ |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 69 | static int MIDM_NUMDEVS = 0; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 70 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 71 | static int midiSeqFD = -1; |
| 72 | static int numOpenMidiSeq = 0; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 73 | static UINT midiInTimerID = 0; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 74 | static int numStartedMidiIn = 0; |
Alexandre Julliard | 54c2711 | 1998-03-29 19:44:57 +0000 | [diff] [blame] | 75 | |
| 76 | /* this structure holds pointers with information for each MIDI |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 77 | * out device found. |
Alexandre Julliard | 54c2711 | 1998-03-29 19:44:57 +0000 | [diff] [blame] | 78 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 79 | static LPMIDIOUTCAPSA midiOutDevices[MAX_MIDIOUTDRV]; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 80 | |
| 81 | /* this structure holds pointers with information for each MIDI |
| 82 | * in device found. |
| 83 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 84 | static LPMIDIINCAPSA midiInDevices [MAX_MIDIINDRV]; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 85 | |
| 86 | /* |
| 87 | * FIXME : all tests on device ID for midXXX and modYYY are made against |
| 88 | * MAX_MIDIxxDRV (when they are made) but should be done against the actual |
| 89 | * number of midi devices found... |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 90 | */ |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 91 | |
Eric Pouech | 4fa77ce | 1998-11-24 18:31:43 +0000 | [diff] [blame] | 92 | /*======================================================================* |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 93 | * Low level MIDI implementation * |
Eric Pouech | 4fa77ce | 1998-11-24 18:31:43 +0000 | [diff] [blame] | 94 | *======================================================================*/ |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 95 | |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 96 | static int midiOpenSeq(void); |
| 97 | static int midiCloseSeq(void); |
| 98 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 99 | /************************************************************************** |
| 100 | * unixToWindowsDeviceType [internal] |
| 101 | * |
| 102 | * return the Windows equivalent to a Unix Device Type |
| 103 | * |
| 104 | */ |
| 105 | static int MIDI_UnixToWindowsDeviceType(int type) |
| 106 | { |
| 107 | /* MOD_MIDIPORT output port |
| 108 | * MOD_SYNTH generic internal synth |
| 109 | * MOD_SQSYNTH square wave internal synth |
| 110 | * MOD_FMSYNTH FM internal synth |
| 111 | * MOD_MAPPER MIDI mapper |
| 112 | */ |
| 113 | |
| 114 | /* FIXME Is this really the correct equivalence from UNIX to |
| 115 | Windows Sound type */ |
| 116 | |
| 117 | switch (type) { |
| 118 | case SYNTH_TYPE_FM: return MOD_FMSYNTH; |
| 119 | case SYNTH_TYPE_SAMPLE: return MOD_SYNTH; |
| 120 | case SYNTH_TYPE_MIDI: return MOD_MIDIPORT; |
| 121 | default: |
| 122 | ERR("Cannot determine the type of this midi device. " |
| 123 | "Assuming FM Synth\n"); |
| 124 | return MOD_FMSYNTH; |
| 125 | } |
| 126 | return MOD_FMSYNTH; |
| 127 | } |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 128 | |
| 129 | /************************************************************************** |
Eric Pouech | 37c0217 | 1999-09-05 16:44:38 +0000 | [diff] [blame] | 130 | * OSS_MidiInit [internal] |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 131 | * |
| 132 | * Initializes the MIDI devices information variables |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 133 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 134 | static BOOL OSS_MidiInit(void) |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 135 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 136 | int i, status, numsynthdevs = 255, nummididevs = 255; |
| 137 | struct synth_info sinfo; |
| 138 | struct midi_info minfo; |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 139 | static BOOL bInitDone = FALSE; |
| 140 | |
| 141 | if (bInitDone) |
| 142 | return TRUE; |
| 143 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 144 | TRACE("Initializing the MIDI variables.\n"); |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 145 | bInitDone = TRUE; |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 146 | |
| 147 | /* try to open device */ |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 148 | if (midiOpenSeq() == -1) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 149 | return TRUE; |
| 150 | } |
| 151 | |
| 152 | /* find how many Synth devices are there in the system */ |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 153 | status = ioctl(midiSeqFD, SNDCTL_SEQ_NRSYNTHS, &numsynthdevs); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 154 | |
| 155 | if (status == -1) { |
| 156 | ERR("ioctl for nr synth failed.\n"); |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 157 | midiCloseSeq(); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 158 | return TRUE; |
| 159 | } |
| 160 | |
| 161 | if (numsynthdevs > MAX_MIDIOUTDRV) { |
| 162 | ERR("MAX_MIDIOUTDRV (%d) was enough for the number of devices (%d). " |
| 163 | "Some FM devices will not be available.\n",MAX_MIDIOUTDRV,numsynthdevs); |
| 164 | numsynthdevs = MAX_MIDIOUTDRV; |
| 165 | } |
| 166 | |
| 167 | for (i = 0; i < numsynthdevs; i++) { |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 168 | LPMIDIOUTCAPSA tmplpCaps; |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 169 | |
| 170 | sinfo.device = i; |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 171 | status = ioctl(midiSeqFD, SNDCTL_SYNTH_INFO, &sinfo); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 172 | if (status == -1) { |
| 173 | ERR("ioctl for synth info failed.\n"); |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 174 | midiCloseSeq(); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 175 | return TRUE; |
| 176 | } |
| 177 | |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 178 | tmplpCaps = HeapAlloc(SystemHeap, 0, sizeof(MIDIOUTCAPSA)); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 179 | if (!tmplpCaps) |
| 180 | break; |
| 181 | /* We also have the information sinfo.synth_subtype, not used here |
| 182 | */ |
| 183 | |
| 184 | /* Manufac ID. We do not have access to this with soundcard.h |
| 185 | * Does not seem to be a problem, because in mmsystem.h only |
| 186 | * Microsoft's ID is listed. |
| 187 | */ |
| 188 | tmplpCaps->wMid = 0x00FF; |
| 189 | tmplpCaps->wPid = 0x0001; /* FIXME Product ID */ |
| 190 | /* Product Version. We simply say "1" */ |
| 191 | tmplpCaps->vDriverVersion = 0x001; |
| 192 | strcpy(tmplpCaps->szPname, sinfo.name); |
| 193 | |
| 194 | tmplpCaps->wTechnology = MIDI_UnixToWindowsDeviceType(sinfo.synth_type); |
| 195 | tmplpCaps->wVoices = sinfo.nr_voices; |
| 196 | |
| 197 | /* FIXME Is it possible to know the maximum |
| 198 | * number of simultaneous notes of a soundcard ? |
| 199 | * I believe we don't have this information, but |
| 200 | * it's probably equal or more than wVoices |
| 201 | */ |
| 202 | tmplpCaps->wNotes = sinfo.nr_voices; |
| 203 | |
| 204 | /* FIXME Do we have this information? |
| 205 | * Assuming the soundcards can handle |
| 206 | * MIDICAPS_VOLUME and MIDICAPS_LRVOLUME but |
| 207 | * not MIDICAPS_CACHE. |
| 208 | */ |
| 209 | tmplpCaps->dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME; |
| 210 | |
| 211 | midiOutDevices[i] = tmplpCaps; |
| 212 | |
| 213 | if (sinfo.capabilities & SYNTH_CAP_INPUT) { |
| 214 | FIXME("Synthetizer support MIDI in. Not supported yet (please report)\n"); |
| 215 | } |
| 216 | |
| 217 | TRACE("name='%s', techn=%d voices=%d notes=%d support=%ld\n", |
| 218 | tmplpCaps->szPname, tmplpCaps->wTechnology, |
| 219 | tmplpCaps->wVoices, tmplpCaps->wNotes, tmplpCaps->dwSupport); |
| 220 | TRACE("OSS info: synth subtype=%d capa=%Xh\n", |
| 221 | sinfo.synth_subtype, sinfo.capabilities); |
| 222 | } |
| 223 | |
| 224 | /* find how many MIDI devices are there in the system */ |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 225 | status = ioctl(midiSeqFD, SNDCTL_SEQ_NRMIDIS, &nummididevs); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 226 | if (status == -1) { |
| 227 | ERR("ioctl on nr midi failed.\n"); |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 228 | midiCloseSeq(); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 229 | return TRUE; |
| 230 | } |
| 231 | |
| 232 | /* FIXME: the two restrictions below could be loosen in some cases */ |
| 233 | if (numsynthdevs + nummididevs > MAX_MIDIOUTDRV) { |
| 234 | ERR("MAX_MIDIOUTDRV was not enough for the number of devices. " |
| 235 | "Some MIDI devices will not be available.\n"); |
| 236 | nummididevs = MAX_MIDIOUTDRV - numsynthdevs; |
| 237 | } |
| 238 | |
| 239 | if (nummididevs > MAX_MIDIINDRV) { |
| 240 | ERR("MAX_MIDIINDRV (%d) was not enough for the number of devices (%d). " |
| 241 | "Some MIDI devices will not be available.\n",MAX_MIDIINDRV,nummididevs); |
| 242 | nummididevs = MAX_MIDIINDRV; |
| 243 | } |
| 244 | |
| 245 | for (i = 0; i < nummididevs; i++) { |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 246 | LPMIDIOUTCAPSA tmplpOutCaps; |
| 247 | LPMIDIINCAPSA tmplpInCaps; |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 248 | |
| 249 | minfo.device = i; |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 250 | status = ioctl(midiSeqFD, SNDCTL_MIDI_INFO, &minfo); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 251 | if (status == -1) { |
| 252 | ERR("ioctl on midi info failed.\n"); |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 253 | midiCloseSeq(); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 254 | return TRUE; |
| 255 | } |
| 256 | |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 257 | tmplpOutCaps = HeapAlloc(SystemHeap, 0, sizeof(MIDIOUTCAPSA)); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 258 | if (!tmplpOutCaps) |
| 259 | break; |
| 260 | /* This whole part is somewhat obscure to me. I'll keep trying to dig |
| 261 | info about it. If you happen to know, please tell us. The very |
| 262 | descritive minfo.dev_type was not used here. |
| 263 | */ |
| 264 | /* Manufac ID. We do not have access to this with soundcard.h |
| 265 | Does not seem to be a problem, because in mmsystem.h only |
| 266 | Microsoft's ID is listed */ |
| 267 | tmplpOutCaps->wMid = 0x00FF; |
| 268 | tmplpOutCaps->wPid = 0x0001; /* FIXME Product ID */ |
| 269 | /* Product Version. We simply say "1" */ |
| 270 | tmplpOutCaps->vDriverVersion = 0x001; |
| 271 | strcpy(tmplpOutCaps->szPname, minfo.name); |
| 272 | |
| 273 | tmplpOutCaps->wTechnology = MOD_MIDIPORT; /* FIXME Is this right? */ |
| 274 | /* Does it make any difference? */ |
| 275 | tmplpOutCaps->wVoices = 16; |
| 276 | /* Does it make any difference? */ |
| 277 | tmplpOutCaps->wNotes = 16; |
| 278 | /* FIXME Does it make any difference? */ |
| 279 | tmplpOutCaps->dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME; |
| 280 | |
| 281 | midiOutDevices[numsynthdevs + i] = tmplpOutCaps; |
| 282 | |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 283 | tmplpInCaps = HeapAlloc(SystemHeap, 0, sizeof(MIDIOUTCAPSA)); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 284 | if (!tmplpInCaps) |
| 285 | break; |
| 286 | /* This whole part is somewhat obscure to me. I'll keep trying to dig |
| 287 | info about it. If you happen to know, please tell us. The very |
| 288 | descritive minfo.dev_type was not used here. |
| 289 | */ |
| 290 | /* Manufac ID. We do not have access to this with soundcard.h |
| 291 | Does not seem to be a problem, because in mmsystem.h only |
| 292 | Microsoft's ID is listed */ |
| 293 | tmplpInCaps->wMid = 0x00FF; |
| 294 | tmplpInCaps->wPid = 0x0001; /* FIXME Product ID */ |
| 295 | /* Product Version. We simply say "1" */ |
| 296 | tmplpInCaps->vDriverVersion = 0x001; |
| 297 | strcpy(tmplpInCaps->szPname, minfo.name); |
| 298 | |
| 299 | /* FIXME : could we get better information than that ? */ |
| 300 | tmplpInCaps->dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME; |
| 301 | |
| 302 | midiInDevices[i] = tmplpInCaps; |
| 303 | |
| 304 | TRACE("name='%s' techn=%d voices=%d notes=%d support=%ld\n", |
| 305 | tmplpOutCaps->szPname, tmplpOutCaps->wTechnology, tmplpOutCaps->wVoices, |
| 306 | tmplpOutCaps->wNotes, tmplpOutCaps->dwSupport); |
| 307 | TRACE("OSS info: midi dev-type=%d, capa=%d\n", |
| 308 | minfo.dev_type, minfo.capabilities); |
| 309 | } |
| 310 | |
| 311 | /* windows does not seem to differentiate Synth from MIDI devices */ |
| 312 | MODM_NUMFMSYNTHDEVS = numsynthdevs; |
| 313 | MODM_NUMMIDIDEVS = nummididevs; |
| 314 | MODM_NUMDEVS = numsynthdevs + nummididevs; |
| 315 | |
| 316 | MIDM_NUMDEVS = nummididevs; |
| 317 | |
| 318 | /* close file and exit */ |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 319 | midiCloseSeq(); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 320 | |
| 321 | return TRUE; |
| 322 | } |
| 323 | |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 324 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 325 | * MIDI_NotifyClient [internal] |
| 326 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 327 | static DWORD MIDI_NotifyClient(UINT wDevID, WORD wMsg, |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 328 | DWORD dwParam1, DWORD dwParam2) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 329 | { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 330 | DWORD dwCallBack; |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 331 | UINT uFlags; |
| 332 | HANDLE hDev; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 333 | DWORD dwInstance; |
| 334 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 335 | TRACE("wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n", |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 336 | wDevID, wMsg, dwParam1, dwParam2); |
| 337 | |
| 338 | switch (wMsg) { |
| 339 | case MOM_OPEN: |
| 340 | case MOM_CLOSE: |
| 341 | case MOM_DONE: |
| 342 | if (wDevID > MAX_MIDIOUTDRV) |
| 343 | return MCIERR_INTERNAL; |
| 344 | |
| 345 | dwCallBack = MidiOutDev[wDevID].midiDesc->dwCallback; |
| 346 | uFlags = MidiOutDev[wDevID].wFlags; |
| 347 | hDev = MidiOutDev[wDevID].midiDesc->hMidi; |
| 348 | dwInstance = MidiOutDev[wDevID].midiDesc->dwInstance; |
| 349 | break; |
| 350 | |
| 351 | case MIM_OPEN: |
| 352 | case MIM_CLOSE: |
| 353 | case MIM_DATA: |
| 354 | case MIM_ERROR: |
| 355 | if (wDevID > MAX_MIDIINDRV) |
| 356 | return MCIERR_INTERNAL; |
| 357 | |
| 358 | dwCallBack = MidiInDev[wDevID].midiDesc->dwCallback; |
| 359 | uFlags = MidiInDev[wDevID].wFlags; |
| 360 | hDev = MidiInDev[wDevID].midiDesc->hMidi; |
| 361 | dwInstance = MidiInDev[wDevID].midiDesc->dwInstance; |
| 362 | break; |
| 363 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 364 | WARN("Unsupported MSW-MIDI message %u\n", wMsg); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 365 | return MCIERR_INTERNAL; |
| 366 | } |
| 367 | |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 368 | return DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2) ? |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 369 | 0 : MCIERR_INTERNAL; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 370 | } |
| 371 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 372 | /************************************************************************** |
| 373 | * midiOpenSeq [internal] |
| 374 | */ |
| 375 | static int midiOpenSeq(void) |
| 376 | { |
| 377 | if (numOpenMidiSeq == 0) { |
| 378 | midiSeqFD = open(MIDI_SEQ, O_RDWR, 0); |
| 379 | if (midiSeqFD == -1) { |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 380 | /* don't bark when we're facing a config without midi driver available */ |
| 381 | if (errno != ENODEV && errno != ENXIO) { |
| 382 | ERR("can't open '%s' ! (%d)\n", MIDI_SEQ, errno); |
| 383 | } else { |
| 384 | TRACE("No midi device present\n"); |
| 385 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 386 | return -1; |
| 387 | } |
| 388 | if (fcntl(midiSeqFD, F_SETFL, O_NONBLOCK) < 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 389 | WARN("can't set sequencer fd to non blocking (%d)\n", errno); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 390 | close(midiSeqFD); |
| 391 | midiSeqFD = -1; |
| 392 | return -1; |
| 393 | } |
| 394 | ioctl(midiSeqFD, SNDCTL_SEQ_RESET); |
| 395 | } |
| 396 | numOpenMidiSeq++; |
| 397 | return 0; |
| 398 | } |
| 399 | |
| 400 | /************************************************************************** |
| 401 | * midiCloseSeq [internal] |
| 402 | */ |
| 403 | static int midiCloseSeq(void) |
| 404 | { |
| 405 | if (--numOpenMidiSeq == 0) { |
| 406 | close(midiSeqFD); |
| 407 | midiSeqFD = -1; |
| 408 | } |
| 409 | return 0; |
| 410 | } |
| 411 | |
| 412 | /* FIXME: this is a bad idea, it's even not static... */ |
| 413 | SEQ_DEFINEBUF(1024); |
| 414 | |
| 415 | /* FIXME: this is not reentrant, not static - because of global variable |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 416 | * _seqbuf and al. |
| 417 | */ |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 418 | /************************************************************************** |
| 419 | * seqbuf_dump [internal] |
| 420 | */ |
| 421 | void seqbuf_dump(void) |
| 422 | { |
| 423 | if (_seqbufptr) { |
| 424 | if (write(midiSeqFD, _seqbuf, _seqbufptr) == -1) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 425 | WARN("Can't write data to sequencer (%d/%d)!\n", |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 426 | midiSeqFD, errno); |
| 427 | } |
| 428 | /* FIXME: |
| 429 | * in any case buffer is lost so that if many errors occur the buffer |
| 430 | * will not overrun |
| 431 | */ |
| 432 | _seqbufptr = 0; |
| 433 | } |
| 434 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 435 | |
| 436 | static void midReceiveChar(WORD wDevID, unsigned char value, DWORD dwTime) |
| 437 | { |
| 438 | DWORD toSend = 0; |
| 439 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 440 | TRACE("Adding %02xh to %d[%d]\n", value, wDevID, MidiInDev[wDevID].incLen); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 441 | |
| 442 | if (wDevID >= MAX_MIDIINDRV) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 443 | WARN("bad devID\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 444 | return; |
| 445 | } |
| 446 | if (MidiInDev[wDevID].state == 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 447 | TRACE("input not started, thrown away\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 448 | return; |
| 449 | } |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 450 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 451 | if (MidiInDev[wDevID].state & 2) { /* system exclusive */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 452 | LPMIDIHDR lpMidiHdr = MidiInDev[wDevID].lpQueueHdr; |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 453 | WORD sbfb = FALSE; |
| 454 | |
| 455 | if (lpMidiHdr) { |
Eric Pouech | 322f45c | 1999-09-27 13:35:15 +0000 | [diff] [blame] | 456 | LPBYTE lpData = lpMidiHdr->lpData; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 457 | |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 458 | lpData[lpMidiHdr->dwBytesRecorded++] = value; |
| 459 | if (lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 460 | sbfb = TRUE; |
| 461 | } |
| 462 | } |
| 463 | if (value == 0xF7) { /* then end */ |
| 464 | MidiInDev[wDevID].state &= ~2; |
| 465 | sbfb = TRUE; |
| 466 | } |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 467 | if (sbfb && lpMidiHdr != NULL) { |
| 468 | lpMidiHdr = MidiInDev[wDevID].lpQueueHdr; |
| 469 | lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; |
| 470 | lpMidiHdr->dwFlags |= MHDR_DONE; |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 471 | MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)lpMidiHdr->lpNext; |
Eric Pouech | 322f45c | 1999-09-27 13:35:15 +0000 | [diff] [blame] | 472 | if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD)lpMidiHdr, dwTime) != MMSYSERR_NOERROR) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 473 | WARN("Couldn't notify client\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 474 | } |
| 475 | } |
| 476 | return; |
| 477 | } |
| 478 | |
| 479 | #define IS_CMD(_x) (((_x) & 0x80) == 0x80) |
| 480 | #define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0) |
| 481 | |
| 482 | if (!IS_CMD(value) && MidiInDev[wDevID].incLen == 0) { /* try to reuse old cmd */ |
| 483 | if (IS_CMD(MidiInDev[wDevID].incPrev) && !IS_SYS_CMD(MidiInDev[wDevID].incPrev)) { |
| 484 | MidiInDev[wDevID].incoming[0] = MidiInDev[wDevID].incPrev; |
| 485 | MidiInDev[wDevID].incLen = 1; |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 486 | TRACE("Reusing old command %02xh\n", MidiInDev[wDevID].incPrev); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 487 | } else { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 488 | FIXME("error for midi-in, should generate MIM_ERROR notification:" |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 489 | " prev=%02Xh, incLen=%02Xh\n", |
| 490 | MidiInDev[wDevID].incPrev, MidiInDev[wDevID].incLen); |
| 491 | return; |
| 492 | } |
| 493 | } |
| 494 | MidiInDev[wDevID].incoming[(int)(MidiInDev[wDevID].incLen++)] = value; |
| 495 | if (MidiInDev[wDevID].incLen == 1 && !IS_SYS_CMD(MidiInDev[wDevID].incoming[0])) { |
| 496 | /* store new cmd, just in case */ |
| 497 | MidiInDev[wDevID].incPrev = MidiInDev[wDevID].incoming[0]; |
| 498 | } |
| 499 | |
| 500 | #undef IS_CMD(_x) |
| 501 | #undef IS_SYS_CMD(_x) |
| 502 | |
| 503 | switch (MidiInDev[wDevID].incoming[0] & 0xF0) { |
| 504 | case MIDI_NOTEOFF: |
| 505 | case MIDI_NOTEON: |
| 506 | case MIDI_KEY_PRESSURE: |
| 507 | case MIDI_CTL_CHANGE: |
| 508 | case MIDI_PITCH_BEND: |
| 509 | if (MidiInDev[wDevID].incLen == 3) { |
| 510 | toSend = (MidiInDev[wDevID].incoming[2] << 16) | |
| 511 | (MidiInDev[wDevID].incoming[1] << 8) | |
| 512 | (MidiInDev[wDevID].incoming[0] << 0); |
| 513 | } |
| 514 | break; |
| 515 | case MIDI_PGM_CHANGE: |
| 516 | case MIDI_CHN_PRESSURE: |
| 517 | if (MidiInDev[wDevID].incLen == 2) { |
| 518 | toSend = (MidiInDev[wDevID].incoming[1] << 8) | |
| 519 | (MidiInDev[wDevID].incoming[0] << 0); |
| 520 | } |
| 521 | break; |
| 522 | case MIDI_SYSTEM_PREFIX: |
| 523 | if (MidiInDev[wDevID].incoming[0] == 0xF0) { |
| 524 | MidiInDev[wDevID].state |= 2; |
| 525 | MidiInDev[wDevID].incLen = 0; |
| 526 | } else { |
| 527 | if (MidiInDev[wDevID].incLen == 1) { |
| 528 | toSend = (MidiInDev[wDevID].incoming[0] << 0); |
| 529 | } |
| 530 | } |
| 531 | break; |
| 532 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 533 | WARN("This shouldn't happen (%02X)\n", MidiInDev[wDevID].incoming[0]); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 534 | } |
| 535 | if (toSend != 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 536 | TRACE("Sending event %08lx\n", toSend); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 537 | MidiInDev[wDevID].incLen = 0; |
| 538 | dwTime -= MidiInDev[wDevID].startTime; |
| 539 | if (MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime) != MMSYSERR_NOERROR) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 540 | WARN("Couldn't notify client\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 541 | } |
| 542 | } |
| 543 | } |
| 544 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 545 | static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime) |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 546 | { |
| 547 | unsigned char buffer[256]; |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 548 | int len, idx; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 549 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 550 | TRACE("(%04X, %d, %d, %lu)\n", hwnd, msg, id, dwTime); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 551 | |
| 552 | len = read(midiSeqFD, buffer, sizeof(buffer)); |
| 553 | |
| 554 | if ((len % 4) != 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 555 | WARN("bad length %d (%d)\n", len, errno); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 556 | return; |
| 557 | } |
| 558 | |
| 559 | for (idx = 0; idx < len; ) { |
| 560 | if (buffer[idx] & 0x80) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 561 | TRACE( |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 562 | "reading<8> %02x %02x %02x %02x %02x %02x %02x %02x\n", |
| 563 | buffer[idx + 0], buffer[idx + 1], |
| 564 | buffer[idx + 2], buffer[idx + 3], |
| 565 | buffer[idx + 4], buffer[idx + 5], |
| 566 | buffer[idx + 6], buffer[idx + 7]); |
| 567 | idx += 8; |
| 568 | } else { |
| 569 | switch (buffer[idx + 0]) { |
| 570 | case SEQ_WAIT: |
| 571 | case SEQ_ECHO: |
| 572 | break; |
| 573 | case SEQ_MIDIPUTC: |
| 574 | midReceiveChar(buffer[idx + 2], buffer[idx + 1], dwTime); |
| 575 | break; |
| 576 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 577 | TRACE("Unsupported event %d\n", buffer[idx + 0]); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 578 | break; |
| 579 | } |
| 580 | idx += 4; |
| 581 | } |
| 582 | } |
| 583 | } |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 584 | |
| 585 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 586 | * midGetDevCaps [internal] |
| 587 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 588 | static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPSA lpCaps, DWORD dwSize) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 589 | { |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 590 | LPMIDIINCAPSA tmplpCaps; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 591 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 592 | TRACE("(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 593 | |
| 594 | if (wDevID >= MIDM_NUMDEVS) { |
| 595 | return MMSYSERR_BADDEVICEID; |
| 596 | } |
| 597 | if (lpCaps == NULL) { |
| 598 | return MMSYSERR_INVALPARAM; |
| 599 | } |
| 600 | |
| 601 | tmplpCaps = midiInDevices[wDevID]; |
| 602 | lpCaps->wMid = tmplpCaps->wMid; |
| 603 | lpCaps->wPid = tmplpCaps->wPid; |
| 604 | lpCaps->vDriverVersion = tmplpCaps->vDriverVersion; |
| 605 | strcpy(lpCaps->szPname, tmplpCaps->szPname); |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 606 | if (dwSize == sizeof(MIDIINCAPSA)) { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 607 | /* we should run win 95, so make use of dwSupport */ |
| 608 | lpCaps->dwSupport = tmplpCaps->dwSupport; |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 609 | } else if (dwSize != sizeof(MIDIINCAPSA) - sizeof(DWORD)) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 610 | TRACE("bad size for lpCaps\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 611 | return MMSYSERR_INVALPARAM; |
| 612 | } |
| 613 | |
| 614 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 615 | } |
| 616 | |
| 617 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 618 | * midOpen [internal] |
| 619 | */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 620 | static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 621 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 622 | TRACE("(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 623 | |
| 624 | if (lpDesc == NULL) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 625 | WARN("Invalid Parameter !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 626 | return MMSYSERR_INVALPARAM; |
| 627 | } |
| 628 | /* FIXME : |
| 629 | * how to check that content of lpDesc is correct ? |
| 630 | */ |
| 631 | if (wDevID >= MAX_MIDIINDRV) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 632 | WARN("wDevID too large (%u) !\n", wDevID); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 633 | return MMSYSERR_BADDEVICEID; |
| 634 | } |
| 635 | if (MidiInDev[wDevID].midiDesc != 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 636 | WARN("device already open !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 637 | return MMSYSERR_ALLOCATED; |
| 638 | } |
| 639 | if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 640 | FIXME("No support for MIDI_IO_STATUS in dwFlags\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 641 | return MMSYSERR_INVALFLAG; |
| 642 | } |
| 643 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 644 | if (midiOpenSeq() < 0) { |
| 645 | return MMSYSERR_ERROR; |
| 646 | } |
| 647 | |
| 648 | if (numStartedMidiIn++ == 0) { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 649 | midiInTimerID = SetTimer(0, 0, 250, midTimeCallback); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 650 | if (!midiInTimerID) { |
| 651 | numStartedMidiIn = 0; |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 652 | WARN("Couldn't start timer for midi-in\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 653 | midiCloseSeq(); |
| 654 | return MMSYSERR_ERROR; |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 655 | } |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 656 | TRACE("Starting timer (%u) for midi-in\n", midiInTimerID); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 657 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 658 | |
| 659 | MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 660 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 661 | MidiInDev[wDevID].lpQueueHdr = NULL; |
| 662 | MidiInDev[wDevID].dwTotalPlayed = 0; |
| 663 | MidiInDev[wDevID].bufsize = 0x3FFF; |
| 664 | MidiInDev[wDevID].midiDesc = lpDesc; |
| 665 | MidiInDev[wDevID].state = 0; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 666 | MidiInDev[wDevID].incLen = 0; |
| 667 | MidiInDev[wDevID].startTime = 0; |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 668 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 669 | if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 670 | WARN("can't notify client !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 671 | return MMSYSERR_INVALPARAM; |
| 672 | } |
| 673 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 674 | } |
| 675 | |
| 676 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 677 | * midClose [internal] |
| 678 | */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 679 | static DWORD midClose(WORD wDevID) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 680 | { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 681 | int ret = MMSYSERR_NOERROR; |
| 682 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 683 | TRACE("(%04X);\n", wDevID); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 684 | |
| 685 | if (wDevID >= MAX_MIDIINDRV) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 686 | WARN("wDevID too bif (%u) !\n", wDevID); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 687 | return MMSYSERR_BADDEVICEID; |
| 688 | } |
| 689 | if (MidiInDev[wDevID].midiDesc == 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 690 | WARN("device not opened !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 691 | return MMSYSERR_ERROR; |
| 692 | } |
| 693 | if (MidiInDev[wDevID].lpQueueHdr != 0) { |
| 694 | return MIDIERR_STILLPLAYING; |
| 695 | } |
| 696 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 697 | if (midiSeqFD == -1) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 698 | WARN("ooops !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 699 | return MMSYSERR_ERROR; |
| 700 | } |
| 701 | if (--numStartedMidiIn == 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 702 | TRACE("Stopping timer for midi-in\n"); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 703 | if (!KillTimer(0, midiInTimerID)) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 704 | WARN("Couldn't stop timer for midi-in\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 705 | } |
| 706 | midiInTimerID = 0; |
| 707 | } |
| 708 | midiCloseSeq(); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 709 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 710 | MidiInDev[wDevID].bufsize = 0; |
| 711 | if (MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 712 | WARN("can't notify client !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 713 | ret = MMSYSERR_INVALPARAM; |
| 714 | } |
| 715 | MidiInDev[wDevID].midiDesc = 0; |
| 716 | return ret; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 717 | } |
| 718 | |
| 719 | /************************************************************************** |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 720 | * midAddBuffer [internal] |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 721 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 722 | static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 723 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 724 | TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 725 | |
| 726 | if (lpMidiHdr == NULL) return MMSYSERR_INVALPARAM; |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 727 | if (sizeof(MIDIHDR) > dwSize) return MMSYSERR_INVALPARAM; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 728 | if (lpMidiHdr->dwBufferLength == 0) return MMSYSERR_INVALPARAM; |
| 729 | if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; |
| 730 | if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED; |
| 731 | |
| 732 | if (MidiInDev[wDevID].lpQueueHdr == 0) { |
| 733 | MidiInDev[wDevID].lpQueueHdr = lpMidiHdr; |
| 734 | } else { |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 735 | LPMIDIHDR ptr; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 736 | |
| 737 | for (ptr = MidiInDev[wDevID].lpQueueHdr; |
| 738 | ptr->lpNext != 0; |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 739 | ptr = (LPMIDIHDR)ptr->lpNext); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 740 | ptr->lpNext = (struct midihdr_tag*)lpMidiHdr; |
| 741 | } |
| 742 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 743 | } |
| 744 | |
| 745 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 746 | * midPrepare [internal] |
| 747 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 748 | static DWORD midPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 749 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 750 | TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 751 | |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 752 | if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 || |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 753 | lpMidiHdr->lpData == 0 || lpMidiHdr->dwFlags != 0 || |
| 754 | lpMidiHdr->dwBufferLength >= 0x10000ul) |
| 755 | return MMSYSERR_INVALPARAM; |
| 756 | |
| 757 | lpMidiHdr->lpNext = 0; |
| 758 | lpMidiHdr->dwFlags |= MHDR_PREPARED; |
| 759 | lpMidiHdr->dwBytesRecorded = 0; |
| 760 | |
| 761 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 762 | } |
| 763 | |
| 764 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 765 | * midUnprepare [internal] |
| 766 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 767 | static DWORD midUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 768 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 769 | TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 770 | |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 771 | if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 || |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 772 | lpMidiHdr->lpData == 0 || lpMidiHdr->dwBufferLength >= 0x10000ul) |
| 773 | return MMSYSERR_INVALPARAM; |
| 774 | |
| 775 | if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED; |
| 776 | if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; |
| 777 | |
| 778 | lpMidiHdr->dwFlags &= ~MHDR_PREPARED; |
| 779 | |
| 780 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 781 | } |
| 782 | |
| 783 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 784 | * midReset [internal] |
| 785 | */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 786 | static DWORD midReset(WORD wDevID) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 787 | { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 788 | DWORD dwTime = GetTickCount(); |
| 789 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 790 | TRACE("(%04X);\n", wDevID); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 791 | |
| 792 | while (MidiInDev[wDevID].lpQueueHdr) { |
| 793 | MidiInDev[wDevID].lpQueueHdr->dwFlags &= ~MHDR_INQUEUE; |
| 794 | MidiInDev[wDevID].lpQueueHdr->dwFlags |= MHDR_DONE; |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 795 | /* FIXME: when called from 16 bit, lpQueueHdr needs to be a segmented ptr */ |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 796 | if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, |
| 797 | (DWORD)MidiInDev[wDevID].lpQueueHdr, dwTime) != MMSYSERR_NOERROR) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 798 | WARN("Couldn't notify client\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 799 | } |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 800 | MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)MidiInDev[wDevID].lpQueueHdr->lpNext; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 801 | } |
| 802 | |
| 803 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 804 | } |
| 805 | |
| 806 | |
| 807 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 808 | * midStart [internal] |
| 809 | */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 810 | static DWORD midStart(WORD wDevID) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 811 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 812 | TRACE("(%04X);\n", wDevID); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 813 | |
| 814 | /* FIXME : should test value of wDevID */ |
| 815 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 816 | MidiInDev[wDevID].state = 1; |
| 817 | MidiInDev[wDevID].startTime = GetTickCount(); |
| 818 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 819 | } |
| 820 | |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 821 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 822 | * midStop [internal] |
| 823 | */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 824 | static DWORD midStop(WORD wDevID) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 825 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 826 | TRACE("(%04X);\n", wDevID); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 827 | |
| 828 | /* FIXME : should test value of wDevID */ |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 829 | MidiInDev[wDevID].state = 0; |
| 830 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 831 | } |
| 832 | |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 833 | /*-----------------------------------------------------------------------*/ |
| 834 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 835 | typedef struct sVoice { |
| 836 | int note; /* 0 means not used */ |
| 837 | int channel; |
| 838 | unsigned cntMark : 30, |
| 839 | status : 2; |
| 840 | #define sVS_UNUSED 0 |
| 841 | #define sVS_PLAYING 1 |
| 842 | #define sVS_SUSTAINED 2 |
| 843 | } sVoice; |
| 844 | |
| 845 | typedef struct sChannel { |
| 846 | int program; |
| 847 | |
| 848 | int bender; |
| 849 | int benderRange; |
| 850 | /* controlers */ |
| 851 | int bank; /* CTL_BANK_SELECT */ |
| 852 | int volume; /* CTL_MAIN_VOLUME */ |
| 853 | int balance; /* CTL_BALANCE */ |
| 854 | int expression; /* CTL_EXPRESSION */ |
| 855 | int sustain; /* CTL_SUSTAIN */ |
| 856 | |
| 857 | unsigned char nrgPmtMSB; /* Non register Parameters */ |
| 858 | unsigned char nrgPmtLSB; |
| 859 | unsigned char regPmtMSB; /* Non register Parameters */ |
| 860 | unsigned char regPmtLSB; |
| 861 | } sChannel; |
| 862 | |
| 863 | typedef struct sFMextra { |
| 864 | unsigned counter; |
| 865 | int drumSetMask; |
| 866 | sChannel channel[16]; /* MIDI has only 16 channels */ |
| 867 | sVoice voice[1]; /* dyn allocated according to sound card */ |
| 868 | /* do not append fields below voice[1] since the size of this structure |
| 869 | * depends on the number of available voices on the FM synth... |
| 870 | */ |
| 871 | } sFMextra; |
| 872 | |
| 873 | extern unsigned char midiFMInstrumentPatches[16 * 128]; |
| 874 | extern unsigned char midiFMDrumsPatches [16 * 128]; |
| 875 | |
| 876 | /************************************************************************** |
| 877 | * modFMLoad [internal] |
| 878 | */ |
| 879 | static int modFMLoad(int dev) |
| 880 | { |
| 881 | int i; |
| 882 | struct sbi_instrument sbi; |
| 883 | |
| 884 | sbi.device = dev; |
| 885 | sbi.key = FM_PATCH; |
| 886 | |
| 887 | memset(sbi.operators + 16, 0, 16); |
| 888 | for (i = 0; i < 128; i++) { |
| 889 | sbi.channel = i; |
| 890 | memcpy(sbi.operators, midiFMInstrumentPatches + i * 16, 16); |
| 891 | |
| 892 | if (write(midiSeqFD, (char*)&sbi, sizeof(sbi)) == -1) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 893 | WARN("Couldn't write patch for instrument %d (%d)!\n", sbi.channel, errno); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 894 | return -1; |
| 895 | } |
| 896 | } |
| 897 | for (i = 0; i < 128; i++) { |
| 898 | sbi.channel = 128 + i; |
| 899 | memcpy(sbi.operators, midiFMDrumsPatches + i * 16, 16); |
| 900 | |
| 901 | if (write(midiSeqFD, (char*)&sbi, sizeof(sbi)) == -1) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 902 | WARN("Couldn't write patch for drum %d (%d)!\n", sbi.channel, errno); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 903 | return -1; |
| 904 | } |
| 905 | } |
| 906 | return 0; |
| 907 | } |
| 908 | |
| 909 | /************************************************************************** |
| 910 | * modFMReset [internal] |
| 911 | */ |
| 912 | static void modFMReset(WORD wDevID) |
| 913 | { |
| 914 | sFMextra* extra = (sFMextra*)MidiOutDev[wDevID].lpExtra; |
| 915 | sVoice* voice = extra->voice; |
| 916 | sChannel* channel = extra->channel; |
| 917 | int i; |
| 918 | |
| 919 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 920 | if (voice[i].status != sVS_UNUSED) { |
| 921 | SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64); |
| 922 | } |
| 923 | SEQ_KEY_PRESSURE(wDevID, i, 127, 0); |
| 924 | SEQ_CONTROL(wDevID, i, SEQ_VOLMODE, VOL_METHOD_LINEAR); |
| 925 | voice[i].note = 0; |
| 926 | voice[i].channel = -1; |
| 927 | voice[i].cntMark = 0; |
| 928 | voice[i].status = sVS_UNUSED; |
| 929 | } |
| 930 | for (i = 0; i < 16; i++) { |
| 931 | channel[i].program = 0; |
| 932 | channel[i].bender = 8192; |
| 933 | channel[i].benderRange = 2; |
| 934 | channel[i].bank = 0; |
| 935 | channel[i].volume = 127; |
| 936 | channel[i].balance = 64; |
| 937 | channel[i].expression = 0; |
| 938 | channel[i].sustain = 0; |
| 939 | } |
| 940 | extra->counter = 0; |
| 941 | extra->drumSetMask = 1 << 9; /* channel 10 is normally drums, sometimes 16 also */ |
| 942 | SEQ_DUMPBUF(); |
| 943 | } |
| 944 | |
| 945 | #define IS_DRUM_CHANNEL(_xtra, _chn) ((_xtra)->drumSetMask & (1 << (_chn))) |
| 946 | |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 947 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 948 | * modGetDevCaps [internal] |
| 949 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 950 | static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPSA lpCaps, |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 951 | DWORD dwSize) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 952 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 953 | TRACE("(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 954 | if (wDevID == (WORD) MIDI_MAPPER) { |
Alexandre Julliard | 33072e1 | 1997-06-29 18:08:02 +0000 | [diff] [blame] | 955 | lpCaps->wMid = 0x00FF; /* Manufac ID */ |
| 956 | lpCaps->wPid = 0x0001; /* Product ID */ |
| 957 | lpCaps->vDriverVersion = 0x001; /* Product Version */ |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 958 | strcpy(lpCaps->szPname, "MIDI Mapper (not functional yet)"); |
| 959 | /* FIXME Does it make any difference ? */ |
| 960 | lpCaps->wTechnology = MOD_FMSYNTH; |
| 961 | lpCaps->wVoices = 14; /* FIXME */ |
| 962 | lpCaps->wNotes = 14; /* FIXME */ |
| 963 | /* FIXME Does it make any difference ? */ |
| 964 | lpCaps->dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME; |
| 965 | } else { |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 966 | LPMIDIOUTCAPSA tmplpCaps; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 967 | |
| 968 | if (wDevID >= MODM_NUMDEVS) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 969 | TRACE("MAX_MIDIOUTDRV reached !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 970 | return MMSYSERR_BADDEVICEID; |
| 971 | } |
| 972 | /* FIXME There is a way to do it so easily, but I'm too |
| 973 | * sleepy to think and I want to test |
| 974 | */ |
| 975 | |
| 976 | tmplpCaps = midiOutDevices[wDevID]; |
| 977 | lpCaps->wMid = tmplpCaps->wMid; |
| 978 | lpCaps->wPid = tmplpCaps->wPid; |
| 979 | lpCaps->vDriverVersion = tmplpCaps->vDriverVersion; |
| 980 | strcpy(lpCaps->szPname, tmplpCaps->szPname); |
| 981 | lpCaps->wTechnology = tmplpCaps->wTechnology; |
| 982 | lpCaps->wVoices = tmplpCaps->wVoices; |
| 983 | lpCaps->wNotes = tmplpCaps->wNotes; |
| 984 | lpCaps->dwSupport = tmplpCaps->dwSupport; |
| 985 | } |
| 986 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 987 | } |
| 988 | |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 989 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 990 | * modOpen [internal] |
| 991 | */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 992 | static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags) |
Alexandre Julliard | 7ff1c41 | 1997-05-25 13:58:18 +0000 | [diff] [blame] | 993 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 994 | TRACE("(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 995 | if (lpDesc == NULL) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 996 | WARN("Invalid Parameter !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 997 | return MMSYSERR_INVALPARAM; |
| 998 | } |
| 999 | if (wDevID >= MAX_MIDIOUTDRV) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1000 | TRACE("MAX_MIDIOUTDRV reached !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1001 | return MMSYSERR_BADDEVICEID; |
| 1002 | } |
| 1003 | if (MidiOutDev[wDevID].midiDesc != 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1004 | WARN("device already open !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1005 | return MMSYSERR_ALLOCATED; |
| 1006 | } |
| 1007 | if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1008 | WARN("bad dwFlags\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1009 | return MMSYSERR_INVALFLAG; |
| 1010 | } |
Eric Pouech | 4fa77ce | 1998-11-24 18:31:43 +0000 | [diff] [blame] | 1011 | if (midiOutDevices[wDevID] == NULL) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1012 | TRACE("un-allocated wDevID\n"); |
Eric Pouech | 4fa77ce | 1998-11-24 18:31:43 +0000 | [diff] [blame] | 1013 | return MMSYSERR_BADDEVICEID; |
| 1014 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1015 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1016 | MidiOutDev[wDevID].lpExtra = 0; |
| 1017 | |
| 1018 | switch (midiOutDevices[wDevID]->wTechnology) { |
| 1019 | case MOD_FMSYNTH: |
| 1020 | { |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 1021 | void* extra = HeapAlloc(GetProcessHeap(), 0, |
| 1022 | sizeof(struct sFMextra) + |
| 1023 | sizeof(struct sVoice) * (midiOutDevices[wDevID]->wVoices - 1)); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1024 | |
| 1025 | if (extra == 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1026 | WARN("can't alloc extra data !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1027 | return MMSYSERR_NOMEM; |
| 1028 | } |
| 1029 | MidiOutDev[wDevID].lpExtra = extra; |
| 1030 | if (midiOpenSeq() < 0) { |
| 1031 | MidiOutDev[wDevID].lpExtra = 0; |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 1032 | HeapFree(GetProcessHeap(), 0, extra); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1033 | return MMSYSERR_ERROR; |
| 1034 | } |
| 1035 | if (modFMLoad(wDevID) < 0) { |
| 1036 | midiCloseSeq(); |
| 1037 | MidiOutDev[wDevID].lpExtra = 0; |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 1038 | HeapFree(GetProcessHeap(), 0, extra); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1039 | return MMSYSERR_ERROR; |
| 1040 | } |
| 1041 | modFMReset(wDevID); |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1042 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1043 | break; |
| 1044 | case MOD_MIDIPORT: |
| 1045 | if (midiOpenSeq() < 0) { |
| 1046 | return MMSYSERR_ALLOCATED; |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1047 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1048 | break; |
| 1049 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1050 | WARN("Technology not supported (yet) %d !\n", |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1051 | midiOutDevices[wDevID]->wTechnology); |
| 1052 | return MMSYSERR_NOTENABLED; |
| 1053 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1054 | |
| 1055 | MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1056 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1057 | MidiOutDev[wDevID].lpQueueHdr = NULL; |
| 1058 | MidiOutDev[wDevID].dwTotalPlayed = 0; |
| 1059 | MidiOutDev[wDevID].bufsize = 0x3FFF; |
| 1060 | MidiOutDev[wDevID].midiDesc = lpDesc; |
| 1061 | |
| 1062 | if (MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1063 | WARN("can't notify client !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1064 | return MMSYSERR_INVALPARAM; |
| 1065 | } |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1066 | TRACE("Succesful !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1067 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1068 | } |
| 1069 | |
| 1070 | |
| 1071 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1072 | * modClose [internal] |
| 1073 | */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1074 | static DWORD modClose(WORD wDevID) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1075 | { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1076 | int ret = MMSYSERR_NOERROR; |
| 1077 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1078 | TRACE("(%04X);\n", wDevID); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1079 | |
| 1080 | if (MidiOutDev[wDevID].midiDesc == 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1081 | WARN("device not opened !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1082 | return MMSYSERR_ERROR; |
| 1083 | } |
| 1084 | /* FIXME: should test that no pending buffer is still in the queue for |
| 1085 | * playing */ |
| 1086 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1087 | if (midiSeqFD == -1) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1088 | WARN("can't close !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1089 | return MMSYSERR_ERROR; |
| 1090 | } |
| 1091 | |
| 1092 | switch (midiOutDevices[wDevID]->wTechnology) { |
| 1093 | case MOD_FMSYNTH: |
| 1094 | case MOD_MIDIPORT: |
| 1095 | midiCloseSeq(); |
| 1096 | break; |
| 1097 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1098 | WARN("Technology not supported (yet) %d !\n", |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1099 | midiOutDevices[wDevID]->wTechnology); |
| 1100 | return MMSYSERR_NOTENABLED; |
| 1101 | } |
| 1102 | |
| 1103 | if (MidiOutDev[wDevID].lpExtra != 0) { |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 1104 | HeapFree(GetProcessHeap(), 0, MidiOutDev[wDevID].lpExtra); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1105 | MidiOutDev[wDevID].lpExtra = 0; |
| 1106 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1107 | |
| 1108 | MidiOutDev[wDevID].bufsize = 0; |
| 1109 | if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1110 | WARN("can't notify client !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1111 | ret = MMSYSERR_INVALPARAM; |
| 1112 | } |
| 1113 | MidiOutDev[wDevID].midiDesc = 0; |
| 1114 | return ret; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1115 | } |
| 1116 | |
| 1117 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1118 | * modData [internal] |
| 1119 | */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1120 | static DWORD modData(WORD wDevID, DWORD dwParam) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1121 | { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1122 | WORD evt = LOBYTE(LOWORD(dwParam)); |
| 1123 | WORD d1 = HIBYTE(LOWORD(dwParam)); |
| 1124 | WORD d2 = LOBYTE(HIWORD(dwParam)); |
| 1125 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1126 | TRACE("(%04X, %08lX);\n", wDevID, dwParam); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1127 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1128 | if (midiSeqFD == -1) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1129 | WARN("can't play !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1130 | return MIDIERR_NODEVICE; |
| 1131 | } |
| 1132 | switch (midiOutDevices[wDevID]->wTechnology) { |
| 1133 | case MOD_FMSYNTH: |
| 1134 | /* FIXME: |
| 1135 | * - chorus depth controller is not used |
| 1136 | */ |
| 1137 | { |
| 1138 | sFMextra* extra = (sFMextra*)MidiOutDev[wDevID].lpExtra; |
| 1139 | sVoice* voice = extra->voice; |
| 1140 | sChannel* channel = extra->channel; |
| 1141 | int chn = (evt & 0x0F); |
| 1142 | int i, nv; |
| 1143 | |
| 1144 | switch (evt & 0xF0) { |
| 1145 | case MIDI_NOTEOFF: |
| 1146 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1147 | /* don't stop sustained notes */ |
| 1148 | if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) { |
| 1149 | voice[i].status = sVS_UNUSED; |
| 1150 | SEQ_STOP_NOTE(wDevID, i, d1, d2); |
| 1151 | } |
| 1152 | } |
| 1153 | break; |
| 1154 | case MIDI_NOTEON: |
| 1155 | if (d2 == 0) { /* note off if velocity == 0 */ |
| 1156 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1157 | /* don't stop sustained notes */ |
| 1158 | if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) { |
| 1159 | voice[i].status = sVS_UNUSED; |
| 1160 | SEQ_STOP_NOTE(wDevID, i, d1, 64); |
| 1161 | } |
| 1162 | } |
| 1163 | break; |
| 1164 | } |
| 1165 | /* finding out in this order : |
| 1166 | * - an empty voice |
| 1167 | * - if replaying the same note on the same channel |
| 1168 | * - the older voice (LRU) |
| 1169 | */ |
| 1170 | for (i = nv = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1171 | if (voice[i].status == sVS_UNUSED || |
| 1172 | (voice[i].note == d1 && voice[i].channel == chn)) { |
| 1173 | nv = i; |
| 1174 | break; |
| 1175 | } |
| 1176 | if (voice[i].cntMark < voice[0].cntMark) { |
| 1177 | nv = i; |
| 1178 | } |
| 1179 | } |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1180 | TRACE( |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1181 | "playing on voice=%d, pgm=%d, pan=0x%02X, vol=0x%02X, " |
| 1182 | "bender=0x%02X, note=0x%02X, vel=0x%02X\n", |
| 1183 | nv, channel[chn].program, |
| 1184 | channel[chn].balance, |
| 1185 | channel[chn].volume, |
| 1186 | channel[chn].bender, d1, d2); |
| 1187 | |
| 1188 | SEQ_SET_PATCH(wDevID, nv, IS_DRUM_CHANNEL(extra, chn) ? |
| 1189 | (128 + d1) : channel[chn].program); |
| 1190 | SEQ_BENDER_RANGE(wDevID, nv, channel[chn].benderRange * 100); |
| 1191 | SEQ_BENDER(wDevID, nv, channel[chn].bender); |
| 1192 | SEQ_CONTROL(wDevID, nv, CTL_PAN, channel[chn].balance); |
| 1193 | SEQ_CONTROL(wDevID, nv, CTL_EXPRESSION, channel[chn].expression); |
| 1194 | #if 0 |
| 1195 | /* FIXME: does not really seem to work on my SB card and |
| 1196 | * screws everything up... so lay it down |
| 1197 | */ |
| 1198 | SEQ_CONTROL(wDevID, nv, CTL_MAIN_VOLUME, channel[chn].volume); |
| 1199 | #endif |
| 1200 | SEQ_START_NOTE(wDevID, nv, d1, d2); |
| 1201 | voice[nv].status = channel[chn].sustain ? sVS_SUSTAINED : sVS_PLAYING; |
| 1202 | voice[nv].note = d1; |
| 1203 | voice[nv].channel = chn; |
| 1204 | voice[nv].cntMark = extra->counter++; |
| 1205 | break; |
| 1206 | case MIDI_KEY_PRESSURE: |
| 1207 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1208 | if (voice[i].status != sVS_UNUSED && voice[i].channel == chn && voice[i].note == d1) { |
| 1209 | SEQ_KEY_PRESSURE(wDevID, i, d1, d2); |
| 1210 | } |
| 1211 | } |
| 1212 | break; |
| 1213 | case MIDI_CTL_CHANGE: |
| 1214 | switch (d1) { |
| 1215 | case CTL_BANK_SELECT: channel[chn].bank = d2; break; |
| 1216 | case CTL_MAIN_VOLUME: channel[chn].volume = d2; break; |
| 1217 | case CTL_PAN: channel[chn].balance = d2; break; |
| 1218 | case CTL_EXPRESSION: channel[chn].expression = d2; break; |
| 1219 | case CTL_SUSTAIN: channel[chn].sustain = d2; |
| 1220 | if (d2) { |
| 1221 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1222 | if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) { |
| 1223 | voice[i].status = sVS_SUSTAINED; |
| 1224 | } |
| 1225 | } |
| 1226 | } else { |
| 1227 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1228 | if (voice[i].status == sVS_SUSTAINED && voice[i].channel == chn) { |
| 1229 | voice[i].status = sVS_UNUSED; |
| 1230 | SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64); |
| 1231 | } |
| 1232 | } |
| 1233 | } |
| 1234 | break; |
| 1235 | case CTL_NONREG_PARM_NUM_LSB: channel[chn].nrgPmtLSB = d2; break; |
| 1236 | case CTL_NONREG_PARM_NUM_MSB: channel[chn].nrgPmtMSB = d2; break; |
| 1237 | case CTL_REGIST_PARM_NUM_LSB: channel[chn].regPmtLSB = d2; break; |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 1238 | case CTL_REGIST_PARM_NUM_MSB: channel[chn].regPmtMSB = d2; break; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1239 | case CTL_DATA_ENTRY: |
| 1240 | switch ((channel[chn].regPmtMSB << 8) | channel[chn].regPmtLSB) { |
| 1241 | case 0x0000: |
| 1242 | if (channel[chn].benderRange != d2) { |
| 1243 | channel[chn].benderRange = d2; |
| 1244 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1245 | if (voice[i].channel == chn) { |
| 1246 | SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange); |
| 1247 | } |
| 1248 | } |
| 1249 | } |
| 1250 | break; |
| 1251 | |
| 1252 | case 0x7F7F: |
| 1253 | channel[chn].benderRange = 2; |
| 1254 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1255 | if (voice[i].channel == chn) { |
| 1256 | SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange); |
| 1257 | } |
| 1258 | } |
| 1259 | break; |
| 1260 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1261 | TRACE("Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n", |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1262 | channel[chn].regPmtMSB, channel[chn].regPmtLSB, |
| 1263 | channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB, |
| 1264 | d2); |
| 1265 | break; |
| 1266 | } |
| 1267 | break; |
| 1268 | |
| 1269 | case 0x78: /* all sounds off */ |
Eric Pouech | 4fa77ce | 1998-11-24 18:31:43 +0000 | [diff] [blame] | 1270 | /* FIXME: I don't know if I have to take care of the channel |
| 1271 | * for this control ? |
| 1272 | */ |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1273 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1274 | if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) { |
| 1275 | voice[i].status = sVS_UNUSED; |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 1276 | SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1277 | } |
| 1278 | } |
| 1279 | break; |
| 1280 | case 0x7B: /* all notes off */ |
Eric Pouech | 4fa77ce | 1998-11-24 18:31:43 +0000 | [diff] [blame] | 1281 | /* FIXME: I don't know if I have to take care of the channel |
| 1282 | * for this control ? |
| 1283 | */ |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1284 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1285 | if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) { |
| 1286 | voice[i].status = sVS_UNUSED; |
Eric Pouech | 5be17f7 | 1999-07-15 14:35:37 +0000 | [diff] [blame] | 1287 | SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1288 | } |
| 1289 | } |
| 1290 | break; |
| 1291 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1292 | TRACE("Dropping MIDI control event 0x%02x(%02x) on channel %d\n", |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1293 | d1, d2, chn); |
| 1294 | break; |
| 1295 | } |
| 1296 | break; |
| 1297 | case MIDI_PGM_CHANGE: |
| 1298 | channel[chn].program = d1; |
| 1299 | break; |
| 1300 | case MIDI_CHN_PRESSURE: |
| 1301 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1302 | if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) { |
| 1303 | SEQ_KEY_PRESSURE(wDevID, i, voice[i].note, d1); |
| 1304 | } |
| 1305 | } |
| 1306 | break; |
| 1307 | case MIDI_PITCH_BEND: |
| 1308 | channel[chn].bender = (d2 << 7) + d1; |
| 1309 | for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) { |
| 1310 | if (voice[i].channel == chn) { |
| 1311 | SEQ_BENDER(wDevID, i, channel[chn].bender); |
| 1312 | } |
| 1313 | } |
| 1314 | break; |
| 1315 | case MIDI_SYSTEM_PREFIX: |
| 1316 | switch (evt & 0x0F) { |
| 1317 | case 0x0F: /* Reset */ |
| 1318 | modFMReset(wDevID); |
| 1319 | break; |
| 1320 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1321 | WARN("Unsupported (yet) system event %02x\n", evt & 0x0F); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1322 | } |
| 1323 | break; |
| 1324 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1325 | WARN("Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1326 | return MMSYSERR_NOTENABLED; |
| 1327 | } |
| 1328 | } |
| 1329 | break; |
| 1330 | case MOD_MIDIPORT: |
| 1331 | { |
| 1332 | int dev = wDevID - MODM_NUMFMSYNTHDEVS; |
| 1333 | if (dev < 0) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1334 | WARN("Internal error on devID (%u) !\n", wDevID); |
Alexandre Julliard | ecc3712 | 1994-11-22 16:31:29 +0000 | [diff] [blame] | 1335 | return MIDIERR_NODEVICE; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1336 | } |
| 1337 | |
| 1338 | switch (evt & 0xF0) { |
| 1339 | case MIDI_NOTEOFF: |
| 1340 | case MIDI_NOTEON: |
| 1341 | case MIDI_KEY_PRESSURE: |
| 1342 | case MIDI_CTL_CHANGE: |
| 1343 | case MIDI_PITCH_BEND: |
| 1344 | SEQ_MIDIOUT(dev, evt); |
| 1345 | SEQ_MIDIOUT(dev, d1); |
| 1346 | SEQ_MIDIOUT(dev, d2); |
| 1347 | break; |
| 1348 | case MIDI_PGM_CHANGE: |
| 1349 | case MIDI_CHN_PRESSURE: |
| 1350 | SEQ_MIDIOUT(dev, evt); |
| 1351 | SEQ_MIDIOUT(dev, d1); |
| 1352 | break; |
| 1353 | case MIDI_SYSTEM_PREFIX: |
| 1354 | switch (evt & 0x0F) { |
| 1355 | case 0x00: /* System Exclusive, don't do it on modData, |
| 1356 | * should require modLongData*/ |
| 1357 | case 0x01: /* Undefined */ |
| 1358 | case 0x04: /* Undefined. */ |
| 1359 | case 0x05: /* Undefined. */ |
| 1360 | case 0x07: /* End of Exclusive. */ |
| 1361 | case 0x09: /* Undefined. */ |
| 1362 | case 0x0D: /* Undefined. */ |
| 1363 | break; |
| 1364 | case 0x06: /* Tune Request */ |
| 1365 | case 0x08: /* Timing Clock. */ |
| 1366 | case 0x0A: /* Start. */ |
| 1367 | case 0x0B: /* Continue */ |
| 1368 | case 0x0C: /* Stop */ |
| 1369 | case 0x0E: /* Active Sensing. */ |
| 1370 | SEQ_MIDIOUT(dev, evt); |
| 1371 | break; |
| 1372 | case 0x0F: /* Reset */ |
| 1373 | /* SEQ_MIDIOUT(dev, evt); |
| 1374 | this other way may be better */ |
| 1375 | SEQ_MIDIOUT(dev, MIDI_SYSTEM_PREFIX); |
| 1376 | SEQ_MIDIOUT(dev, 0x7e); |
| 1377 | SEQ_MIDIOUT(dev, 0x7f); |
| 1378 | SEQ_MIDIOUT(dev, 0x09); |
| 1379 | SEQ_MIDIOUT(dev, 0x01); |
| 1380 | SEQ_MIDIOUT(dev, 0xf7); |
| 1381 | break; |
| 1382 | case 0x03: /* Song Select. */ |
| 1383 | SEQ_MIDIOUT(dev, evt); |
| 1384 | SEQ_MIDIOUT(dev, d1); |
| 1385 | case 0x02: /* Song Position Pointer. */ |
| 1386 | SEQ_MIDIOUT(dev, evt); |
| 1387 | SEQ_MIDIOUT(dev, d1); |
| 1388 | SEQ_MIDIOUT(dev, d2); |
| 1389 | } |
| 1390 | break; |
| 1391 | } |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1392 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1393 | break; |
| 1394 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1395 | WARN("Technology not supported (yet) %d !\n", |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1396 | midiOutDevices[wDevID]->wTechnology); |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1397 | return MMSYSERR_NOTENABLED; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1398 | } |
| 1399 | |
| 1400 | SEQ_DUMPBUF(); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1401 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1402 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1403 | } |
| 1404 | |
| 1405 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1406 | * modLongData [internal] |
| 1407 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1408 | static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1409 | { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1410 | int count; |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1411 | LPBYTE lpData; |
| 1412 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1413 | TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1414 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1415 | if (midiSeqFD == -1) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1416 | WARN("can't play !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1417 | return MIDIERR_NODEVICE; |
| 1418 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1419 | |
Eric Pouech | 322f45c | 1999-09-27 13:35:15 +0000 | [diff] [blame] | 1420 | lpData = lpMidiHdr->lpData; |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1421 | |
| 1422 | if (lpData == NULL) |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1423 | return MIDIERR_UNPREPARED; |
| 1424 | if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) |
| 1425 | return MIDIERR_UNPREPARED; |
| 1426 | if (lpMidiHdr->dwFlags & MHDR_INQUEUE) |
| 1427 | return MIDIERR_STILLPLAYING; |
| 1428 | lpMidiHdr->dwFlags &= ~MHDR_DONE; |
| 1429 | lpMidiHdr->dwFlags |= MHDR_INQUEUE; |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 1430 | |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1431 | /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive |
| 1432 | * data, or can it also contain raw MIDI data, to be split up and sent to |
| 1433 | * modShortData() ? |
| 1434 | * If the latest is true, then the following WARNing will fire up |
| 1435 | */ |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1436 | if (lpData[0] != 0xF0 || lpData[lpMidiHdr->dwBufferLength - 1] != 0xF7) { |
| 1437 | WARN("Alledged system exclusive buffer is not correct\n\tPlease report with MIDI file\n"); |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1438 | } |
| 1439 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1440 | TRACE("dwBufferLength=%lu !\n", lpMidiHdr->dwBufferLength); |
| 1441 | TRACE(" %02X %02X %02X ... %02X %02X %02X\n", |
| 1442 | lpData[0], lpData[1], lpData[2], lpData[lpMidiHdr->dwBufferLength-3], |
| 1443 | lpData[lpMidiHdr->dwBufferLength-2], lpData[lpMidiHdr->dwBufferLength-1]); |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1444 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1445 | switch (midiOutDevices[wDevID]->wTechnology) { |
| 1446 | case MOD_FMSYNTH: |
| 1447 | /* FIXME: I don't think there is much to do here */ |
| 1448 | break; |
| 1449 | case MOD_MIDIPORT: |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1450 | if (lpData[0] != 0xF0) { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1451 | /* Send end of System Exclusive */ |
| 1452 | SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 0xF0); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1453 | WARN("Adding missing 0xF0 marker at the begining of " |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1454 | "system exclusive byte stream\n"); |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1455 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1456 | for (count = 0; count < lpMidiHdr->dwBytesRecorded; count++) { |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1457 | SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, lpData[count]); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1458 | } |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1459 | if (lpData[count - 1] != 0xF7) { |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1460 | /* Send end of System Exclusive */ |
| 1461 | SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 0xF7); |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1462 | WARN("Adding missing 0xF7 marker at the end of " |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1463 | "system exclusive byte stream\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1464 | } |
| 1465 | SEQ_DUMPBUF(); |
| 1466 | break; |
| 1467 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1468 | WARN("Technology not supported (yet) %d !\n", |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1469 | midiOutDevices[wDevID]->wTechnology); |
| 1470 | return MMSYSERR_NOTENABLED; |
| 1471 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1472 | |
| 1473 | lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; |
| 1474 | lpMidiHdr->dwFlags |= MHDR_DONE; |
Eric Pouech | 322f45c | 1999-09-27 13:35:15 +0000 | [diff] [blame] | 1475 | if (MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD)lpMidiHdr, 0L) != MMSYSERR_NOERROR) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1476 | WARN("can't notify client !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1477 | return MMSYSERR_INVALPARAM; |
| 1478 | } |
| 1479 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1480 | } |
| 1481 | |
| 1482 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1483 | * modPrepare [internal] |
| 1484 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1485 | static DWORD modPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1486 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1487 | TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1488 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1489 | if (midiSeqFD == -1) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1490 | WARN("can't prepare !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1491 | return MMSYSERR_NOTENABLED; |
| 1492 | } |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1493 | |
| 1494 | /* MS doc says taht dwFlags must be set to zero, but (kinda funny) MS mciseq drivers |
| 1495 | * asks to prepare MIDIHDR which dwFlags != 0. |
| 1496 | * So at least check for the inqueue flag |
| 1497 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1498 | if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 || |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1499 | lpMidiHdr->lpData == 0 || (lpMidiHdr->dwFlags & MHDR_INQUEUE) != 0 || |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1500 | lpMidiHdr->dwBufferLength >= 0x10000ul) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1501 | WARN("%p %p %08lx %d/%ld\n", lpMidiHdr, lpMidiHdr->lpData, |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1502 | lpMidiHdr->dwFlags, sizeof(MIDIHDR), dwSize); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1503 | return MMSYSERR_INVALPARAM; |
Eric Pouech | ec301db | 1999-04-11 12:20:08 +0000 | [diff] [blame] | 1504 | } |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1505 | |
| 1506 | lpMidiHdr->lpNext = 0; |
| 1507 | lpMidiHdr->dwFlags |= MHDR_PREPARED; |
| 1508 | lpMidiHdr->dwFlags &= ~MHDR_DONE; |
| 1509 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1510 | } |
| 1511 | |
| 1512 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1513 | * modUnprepare [internal] |
| 1514 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1515 | static DWORD modUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1516 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1517 | TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize); |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 1518 | |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1519 | if (midiSeqFD == -1) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1520 | WARN("can't unprepare !\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1521 | return MMSYSERR_NOTENABLED; |
| 1522 | } |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1523 | |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1524 | if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0) |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1525 | return MMSYSERR_INVALPARAM; |
| 1526 | if (lpMidiHdr->dwFlags & MHDR_INQUEUE) |
| 1527 | return MIDIERR_STILLPLAYING; |
| 1528 | lpMidiHdr->dwFlags &= ~MHDR_PREPARED; |
| 1529 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1530 | } |
| 1531 | |
| 1532 | /************************************************************************** |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1533 | * modReset [internal] |
| 1534 | */ |
Alexandre Julliard | bd34d4f | 1995-06-20 19:08:12 +0000 | [diff] [blame] | 1535 | static DWORD modReset(WORD wDevID) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1536 | { |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1537 | unsigned chn; |
| 1538 | |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1539 | TRACE("(%04X);\n", wDevID); |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1540 | |
| 1541 | /* stop all notes */ |
| 1542 | /* FIXME: check if 0x78B0 is channel dependant or not. I coded it so that |
| 1543 | * it's channel dependent... |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1544 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1545 | for (chn = 0; chn < 16; chn++) { |
| 1546 | /* turn off every note */ |
| 1547 | modData(wDevID, 0x7800 | MIDI_CTL_CHANGE | chn); |
| 1548 | /* remove sustain on all channels */ |
| 1549 | modData(wDevID, (CTL_SUSTAIN << 8) | MIDI_CTL_CHANGE | chn); |
| 1550 | } |
| 1551 | /* FIXME: the LongData buffers must also be returned to the app */ |
| 1552 | return MMSYSERR_NOERROR; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1553 | } |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1554 | |
| 1555 | #endif /* HAVE_OSS_MIDI */ |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1556 | |
Eric Pouech | 4fa77ce | 1998-11-24 18:31:43 +0000 | [diff] [blame] | 1557 | /*======================================================================* |
| 1558 | * MIDI entry points * |
| 1559 | *======================================================================*/ |
| 1560 | |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1561 | /************************************************************************** |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1562 | * OSS_midMessage [sample driver] |
Brian Joseph Czapiga | 5ef8b17 | 1999-02-14 13:35:52 +0000 | [diff] [blame] | 1563 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1564 | DWORD WINAPI OSS_midMessage(UINT wDevID, UINT wMsg, DWORD dwUser, |
| 1565 | DWORD dwParam1, DWORD dwParam2) |
Brian Joseph Czapiga | 5ef8b17 | 1999-02-14 13:35:52 +0000 | [diff] [blame] | 1566 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1567 | TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n", |
Brian Joseph Czapiga | 5ef8b17 | 1999-02-14 13:35:52 +0000 | [diff] [blame] | 1568 | wDevID, wMsg, dwUser, dwParam1, dwParam2); |
| 1569 | switch (wMsg) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1570 | #ifdef HAVE_OSS_MIDI |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1571 | case DRVM_INIT: |
| 1572 | OSS_MidiInit(); |
| 1573 | /* fall thru */ |
| 1574 | case DRVM_EXIT: |
| 1575 | case DRVM_ENABLE: |
| 1576 | case DRVM_DISABLE: |
| 1577 | /* FIXME: Pretend this is supported */ |
| 1578 | return 0; |
Brian Joseph Czapiga | 5ef8b17 | 1999-02-14 13:35:52 +0000 | [diff] [blame] | 1579 | case MIDM_OPEN: |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1580 | return midOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2); |
Brian Joseph Czapiga | 5ef8b17 | 1999-02-14 13:35:52 +0000 | [diff] [blame] | 1581 | case MIDM_CLOSE: |
| 1582 | return midClose(wDevID); |
| 1583 | case MIDM_ADDBUFFER: |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1584 | return midAddBuffer(wDevID, (LPMIDIHDR)dwParam1, dwParam2); |
Brian Joseph Czapiga | 5ef8b17 | 1999-02-14 13:35:52 +0000 | [diff] [blame] | 1585 | case MIDM_PREPARE: |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1586 | return midPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2); |
Brian Joseph Czapiga | 5ef8b17 | 1999-02-14 13:35:52 +0000 | [diff] [blame] | 1587 | case MIDM_UNPREPARE: |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1588 | return midUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2); |
Brian Joseph Czapiga | 5ef8b17 | 1999-02-14 13:35:52 +0000 | [diff] [blame] | 1589 | case MIDM_GETDEVCAPS: |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1590 | return midGetDevCaps(wDevID, (LPMIDIINCAPSA)dwParam1,dwParam2); |
Brian Joseph Czapiga | 5ef8b17 | 1999-02-14 13:35:52 +0000 | [diff] [blame] | 1591 | case MIDM_GETNUMDEVS: |
| 1592 | return MIDM_NUMDEVS; |
| 1593 | case MIDM_RESET: |
| 1594 | return midReset(wDevID); |
| 1595 | case MIDM_START: |
| 1596 | return midStart(wDevID); |
| 1597 | case MIDM_STOP: |
| 1598 | return midStop(wDevID); |
| 1599 | #endif |
| 1600 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1601 | TRACE("Unsupported message\n"); |
Brian Joseph Czapiga | 5ef8b17 | 1999-02-14 13:35:52 +0000 | [diff] [blame] | 1602 | } |
| 1603 | return MMSYSERR_NOTSUPPORTED; |
| 1604 | } |
| 1605 | |
| 1606 | /************************************************************************** |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1607 | * OSS_modMessage [sample driver] |
Alexandre Julliard | 491502b | 1997-11-01 19:08:16 +0000 | [diff] [blame] | 1608 | */ |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1609 | DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, |
| 1610 | DWORD dwParam1, DWORD dwParam2) |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1611 | { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1612 | TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n", |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1613 | wDevID, wMsg, dwUser, dwParam1, dwParam2); |
Eric Pouech | 9f65a71 | 1998-10-11 14:14:24 +0000 | [diff] [blame] | 1614 | |
| 1615 | switch (wMsg) { |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1616 | #ifdef HAVE_OSS_MIDI |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1617 | case DRVM_INIT: |
| 1618 | OSS_MidiInit(); |
| 1619 | /* fall thru */ |
| 1620 | case DRVM_EXIT: |
| 1621 | case DRVM_ENABLE: |
| 1622 | case DRVM_DISABLE: |
| 1623 | /* FIXME: Pretend this is supported */ |
| 1624 | return 0; |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1625 | case MODM_OPEN: |
| 1626 | return modOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2); |
| 1627 | case MODM_CLOSE: |
| 1628 | return modClose(wDevID); |
| 1629 | case MODM_DATA: |
| 1630 | return modData(wDevID, dwParam1); |
| 1631 | case MODM_LONGDATA: |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1632 | return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1633 | case MODM_PREPARE: |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1634 | return modPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1635 | case MODM_UNPREPARE: |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1636 | return modUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1637 | case MODM_GETDEVCAPS: |
Eric Pouech | ed18ce6 | 1999-09-22 16:44:34 +0000 | [diff] [blame] | 1638 | return modGetDevCaps(wDevID, (LPMIDIOUTCAPSA)dwParam1, dwParam2); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1639 | case MODM_GETNUMDEVS: |
| 1640 | return MODM_NUMDEVS; |
| 1641 | case MODM_GETVOLUME: |
| 1642 | return 0; |
| 1643 | case MODM_SETVOLUME: |
| 1644 | return 0; |
| 1645 | case MODM_RESET: |
| 1646 | return modReset(wDevID); |
Todd Vierling | ecc7669 | 1998-12-15 17:49:02 +0000 | [diff] [blame] | 1647 | #endif |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1648 | default: |
Eric Pouech | 0eacb6f | 1999-05-24 08:21:08 +0000 | [diff] [blame] | 1649 | TRACE("Unsupported message\n"); |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 1650 | } |
| 1651 | return MMSYSERR_NOTSUPPORTED; |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1652 | } |
| 1653 | |
Alexandre Julliard | 3a405ba | 1994-10-30 16:25:19 +0000 | [diff] [blame] | 1654 | /*-----------------------------------------------------------------------*/ |