blob: dd8275b70c6fdf2204c4b2fbd1ce8a4599759c11 [file] [log] [blame]
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001/* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00003/*
Eric Pouech0eacb6f1999-05-24 08:21:08 +00004 * Sample MIDI Wine Driver for Open Sound System (basically Linux)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00005 *
Eric Pouech0eacb6f1999-05-24 08:21:08 +00006 * Copyright 1994 Martin Ayotte
7 * Copyright 1998 Luiz Otavio L. Zorzella (init procedures)
8 * Copyright 1998/1999 Eric POUECH :
Eric Pouech5be17f71999-07-15 14:35:37 +00009 * 98/7 changes for making this MIDI driver work on OSS
Eric Pouech0eacb6f1999-05-24 08:21:08 +000010 * current support is limited to MIDI ports of OSS systems
11 * 98/9 rewriting MCI code for MIDI
Eric Pouech5be17f71999-07-15 14:35:37 +000012 * 98/11 splitted in midi.c and mcimidi.c
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000013 */
14
Alexandre Julliard23946ad1997-06-16 17:43:53 +000015#include <string.h>
Alexandre Julliard7cbe6571995-01-09 18:21:16 +000016#include <unistd.h>
17#include <fcntl.h>
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000018#include <sys/ioctl.h>
Michael Vekslerff5ae3d1999-04-22 15:26:11 +000019#include "winuser.h"
Eric Pouech37c02171999-09-05 16:44:38 +000020#include "mmddk.h"
21#include "oss.h"
Alexandre Julliard3a405ba1994-10-30 16:25:19 +000022#include "driver.h"
Eric Pouech0eacb6f1999-05-24 08:21:08 +000023#include "debugtools.h"
Eric Pouech5be17f71999-07-15 14:35:37 +000024#include "heap.h"
Eric Pouechec301db1999-04-11 12:20:08 +000025#include "ldt.h"
Marcus Meissner61afa331999-02-22 10:16:00 +000026
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000027DEFAULT_DEBUG_CHANNEL(midi)
28
Eric Pouech0eacb6f1999-05-24 08:21:08 +000029#ifdef HAVE_OSS_MIDI
30
Eric Pouech37c02171999-09-05 16:44:38 +000031#define MIDI_SEQ "/dev/sequencer"
32
Eric Pouech9f65a711998-10-11 14:14:24 +000033typedef struct {
Eric Pouech9f65a711998-10-11 14:14:24 +000034 int state;
35 DWORD bufsize;
36 LPMIDIOPENDESC midiDesc;
37 WORD wFlags;
Eric Poueched18ce61999-09-22 16:44:34 +000038 LPMIDIHDR lpQueueHdr;
Eric Pouech9f65a711998-10-11 14:14:24 +000039 DWORD dwTotalPlayed;
Eric Pouech9f65a711998-10-11 14:14:24 +000040 unsigned char incoming[3];
41 unsigned char incPrev;
42 char incLen;
43 DWORD startTime;
Eric Pouech9f65a711998-10-11 14:14:24 +000044} WINE_MIDIIN;
45
46typedef struct {
Eric Pouech9f65a711998-10-11 14:14:24 +000047 int state;
48 DWORD bufsize;
49 LPMIDIOPENDESC midiDesc;
50 WORD wFlags;
Eric Poueched18ce61999-09-22 16:44:34 +000051 LPMIDIHDR lpQueueHdr;
Eric Pouech9f65a711998-10-11 14:14:24 +000052 DWORD dwTotalPlayed;
Eric Pouech9f65a711998-10-11 14:14:24 +000053 void* lpExtra; /* according to port type (MIDI, FM...), extra data when needed */
Eric Pouech9f65a711998-10-11 14:14:24 +000054} WINE_MIDIOUT;
55
Eric Pouech9f65a711998-10-11 14:14:24 +000056static WINE_MIDIIN MidiInDev [MAX_MIDIINDRV ];
57static WINE_MIDIOUT MidiOutDev[MAX_MIDIOUTDRV];
Alexandre Julliard54c27111998-03-29 19:44:57 +000058
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000059/* this is the total number of MIDI out devices found */
Eric Pouech0eacb6f1999-05-24 08:21:08 +000060static int MODM_NUMDEVS = 0;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000061/* this is the number of FM synthetizers (index from 0 to
62 NUMFMSYNTHDEVS - 1) */
Eric Pouech0eacb6f1999-05-24 08:21:08 +000063static int MODM_NUMFMSYNTHDEVS = 0;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000064/* this is the number of Midi ports (index from NUMFMSYNTHDEVS to
65 NUMFMSYNTHDEVS + NUMMIDIDEVS - 1) */
Eric Pouech0eacb6f1999-05-24 08:21:08 +000066static int MODM_NUMMIDIDEVS = 0;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000067
68/* this is the total number of MIDI out devices found */
Eric Pouech0eacb6f1999-05-24 08:21:08 +000069static int MIDM_NUMDEVS = 0;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000070
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000071static int midiSeqFD = -1;
72static int numOpenMidiSeq = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +000073static UINT midiInTimerID = 0;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000074static int numStartedMidiIn = 0;
Alexandre Julliard54c27111998-03-29 19:44:57 +000075
76/* this structure holds pointers with information for each MIDI
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000077 * out device found.
Alexandre Julliard54c27111998-03-29 19:44:57 +000078 */
Eric Poueched18ce61999-09-22 16:44:34 +000079static LPMIDIOUTCAPSA midiOutDevices[MAX_MIDIOUTDRV];
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000080
81/* this structure holds pointers with information for each MIDI
82 * in device found.
83 */
Eric Poueched18ce61999-09-22 16:44:34 +000084static LPMIDIINCAPSA midiInDevices [MAX_MIDIINDRV];
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000085
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 Julliardd30dfd21998-09-27 18:28:36 +000090 */
Alexandre Julliard3a405ba1994-10-30 16:25:19 +000091
Eric Pouech4fa77ce1998-11-24 18:31:43 +000092/*======================================================================*
Eric Pouech0eacb6f1999-05-24 08:21:08 +000093 * Low level MIDI implementation *
Eric Pouech4fa77ce1998-11-24 18:31:43 +000094 *======================================================================*/
Eric Pouech0eacb6f1999-05-24 08:21:08 +000095
Eric Pouech5be17f71999-07-15 14:35:37 +000096static int midiOpenSeq(void);
97static int midiCloseSeq(void);
98
Eric Pouech0eacb6f1999-05-24 08:21:08 +000099/**************************************************************************
100 * unixToWindowsDeviceType [internal]
101 *
102 * return the Windows equivalent to a Unix Device Type
103 *
104 */
105static 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 Pouech0eacb6f1999-05-24 08:21:08 +0000128
129/**************************************************************************
Eric Pouech37c02171999-09-05 16:44:38 +0000130 * OSS_MidiInit [internal]
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000131 *
132 * Initializes the MIDI devices information variables
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000133 */
Eric Poueched18ce61999-09-22 16:44:34 +0000134static BOOL OSS_MidiInit(void)
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000135{
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000136 int i, status, numsynthdevs = 255, nummididevs = 255;
137 struct synth_info sinfo;
138 struct midi_info minfo;
Eric Poueched18ce61999-09-22 16:44:34 +0000139 static BOOL bInitDone = FALSE;
140
141 if (bInitDone)
142 return TRUE;
143
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000144 TRACE("Initializing the MIDI variables.\n");
Eric Poueched18ce61999-09-22 16:44:34 +0000145 bInitDone = TRUE;
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000146
147 /* try to open device */
Eric Pouech5be17f71999-07-15 14:35:37 +0000148 if (midiOpenSeq() == -1) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000149 return TRUE;
150 }
151
152 /* find how many Synth devices are there in the system */
Eric Pouech5be17f71999-07-15 14:35:37 +0000153 status = ioctl(midiSeqFD, SNDCTL_SEQ_NRSYNTHS, &numsynthdevs);
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000154
155 if (status == -1) {
156 ERR("ioctl for nr synth failed.\n");
Eric Pouech5be17f71999-07-15 14:35:37 +0000157 midiCloseSeq();
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000158 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 Poueched18ce61999-09-22 16:44:34 +0000168 LPMIDIOUTCAPSA tmplpCaps;
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000169
170 sinfo.device = i;
Eric Pouech5be17f71999-07-15 14:35:37 +0000171 status = ioctl(midiSeqFD, SNDCTL_SYNTH_INFO, &sinfo);
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000172 if (status == -1) {
173 ERR("ioctl for synth info failed.\n");
Eric Pouech5be17f71999-07-15 14:35:37 +0000174 midiCloseSeq();
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000175 return TRUE;
176 }
177
Eric Poueched18ce61999-09-22 16:44:34 +0000178 tmplpCaps = HeapAlloc(SystemHeap, 0, sizeof(MIDIOUTCAPSA));
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000179 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 Pouech5be17f71999-07-15 14:35:37 +0000225 status = ioctl(midiSeqFD, SNDCTL_SEQ_NRMIDIS, &nummididevs);
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000226 if (status == -1) {
227 ERR("ioctl on nr midi failed.\n");
Eric Pouech5be17f71999-07-15 14:35:37 +0000228 midiCloseSeq();
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000229 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 Poueched18ce61999-09-22 16:44:34 +0000246 LPMIDIOUTCAPSA tmplpOutCaps;
247 LPMIDIINCAPSA tmplpInCaps;
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000248
249 minfo.device = i;
Eric Pouech5be17f71999-07-15 14:35:37 +0000250 status = ioctl(midiSeqFD, SNDCTL_MIDI_INFO, &minfo);
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000251 if (status == -1) {
252 ERR("ioctl on midi info failed.\n");
Eric Pouech5be17f71999-07-15 14:35:37 +0000253 midiCloseSeq();
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000254 return TRUE;
255 }
256
Eric Poueched18ce61999-09-22 16:44:34 +0000257 tmplpOutCaps = HeapAlloc(SystemHeap, 0, sizeof(MIDIOUTCAPSA));
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000258 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 Poueched18ce61999-09-22 16:44:34 +0000283 tmplpInCaps = HeapAlloc(SystemHeap, 0, sizeof(MIDIOUTCAPSA));
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000284 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 Pouech5be17f71999-07-15 14:35:37 +0000319 midiCloseSeq();
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000320
321 return TRUE;
322}
323
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000324/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000325 * MIDI_NotifyClient [internal]
326 */
Eric Poueched18ce61999-09-22 16:44:34 +0000327static DWORD MIDI_NotifyClient(UINT wDevID, WORD wMsg,
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000328 DWORD dwParam1, DWORD dwParam2)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000329{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000330 DWORD dwCallBack;
Eric Poueched18ce61999-09-22 16:44:34 +0000331 UINT uFlags;
332 HANDLE hDev;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000333 DWORD dwInstance;
334
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000335 TRACE("wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000336 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 Pouech0eacb6f1999-05-24 08:21:08 +0000364 WARN("Unsupported MSW-MIDI message %u\n", wMsg);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000365 return MCIERR_INTERNAL;
366 }
367
Eric Poueched18ce61999-09-22 16:44:34 +0000368 return DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2) ?
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000369 0 : MCIERR_INTERNAL;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000370}
371
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000372/**************************************************************************
373 * midiOpenSeq [internal]
374 */
375static int midiOpenSeq(void)
376{
377 if (numOpenMidiSeq == 0) {
378 midiSeqFD = open(MIDI_SEQ, O_RDWR, 0);
379 if (midiSeqFD == -1) {
Eric Poueched18ce61999-09-22 16:44:34 +0000380 /* 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 Julliardd30dfd21998-09-27 18:28:36 +0000386 return -1;
387 }
388 if (fcntl(midiSeqFD, F_SETFL, O_NONBLOCK) < 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000389 WARN("can't set sequencer fd to non blocking (%d)\n", errno);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000390 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 */
403static 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... */
413SEQ_DEFINEBUF(1024);
414
415/* FIXME: this is not reentrant, not static - because of global variable
Eric Pouech5be17f71999-07-15 14:35:37 +0000416 * _seqbuf and al.
417 */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000418/**************************************************************************
419 * seqbuf_dump [internal]
420 */
421void seqbuf_dump(void)
422{
423 if (_seqbufptr) {
424 if (write(midiSeqFD, _seqbuf, _seqbufptr) == -1) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000425 WARN("Can't write data to sequencer (%d/%d)!\n",
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000426 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 Julliardd30dfd21998-09-27 18:28:36 +0000435
436static void midReceiveChar(WORD wDevID, unsigned char value, DWORD dwTime)
437{
438 DWORD toSend = 0;
439
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000440 TRACE("Adding %02xh to %d[%d]\n", value, wDevID, MidiInDev[wDevID].incLen);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000441
442 if (wDevID >= MAX_MIDIINDRV) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000443 WARN("bad devID\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000444 return;
445 }
446 if (MidiInDev[wDevID].state == 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000447 TRACE("input not started, thrown away\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000448 return;
449 }
Eric Pouechec301db1999-04-11 12:20:08 +0000450
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000451 if (MidiInDev[wDevID].state & 2) { /* system exclusive */
Eric Poueched18ce61999-09-22 16:44:34 +0000452 LPMIDIHDR lpMidiHdr = MidiInDev[wDevID].lpQueueHdr;
Eric Pouechec301db1999-04-11 12:20:08 +0000453 WORD sbfb = FALSE;
454
455 if (lpMidiHdr) {
Eric Pouech322f45c1999-09-27 13:35:15 +0000456 LPBYTE lpData = lpMidiHdr->lpData;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000457
Eric Pouechec301db1999-04-11 12:20:08 +0000458 lpData[lpMidiHdr->dwBytesRecorded++] = value;
459 if (lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) {
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000460 sbfb = TRUE;
461 }
462 }
463 if (value == 0xF7) { /* then end */
464 MidiInDev[wDevID].state &= ~2;
465 sbfb = TRUE;
466 }
Eric Pouechec301db1999-04-11 12:20:08 +0000467 if (sbfb && lpMidiHdr != NULL) {
468 lpMidiHdr = MidiInDev[wDevID].lpQueueHdr;
469 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
470 lpMidiHdr->dwFlags |= MHDR_DONE;
Eric Poueched18ce61999-09-22 16:44:34 +0000471 MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
Eric Pouech322f45c1999-09-27 13:35:15 +0000472 if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD)lpMidiHdr, dwTime) != MMSYSERR_NOERROR) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000473 WARN("Couldn't notify client\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000474 }
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 Pouech0eacb6f1999-05-24 08:21:08 +0000486 TRACE("Reusing old command %02xh\n", MidiInDev[wDevID].incPrev);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000487 } else {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000488 FIXME("error for midi-in, should generate MIM_ERROR notification:"
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000489 " 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 Pouech0eacb6f1999-05-24 08:21:08 +0000533 WARN("This shouldn't happen (%02X)\n", MidiInDev[wDevID].incoming[0]);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000534 }
535 if (toSend != 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000536 TRACE("Sending event %08lx\n", toSend);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000537 MidiInDev[wDevID].incLen = 0;
538 dwTime -= MidiInDev[wDevID].startTime;
539 if (MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime) != MMSYSERR_NOERROR) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000540 WARN("Couldn't notify client\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000541 }
542 }
543}
544
Alexandre Julliarda3960291999-02-26 11:11:13 +0000545static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000546{
547 unsigned char buffer[256];
Eric Pouech9f65a711998-10-11 14:14:24 +0000548 int len, idx;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000549
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000550 TRACE("(%04X, %d, %d, %lu)\n", hwnd, msg, id, dwTime);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000551
552 len = read(midiSeqFD, buffer, sizeof(buffer));
553
554 if ((len % 4) != 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000555 WARN("bad length %d (%d)\n", len, errno);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000556 return;
557 }
558
559 for (idx = 0; idx < len; ) {
560 if (buffer[idx] & 0x80) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000561 TRACE(
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000562 "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 Pouech0eacb6f1999-05-24 08:21:08 +0000577 TRACE("Unsupported event %d\n", buffer[idx + 0]);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000578 break;
579 }
580 idx += 4;
581 }
582 }
583}
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000584
585/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000586 * midGetDevCaps [internal]
587 */
Eric Poueched18ce61999-09-22 16:44:34 +0000588static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPSA lpCaps, DWORD dwSize)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000589{
Eric Poueched18ce61999-09-22 16:44:34 +0000590 LPMIDIINCAPSA tmplpCaps;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000591
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000592 TRACE("(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000593
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 Poueched18ce61999-09-22 16:44:34 +0000606 if (dwSize == sizeof(MIDIINCAPSA)) {
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000607 /* we should run win 95, so make use of dwSupport */
608 lpCaps->dwSupport = tmplpCaps->dwSupport;
Eric Poueched18ce61999-09-22 16:44:34 +0000609 } else if (dwSize != sizeof(MIDIINCAPSA) - sizeof(DWORD)) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000610 TRACE("bad size for lpCaps\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000611 return MMSYSERR_INVALPARAM;
612 }
613
614 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000615}
616
617/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000618 * midOpen [internal]
619 */
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000620static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000621{
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000622 TRACE("(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000623
624 if (lpDesc == NULL) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000625 WARN("Invalid Parameter !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000626 return MMSYSERR_INVALPARAM;
627 }
628 /* FIXME :
629 * how to check that content of lpDesc is correct ?
630 */
631 if (wDevID >= MAX_MIDIINDRV) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000632 WARN("wDevID too large (%u) !\n", wDevID);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000633 return MMSYSERR_BADDEVICEID;
634 }
635 if (MidiInDev[wDevID].midiDesc != 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000636 WARN("device already open !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000637 return MMSYSERR_ALLOCATED;
638 }
639 if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000640 FIXME("No support for MIDI_IO_STATUS in dwFlags\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000641 return MMSYSERR_INVALFLAG;
642 }
643
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000644 if (midiOpenSeq() < 0) {
645 return MMSYSERR_ERROR;
646 }
647
648 if (numStartedMidiIn++ == 0) {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000649 midiInTimerID = SetTimer(0, 0, 250, midTimeCallback);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000650 if (!midiInTimerID) {
651 numStartedMidiIn = 0;
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000652 WARN("Couldn't start timer for midi-in\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000653 midiCloseSeq();
654 return MMSYSERR_ERROR;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000655 }
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000656 TRACE("Starting timer (%u) for midi-in\n", midiInTimerID);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000657 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000658
659 MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
Eric Pouechec301db1999-04-11 12:20:08 +0000660
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000661 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 Julliardd30dfd21998-09-27 18:28:36 +0000666 MidiInDev[wDevID].incLen = 0;
667 MidiInDev[wDevID].startTime = 0;
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000668
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000669 if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000670 WARN("can't notify client !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000671 return MMSYSERR_INVALPARAM;
672 }
673 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000674}
675
676/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000677 * midClose [internal]
678 */
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000679static DWORD midClose(WORD wDevID)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000680{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000681 int ret = MMSYSERR_NOERROR;
682
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000683 TRACE("(%04X);\n", wDevID);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000684
685 if (wDevID >= MAX_MIDIINDRV) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000686 WARN("wDevID too bif (%u) !\n", wDevID);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000687 return MMSYSERR_BADDEVICEID;
688 }
689 if (MidiInDev[wDevID].midiDesc == 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000690 WARN("device not opened !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000691 return MMSYSERR_ERROR;
692 }
693 if (MidiInDev[wDevID].lpQueueHdr != 0) {
694 return MIDIERR_STILLPLAYING;
695 }
696
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000697 if (midiSeqFD == -1) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000698 WARN("ooops !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000699 return MMSYSERR_ERROR;
700 }
701 if (--numStartedMidiIn == 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000702 TRACE("Stopping timer for midi-in\n");
Alexandre Julliarda3960291999-02-26 11:11:13 +0000703 if (!KillTimer(0, midiInTimerID)) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000704 WARN("Couldn't stop timer for midi-in\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000705 }
706 midiInTimerID = 0;
707 }
708 midiCloseSeq();
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000709
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000710 MidiInDev[wDevID].bufsize = 0;
711 if (MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000712 WARN("can't notify client !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000713 ret = MMSYSERR_INVALPARAM;
714 }
715 MidiInDev[wDevID].midiDesc = 0;
716 return ret;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000717}
718
719/**************************************************************************
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000720 * midAddBuffer [internal]
Alexandre Julliard491502b1997-11-01 19:08:16 +0000721 */
Eric Poueched18ce61999-09-22 16:44:34 +0000722static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000723{
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000724 TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000725
726 if (lpMidiHdr == NULL) return MMSYSERR_INVALPARAM;
Eric Poueched18ce61999-09-22 16:44:34 +0000727 if (sizeof(MIDIHDR) > dwSize) return MMSYSERR_INVALPARAM;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000728 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 Poueched18ce61999-09-22 16:44:34 +0000735 LPMIDIHDR ptr;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000736
737 for (ptr = MidiInDev[wDevID].lpQueueHdr;
738 ptr->lpNext != 0;
Eric Poueched18ce61999-09-22 16:44:34 +0000739 ptr = (LPMIDIHDR)ptr->lpNext);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000740 ptr->lpNext = (struct midihdr_tag*)lpMidiHdr;
741 }
742 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000743}
744
745/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000746 * midPrepare [internal]
747 */
Eric Poueched18ce61999-09-22 16:44:34 +0000748static DWORD midPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000749{
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000750 TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000751
Eric Poueched18ce61999-09-22 16:44:34 +0000752 if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 ||
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000753 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 Julliard3a405ba1994-10-30 16:25:19 +0000762}
763
764/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000765 * midUnprepare [internal]
766 */
Eric Poueched18ce61999-09-22 16:44:34 +0000767static DWORD midUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000768{
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000769 TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000770
Eric Poueched18ce61999-09-22 16:44:34 +0000771 if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 ||
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000772 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 Julliard3a405ba1994-10-30 16:25:19 +0000781}
782
783/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000784 * midReset [internal]
785 */
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000786static DWORD midReset(WORD wDevID)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000787{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000788 DWORD dwTime = GetTickCount();
789
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000790 TRACE("(%04X);\n", wDevID);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000791
792 while (MidiInDev[wDevID].lpQueueHdr) {
793 MidiInDev[wDevID].lpQueueHdr->dwFlags &= ~MHDR_INQUEUE;
794 MidiInDev[wDevID].lpQueueHdr->dwFlags |= MHDR_DONE;
Eric Pouechec301db1999-04-11 12:20:08 +0000795 /* FIXME: when called from 16 bit, lpQueueHdr needs to be a segmented ptr */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000796 if (MIDI_NotifyClient(wDevID, MIM_LONGDATA,
797 (DWORD)MidiInDev[wDevID].lpQueueHdr, dwTime) != MMSYSERR_NOERROR) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000798 WARN("Couldn't notify client\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000799 }
Eric Poueched18ce61999-09-22 16:44:34 +0000800 MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)MidiInDev[wDevID].lpQueueHdr->lpNext;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000801 }
802
803 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000804}
805
806
807/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000808 * midStart [internal]
809 */
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000810static DWORD midStart(WORD wDevID)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000811{
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000812 TRACE("(%04X);\n", wDevID);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000813
814 /* FIXME : should test value of wDevID */
815
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000816 MidiInDev[wDevID].state = 1;
817 MidiInDev[wDevID].startTime = GetTickCount();
818 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000819}
820
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000821/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000822 * midStop [internal]
823 */
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000824static DWORD midStop(WORD wDevID)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000825{
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000826 TRACE("(%04X);\n", wDevID);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000827
828 /* FIXME : should test value of wDevID */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000829 MidiInDev[wDevID].state = 0;
830 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000831}
832
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000833/*-----------------------------------------------------------------------*/
834
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000835typedef 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
845typedef 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
863typedef 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
873extern unsigned char midiFMInstrumentPatches[16 * 128];
874extern unsigned char midiFMDrumsPatches [16 * 128];
875
876/**************************************************************************
877 * modFMLoad [internal]
878 */
879static 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 Pouech0eacb6f1999-05-24 08:21:08 +0000893 WARN("Couldn't write patch for instrument %d (%d)!\n", sbi.channel, errno);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000894 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 Pouech0eacb6f1999-05-24 08:21:08 +0000902 WARN("Couldn't write patch for drum %d (%d)!\n", sbi.channel, errno);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000903 return -1;
904 }
905 }
906 return 0;
907}
908
909/**************************************************************************
910 * modFMReset [internal]
911 */
912static 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 Julliard3a405ba1994-10-30 16:25:19 +0000947/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000948 * modGetDevCaps [internal]
949 */
Eric Poueched18ce61999-09-22 16:44:34 +0000950static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPSA lpCaps,
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000951 DWORD dwSize)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000952{
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000953 TRACE("(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000954 if (wDevID == (WORD) MIDI_MAPPER) {
Alexandre Julliard33072e11997-06-29 18:08:02 +0000955 lpCaps->wMid = 0x00FF; /* Manufac ID */
956 lpCaps->wPid = 0x0001; /* Product ID */
957 lpCaps->vDriverVersion = 0x001; /* Product Version */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000958 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 Poueched18ce61999-09-22 16:44:34 +0000966 LPMIDIOUTCAPSA tmplpCaps;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000967
968 if (wDevID >= MODM_NUMDEVS) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000969 TRACE("MAX_MIDIOUTDRV reached !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000970 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 Julliard3a405ba1994-10-30 16:25:19 +0000987}
988
Alexandre Julliard3a405ba1994-10-30 16:25:19 +0000989/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000990 * modOpen [internal]
991 */
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +0000992static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000993{
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000994 TRACE("(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000995 if (lpDesc == NULL) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +0000996 WARN("Invalid Parameter !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000997 return MMSYSERR_INVALPARAM;
998 }
999 if (wDevID >= MAX_MIDIOUTDRV) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001000 TRACE("MAX_MIDIOUTDRV reached !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001001 return MMSYSERR_BADDEVICEID;
1002 }
1003 if (MidiOutDev[wDevID].midiDesc != 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001004 WARN("device already open !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001005 return MMSYSERR_ALLOCATED;
1006 }
1007 if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001008 WARN("bad dwFlags\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001009 return MMSYSERR_INVALFLAG;
1010 }
Eric Pouech4fa77ce1998-11-24 18:31:43 +00001011 if (midiOutDevices[wDevID] == NULL) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001012 TRACE("un-allocated wDevID\n");
Eric Pouech4fa77ce1998-11-24 18:31:43 +00001013 return MMSYSERR_BADDEVICEID;
1014 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001015
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001016 MidiOutDev[wDevID].lpExtra = 0;
1017
1018 switch (midiOutDevices[wDevID]->wTechnology) {
1019 case MOD_FMSYNTH:
1020 {
Eric Pouech5be17f71999-07-15 14:35:37 +00001021 void* extra = HeapAlloc(GetProcessHeap(), 0,
1022 sizeof(struct sFMextra) +
1023 sizeof(struct sVoice) * (midiOutDevices[wDevID]->wVoices - 1));
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001024
1025 if (extra == 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001026 WARN("can't alloc extra data !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001027 return MMSYSERR_NOMEM;
1028 }
1029 MidiOutDev[wDevID].lpExtra = extra;
1030 if (midiOpenSeq() < 0) {
1031 MidiOutDev[wDevID].lpExtra = 0;
Eric Pouech5be17f71999-07-15 14:35:37 +00001032 HeapFree(GetProcessHeap(), 0, extra);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001033 return MMSYSERR_ERROR;
1034 }
1035 if (modFMLoad(wDevID) < 0) {
1036 midiCloseSeq();
1037 MidiOutDev[wDevID].lpExtra = 0;
Eric Pouech5be17f71999-07-15 14:35:37 +00001038 HeapFree(GetProcessHeap(), 0, extra);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001039 return MMSYSERR_ERROR;
1040 }
1041 modFMReset(wDevID);
Alexandre Julliard491502b1997-11-01 19:08:16 +00001042 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001043 break;
1044 case MOD_MIDIPORT:
1045 if (midiOpenSeq() < 0) {
1046 return MMSYSERR_ALLOCATED;
Alexandre Julliard491502b1997-11-01 19:08:16 +00001047 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001048 break;
1049 default:
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001050 WARN("Technology not supported (yet) %d !\n",
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001051 midiOutDevices[wDevID]->wTechnology);
1052 return MMSYSERR_NOTENABLED;
1053 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001054
1055 MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
Eric Pouechec301db1999-04-11 12:20:08 +00001056
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001057 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 Pouech0eacb6f1999-05-24 08:21:08 +00001063 WARN("can't notify client !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001064 return MMSYSERR_INVALPARAM;
1065 }
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001066 TRACE("Succesful !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001067 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001068}
1069
1070
1071/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +00001072 * modClose [internal]
1073 */
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00001074static DWORD modClose(WORD wDevID)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001075{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001076 int ret = MMSYSERR_NOERROR;
1077
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001078 TRACE("(%04X);\n", wDevID);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001079
1080 if (MidiOutDev[wDevID].midiDesc == 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001081 WARN("device not opened !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001082 return MMSYSERR_ERROR;
1083 }
1084 /* FIXME: should test that no pending buffer is still in the queue for
1085 * playing */
1086
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001087 if (midiSeqFD == -1) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001088 WARN("can't close !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001089 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 Pouech0eacb6f1999-05-24 08:21:08 +00001098 WARN("Technology not supported (yet) %d !\n",
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001099 midiOutDevices[wDevID]->wTechnology);
1100 return MMSYSERR_NOTENABLED;
1101 }
1102
1103 if (MidiOutDev[wDevID].lpExtra != 0) {
Eric Pouech5be17f71999-07-15 14:35:37 +00001104 HeapFree(GetProcessHeap(), 0, MidiOutDev[wDevID].lpExtra);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001105 MidiOutDev[wDevID].lpExtra = 0;
1106 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001107
1108 MidiOutDev[wDevID].bufsize = 0;
1109 if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001110 WARN("can't notify client !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001111 ret = MMSYSERR_INVALPARAM;
1112 }
1113 MidiOutDev[wDevID].midiDesc = 0;
1114 return ret;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001115}
1116
1117/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +00001118 * modData [internal]
1119 */
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00001120static DWORD modData(WORD wDevID, DWORD dwParam)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001121{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001122 WORD evt = LOBYTE(LOWORD(dwParam));
1123 WORD d1 = HIBYTE(LOWORD(dwParam));
1124 WORD d2 = LOBYTE(HIWORD(dwParam));
1125
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001126 TRACE("(%04X, %08lX);\n", wDevID, dwParam);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001127
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001128 if (midiSeqFD == -1) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001129 WARN("can't play !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001130 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 Pouech0eacb6f1999-05-24 08:21:08 +00001180 TRACE(
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001181 "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 Pouech5be17f71999-07-15 14:35:37 +00001238 case CTL_REGIST_PARM_NUM_MSB: channel[chn].regPmtMSB = d2; break;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001239 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 Pouech0eacb6f1999-05-24 08:21:08 +00001261 TRACE("Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n",
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001262 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 Pouech4fa77ce1998-11-24 18:31:43 +00001270 /* FIXME: I don't know if I have to take care of the channel
1271 * for this control ?
1272 */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001273 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 Pouech5be17f71999-07-15 14:35:37 +00001276 SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001277 }
1278 }
1279 break;
1280 case 0x7B: /* all notes off */
Eric Pouech4fa77ce1998-11-24 18:31:43 +00001281 /* FIXME: I don't know if I have to take care of the channel
1282 * for this control ?
1283 */
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001284 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 Pouech5be17f71999-07-15 14:35:37 +00001287 SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001288 }
1289 }
1290 break;
1291 default:
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001292 TRACE("Dropping MIDI control event 0x%02x(%02x) on channel %d\n",
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001293 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 Pouech0eacb6f1999-05-24 08:21:08 +00001321 WARN("Unsupported (yet) system event %02x\n", evt & 0x0F);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001322 }
1323 break;
1324 default:
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001325 WARN("Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001326 return MMSYSERR_NOTENABLED;
1327 }
1328 }
1329 break;
1330 case MOD_MIDIPORT:
1331 {
1332 int dev = wDevID - MODM_NUMFMSYNTHDEVS;
1333 if (dev < 0) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001334 WARN("Internal error on devID (%u) !\n", wDevID);
Alexandre Julliardecc37121994-11-22 16:31:29 +00001335 return MIDIERR_NODEVICE;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001336 }
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 Julliard491502b1997-11-01 19:08:16 +00001392 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001393 break;
1394 default:
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001395 WARN("Technology not supported (yet) %d !\n",
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001396 midiOutDevices[wDevID]->wTechnology);
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001397 return MMSYSERR_NOTENABLED;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001398 }
1399
1400 SEQ_DUMPBUF();
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001401
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001402 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001403}
1404
1405/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +00001406 * modLongData [internal]
1407 */
Eric Poueched18ce61999-09-22 16:44:34 +00001408static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001409{
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001410 int count;
Eric Pouechec301db1999-04-11 12:20:08 +00001411 LPBYTE lpData;
1412
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001413 TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001414
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001415 if (midiSeqFD == -1) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001416 WARN("can't play !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001417 return MIDIERR_NODEVICE;
1418 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001419
Eric Pouech322f45c1999-09-27 13:35:15 +00001420 lpData = lpMidiHdr->lpData;
Eric Pouechec301db1999-04-11 12:20:08 +00001421
1422 if (lpData == NULL)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001423 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 Pouech9f65a711998-10-11 14:14:24 +00001430
Eric Pouechec301db1999-04-11 12:20:08 +00001431 /* 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 Pouech0eacb6f1999-05-24 08:21:08 +00001436 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 Pouechec301db1999-04-11 12:20:08 +00001438 }
1439
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001440 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 Pouechec301db1999-04-11 12:20:08 +00001444
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001445 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 Pouechec301db1999-04-11 12:20:08 +00001450 if (lpData[0] != 0xF0) {
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001451 /* Send end of System Exclusive */
1452 SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 0xF0);
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001453 WARN("Adding missing 0xF0 marker at the begining of "
Eric Pouechec301db1999-04-11 12:20:08 +00001454 "system exclusive byte stream\n");
Alexandre Julliard491502b1997-11-01 19:08:16 +00001455 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001456 for (count = 0; count < lpMidiHdr->dwBytesRecorded; count++) {
Eric Pouechec301db1999-04-11 12:20:08 +00001457 SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, lpData[count]);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001458 }
Eric Pouechec301db1999-04-11 12:20:08 +00001459 if (lpData[count - 1] != 0xF7) {
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001460 /* Send end of System Exclusive */
1461 SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 0xF7);
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001462 WARN("Adding missing 0xF7 marker at the end of "
Eric Pouechec301db1999-04-11 12:20:08 +00001463 "system exclusive byte stream\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001464 }
1465 SEQ_DUMPBUF();
1466 break;
1467 default:
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001468 WARN("Technology not supported (yet) %d !\n",
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001469 midiOutDevices[wDevID]->wTechnology);
1470 return MMSYSERR_NOTENABLED;
1471 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001472
1473 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1474 lpMidiHdr->dwFlags |= MHDR_DONE;
Eric Pouech322f45c1999-09-27 13:35:15 +00001475 if (MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD)lpMidiHdr, 0L) != MMSYSERR_NOERROR) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001476 WARN("can't notify client !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001477 return MMSYSERR_INVALPARAM;
1478 }
1479 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001480}
1481
1482/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +00001483 * modPrepare [internal]
1484 */
Eric Poueched18ce61999-09-22 16:44:34 +00001485static DWORD modPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001486{
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001487 TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001488
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001489 if (midiSeqFD == -1) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001490 WARN("can't prepare !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001491 return MMSYSERR_NOTENABLED;
1492 }
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001493
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 Poueched18ce61999-09-22 16:44:34 +00001498 if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 ||
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001499 lpMidiHdr->lpData == 0 || (lpMidiHdr->dwFlags & MHDR_INQUEUE) != 0 ||
Eric Pouechec301db1999-04-11 12:20:08 +00001500 lpMidiHdr->dwBufferLength >= 0x10000ul) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001501 WARN("%p %p %08lx %d/%ld\n", lpMidiHdr, lpMidiHdr->lpData,
Eric Poueched18ce61999-09-22 16:44:34 +00001502 lpMidiHdr->dwFlags, sizeof(MIDIHDR), dwSize);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001503 return MMSYSERR_INVALPARAM;
Eric Pouechec301db1999-04-11 12:20:08 +00001504 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001505
1506 lpMidiHdr->lpNext = 0;
1507 lpMidiHdr->dwFlags |= MHDR_PREPARED;
1508 lpMidiHdr->dwFlags &= ~MHDR_DONE;
1509 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001510}
1511
1512/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +00001513 * modUnprepare [internal]
1514 */
Eric Poueched18ce61999-09-22 16:44:34 +00001515static DWORD modUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001516{
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001517 TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
Eric Pouech9f65a711998-10-11 14:14:24 +00001518
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001519 if (midiSeqFD == -1) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001520 WARN("can't unprepare !\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001521 return MMSYSERR_NOTENABLED;
1522 }
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001523
Eric Poueched18ce61999-09-22 16:44:34 +00001524 if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001525 return MMSYSERR_INVALPARAM;
1526 if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
1527 return MIDIERR_STILLPLAYING;
1528 lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
1529 return MMSYSERR_NOERROR;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001530}
1531
1532/**************************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +00001533 * modReset [internal]
1534 */
Alexandre Julliardbd34d4f1995-06-20 19:08:12 +00001535static DWORD modReset(WORD wDevID)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001536{
Eric Poueched18ce61999-09-22 16:44:34 +00001537 unsigned chn;
1538
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001539 TRACE("(%04X);\n", wDevID);
Eric Poueched18ce61999-09-22 16:44:34 +00001540
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 Julliardd30dfd21998-09-27 18:28:36 +00001544 */
Eric Poueched18ce61999-09-22 16:44:34 +00001545 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 Julliard3a405ba1994-10-30 16:25:19 +00001553}
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001554
1555#endif /* HAVE_OSS_MIDI */
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001556
Eric Pouech4fa77ce1998-11-24 18:31:43 +00001557/*======================================================================*
1558 * MIDI entry points *
1559 *======================================================================*/
1560
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001561/**************************************************************************
Eric Poueched18ce61999-09-22 16:44:34 +00001562 * OSS_midMessage [sample driver]
Brian Joseph Czapiga5ef8b171999-02-14 13:35:52 +00001563 */
Eric Poueched18ce61999-09-22 16:44:34 +00001564DWORD WINAPI OSS_midMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
1565 DWORD dwParam1, DWORD dwParam2)
Brian Joseph Czapiga5ef8b171999-02-14 13:35:52 +00001566{
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001567 TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n",
Brian Joseph Czapiga5ef8b171999-02-14 13:35:52 +00001568 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1569 switch (wMsg) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001570#ifdef HAVE_OSS_MIDI
Eric Poueched18ce61999-09-22 16:44:34 +00001571 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 Czapiga5ef8b171999-02-14 13:35:52 +00001579 case MIDM_OPEN:
Eric Poueched18ce61999-09-22 16:44:34 +00001580 return midOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
Brian Joseph Czapiga5ef8b171999-02-14 13:35:52 +00001581 case MIDM_CLOSE:
1582 return midClose(wDevID);
1583 case MIDM_ADDBUFFER:
Eric Poueched18ce61999-09-22 16:44:34 +00001584 return midAddBuffer(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Brian Joseph Czapiga5ef8b171999-02-14 13:35:52 +00001585 case MIDM_PREPARE:
Eric Poueched18ce61999-09-22 16:44:34 +00001586 return midPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Brian Joseph Czapiga5ef8b171999-02-14 13:35:52 +00001587 case MIDM_UNPREPARE:
Eric Poueched18ce61999-09-22 16:44:34 +00001588 return midUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Brian Joseph Czapiga5ef8b171999-02-14 13:35:52 +00001589 case MIDM_GETDEVCAPS:
Eric Poueched18ce61999-09-22 16:44:34 +00001590 return midGetDevCaps(wDevID, (LPMIDIINCAPSA)dwParam1,dwParam2);
Brian Joseph Czapiga5ef8b171999-02-14 13:35:52 +00001591 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 Pouech0eacb6f1999-05-24 08:21:08 +00001601 TRACE("Unsupported message\n");
Brian Joseph Czapiga5ef8b171999-02-14 13:35:52 +00001602 }
1603 return MMSYSERR_NOTSUPPORTED;
1604}
1605
1606/**************************************************************************
Eric Poueched18ce61999-09-22 16:44:34 +00001607 * OSS_modMessage [sample driver]
Alexandre Julliard491502b1997-11-01 19:08:16 +00001608 */
Eric Poueched18ce61999-09-22 16:44:34 +00001609DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
1610 DWORD dwParam1, DWORD dwParam2)
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001611{
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001612 TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n",
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001613 wDevID, wMsg, dwUser, dwParam1, dwParam2);
Eric Pouech9f65a711998-10-11 14:14:24 +00001614
1615 switch (wMsg) {
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001616#ifdef HAVE_OSS_MIDI
Eric Poueched18ce61999-09-22 16:44:34 +00001617 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 Julliardd30dfd21998-09-27 18:28:36 +00001625 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 Poueched18ce61999-09-22 16:44:34 +00001632 return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001633 case MODM_PREPARE:
Eric Poueched18ce61999-09-22 16:44:34 +00001634 return modPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001635 case MODM_UNPREPARE:
Eric Poueched18ce61999-09-22 16:44:34 +00001636 return modUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001637 case MODM_GETDEVCAPS:
Eric Poueched18ce61999-09-22 16:44:34 +00001638 return modGetDevCaps(wDevID, (LPMIDIOUTCAPSA)dwParam1, dwParam2);
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001639 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 Vierlingecc76691998-12-15 17:49:02 +00001647#endif
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001648 default:
Eric Pouech0eacb6f1999-05-24 08:21:08 +00001649 TRACE("Unsupported message\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001650 }
1651 return MMSYSERR_NOTSUPPORTED;
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001652}
1653
Alexandre Julliard3a405ba1994-10-30 16:25:19 +00001654/*-----------------------------------------------------------------------*/