midi.c 53.2 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2
/* -*- tab-width: 8; c-basic-offset: 4 -*- */

Alexandre Julliard's avatar
Alexandre Julliard committed
3
/*
4
 * Sample MIDI Wine Driver for Open Sound System (basically Linux)
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 *
6 7
 * Copyright 1994 	Martin Ayotte
 * Copyright 1998 	Luiz Otavio L. Zorzella (init procedures)
8
 * Copyright 1998/1999	Eric POUECH :
9
 * 		98/7 	changes for making this MIDI driver work on OSS
10 11
 * 			current support is limited to MIDI ports of OSS systems
 * 		98/9	rewriting MCI code for MIDI
12
 * 		98/11 	split in midi.c and mcimidi.c
13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
26
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
27 28
 */

29 30 31 32 33 34 35 36 37 38 39 40 41
/* TODO:
 *    + use better instrument definition for OPL/2 (midiPatch.c) or
 *      use existing instrument definition (from playmidi or kmid)
 *      with a .winerc option 
 *    + have a look at OPL/3 ?
 *    + implement asynchronous playback of MidiHdr
 *    + implement STREAM'ed MidiHdr (question: how shall we share the
 *      code between the midiStream functions in MMSYSTEM/WINMM and
 *      the code for the low level driver)
 *    + use a more accurate read mechanism than the one of snooping on
 *      timers (like select on fd)
 */

42
#include "config.h"
43
#include "wine/port.h"
44

45
#include <stdlib.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
46
#include <string.h>
47
#include <stdarg.h>
48
#include <stdio.h>
49 50 51
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
52
#include <fcntl.h>
53
#include <errno.h>
54 55 56
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
57 58 59
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
60 61 62
#ifdef HAVE_SYS_POLL_H
#include <sys/poll.h>
#endif
63

64
#include "windef.h"
65
#include "winbase.h"
66
#include "wingdi.h"
67
#include "winuser.h"
68
#include "winnls.h"
69 70
#include "mmddk.h"
#include "oss.h"
71
#include "wine/unicode.h"
72
#include "wine/debug.h"
73

74
WINE_DEFAULT_DEBUG_CHANNEL(midi);
75

76 77 78 79
#ifdef SNDCTL_SEQ_NRMIDIS
#define HAVE_OSS_MIDI
#endif

80 81
#ifdef HAVE_OSS_MIDI

82
typedef struct {
83
    int			state;                  /* -1 disabled, 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */
84
    DWORD		bufsize;
85
    MIDIOPENDESC	midiDesc;
86
    WORD		wFlags;
87
    LPMIDIHDR	 	lpQueueHdr;
88 89 90 91 92
    DWORD		dwTotalPlayed;
    unsigned char	incoming[3];
    unsigned char	incPrev;
    char		incLen;
    DWORD		startTime;
93
    MIDIINCAPSW         caps;
94 95 96
} WINE_MIDIIN;

typedef struct {
97
    BOOL                bEnabled;
98
    DWORD		bufsize;
99
    MIDIOPENDESC	midiDesc;
100
    WORD		wFlags;
101
    LPMIDIHDR	 	lpQueueHdr;
102 103
    DWORD		dwTotalPlayed;
    void*		lpExtra;	 	/* according to port type (MIDI, FM...), extra data when needed */
104
    MIDIOUTCAPSW        caps;
105 106 107 108
} WINE_MIDIOUT;

static WINE_MIDIIN	MidiInDev [MAX_MIDIINDRV ];
static WINE_MIDIOUT	MidiOutDev[MAX_MIDIOUTDRV];
Alexandre Julliard's avatar
Alexandre Julliard committed
109

110 111
/* this is the total number of MIDI out devices found (synth and port) */
static	int 		MODM_NumDevs = 0;
Austin English's avatar
Austin English committed
112
/* this is the number of FM synthesizers (index from 0 to NUMFMSYNTHDEVS - 1) */
113 114
static	int		MODM_NumFMSynthDevs = 0;
/* the Midi ports have index from NUMFMSYNTHDEVS to NumDevs - 1 */
Alexandre Julliard's avatar
Alexandre Julliard committed
115 116

/* this is the total number of MIDI out devices found */
117
static	int 		MIDM_NumDevs = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
118 119 120 121 122

static	int		midiSeqFD = -1;
static	int		numOpenMidiSeq = 0;
static	int		numStartedMidiIn = 0;

123 124 125 126 127
static CRITICAL_SECTION crit_sect;   /* protects all MidiIn buffers queues */
static CRITICAL_SECTION_DEBUG critsect_debug =
{
    0, 0, &crit_sect,
    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
128
      0, 0, { (DWORD_PTR)(__FILE__ ": crit_sect") }
129 130 131 132 133 134
};
static CRITICAL_SECTION crit_sect = { &critsect_debug, -1, 0, 0, 0, 0 };

static int end_thread;
static HANDLE hThread;

135
/*======================================================================*
136
 *                  Low level MIDI implementation			*
137
 *======================================================================*/
138

139 140 141
static int midiOpenSeq(void);
static int midiCloseSeq(void);

142
/**************************************************************************
143
 * 			MIDI_unixToWindowsDeviceType  		[internal]
144 145 146 147 148 149
 *
 * return the Windows equivalent to a Unix Device Type
 *
 */
static	int 	MIDI_UnixToWindowsDeviceType(int type)
{
150 151 152 153
    /* MOD_MIDIPORT     output port
     * MOD_SYNTH        generic internal synth
     * MOD_SQSYNTH      square wave internal synth
     * MOD_FMSYNTH      FM internal synth
154
     * MOD_MAPPER       MIDI mapper
Christian Costa's avatar
Christian Costa committed
155 156
     * MOD_WAVETABLE    hardware watetable internal synth
     * MOD_SWSYNTH      software internal synth
157
     */
158 159

    /* FIXME Is this really the correct equivalence from UNIX to
160
       Windows Sound type */
161

162 163 164 165 166 167 168 169 170 171 172 173
    switch (type) {
    case SYNTH_TYPE_FM:     return MOD_FMSYNTH;
    case SYNTH_TYPE_SAMPLE: return MOD_SYNTH;
    case SYNTH_TYPE_MIDI:   return MOD_MIDIPORT;
    default:
	ERR("Cannot determine the type of this midi device. "
	    "Assuming FM Synth\n");
	return MOD_FMSYNTH;
    }
}

/**************************************************************************
174
 * 			OSS_MidiInit				[internal]
175 176 177
 *
 * Initializes the MIDI devices information variables
 */
178
LRESULT OSS_MidiInit(void)
179 180 181 182
{
    int 		i, status, numsynthdevs = 255, nummididevs = 255;
    struct synth_info 	sinfo;
    struct midi_info 	minfo;
183 184 185
    static	BOOL	bInitDone = FALSE;

    if (bInitDone)
186
	return 0;
187

188
    TRACE("Initializing the MIDI variables.\n");
189
    bInitDone = TRUE;
190

191
    /* try to open device */
192
    if (midiOpenSeq() == -1) {
193
	return -1;
194
    }
195

196
    /* find how many Synth devices are there in the system */
197
    status = ioctl(midiSeqFD, SNDCTL_SEQ_NRSYNTHS, &numsynthdevs);
198

199 200
    if (status == -1) {
	ERR("ioctl for nr synth failed.\n");
201
	midiCloseSeq();
202
	return -1;
203 204 205 206 207 208 209
    }

    if (numsynthdevs > MAX_MIDIOUTDRV) {
	ERR("MAX_MIDIOUTDRV (%d) was enough for the number of devices (%d). "
	    "Some FM devices will not be available.\n",MAX_MIDIOUTDRV,numsynthdevs);
	numsynthdevs = MAX_MIDIOUTDRV;
    }
210

211 212 213 214 215
    for (i = 0; i < numsynthdevs; i++) {
	/* Manufac ID. We do not have access to this with soundcard.h
	 * Does not seem to be a problem, because in mmsystem.h only
	 * Microsoft's ID is listed.
	 */
216 217
	MidiOutDev[i].caps.wMid = 0x00FF;
	MidiOutDev[i].caps.wPid = 0x0001; 	/* FIXME Product ID  */
218
	/* Product Version. We simply say "1" */
219 220
	MidiOutDev[i].caps.vDriverVersion = 0x001;
	MidiOutDev[i].caps.wChannelMask   = 0xFFFF;
221

222 223 224 225 226
	/* FIXME Do we have this information?
	 * Assuming the soundcards can handle
	 * MIDICAPS_VOLUME and MIDICAPS_LRVOLUME but
	 * not MIDICAPS_CACHE.
	 */
227 228 229 230 231
	MidiOutDev[i].caps.dwSupport      = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;

	sinfo.device = i;
	status = ioctl(midiSeqFD, SNDCTL_SYNTH_INFO, &sinfo);
	if (status == -1) {
232
            static const WCHAR fmt[] = {'W','i','n','e',' ','O','S','S',' ','M','i','d','i',' ','O','u','t',' ','(','#','%','d',')',' ','d','i','s','a','b','l','e','d',0};
233 234
	    ERR("ioctl for synth info failed on %d, disabling it.\n", i);

235
            wsprintfW(MidiOutDev[i].caps.szPname, fmt, i);
236 237 238 239 240 241

            MidiOutDev[i].caps.wTechnology = MOD_MIDIPORT;
            MidiOutDev[i].caps.wVoices     = 16;
            MidiOutDev[i].caps.wNotes      = 16;
            MidiOutDev[i].bEnabled = FALSE;
	} else {
242
            MultiByteToWideChar( CP_UNIXCP, 0, sinfo.name, -1,
243 244
                                 MidiOutDev[i].caps.szPname,
                                 sizeof(MidiOutDev[i].caps.szPname)/sizeof(WCHAR) );
245

246 247 248 249 250 251 252 253 254 255 256 257 258 259
            MidiOutDev[i].caps.wTechnology = MIDI_UnixToWindowsDeviceType(sinfo.synth_type);
            MidiOutDev[i].caps.wVoices     = sinfo.nr_voices;

            /* FIXME Is it possible to know the maximum
             * number of simultaneous notes of a soundcard ?
             * I believe we don't have this information, but
             * it's probably equal or more than wVoices
             */
            MidiOutDev[i].caps.wNotes      = sinfo.nr_voices;
            MidiOutDev[i].bEnabled = TRUE;
        }

	/* We also have the information sinfo.synth_subtype, not used here
	 */
260

261
	if (sinfo.capabilities & SYNTH_CAP_INPUT) {
262
	    FIXME("Synthesizer supports MIDI in. Not yet supported.\n");
263
	}
264

265 266
	TRACE("SynthOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%d\n"
              "\tOSS info: synth subtype=%d capa=%lx\n",
267 268
	      i, wine_dbgstr_w(MidiOutDev[i].caps.szPname), 
              MidiOutDev[i].caps.wTechnology, 
269 270
              MidiOutDev[i].caps.wVoices, MidiOutDev[i].caps.wNotes, 
              MidiOutDev[i].caps.wChannelMask, MidiOutDev[i].caps.dwSupport,
Gerald Pfeifer's avatar
Gerald Pfeifer committed
271
	      sinfo.synth_subtype, (long)sinfo.capabilities);
272
    }
273

274
    /* find how many MIDI devices are there in the system */
275
    status = ioctl(midiSeqFD, SNDCTL_SEQ_NRMIDIS, &nummididevs);
276 277
    if (status == -1) {
	ERR("ioctl on nr midi failed.\n");
278 279
        nummididevs = 0;
        goto wrapup;
280
    }
281

282
    /* FIXME: the two restrictions below could be loosened in some cases */
283 284 285 286 287
    if (numsynthdevs + nummididevs > MAX_MIDIOUTDRV) {
	ERR("MAX_MIDIOUTDRV was not enough for the number of devices. "
	    "Some MIDI devices will not be available.\n");
	nummididevs = MAX_MIDIOUTDRV - numsynthdevs;
    }
288

289 290 291 292 293
    if (nummididevs > MAX_MIDIINDRV) {
	ERR("MAX_MIDIINDRV (%d) was not enough for the number of devices (%d). "
	    "Some MIDI devices will not be available.\n",MAX_MIDIINDRV,nummididevs);
	nummididevs = MAX_MIDIINDRV;
    }
294

295 296
    for (i = 0; i < nummididevs; i++) {
	minfo.device = i;
297
	status = ioctl(midiSeqFD, SNDCTL_MIDI_INFO, &minfo);
298
	if (status == -1) WARN("ioctl on midi info for device %d failed.\n", i);
299

300
	/* This whole part is somewhat obscure to me. I'll keep trying to dig
301
	   info about it. If you happen to know, please tell us. The very
Austin English's avatar
Austin English committed
302
	   descriptive minfo.dev_type was not used here.
303
	*/
Austin English's avatar
Austin English committed
304
	/* Manufacturer ID. We do not have access to this with soundcard.h
305 306
	   Does not seem to be a problem, because in mmsystem.h only
	   Microsoft's ID is listed */
307 308
	MidiOutDev[numsynthdevs + i].caps.wMid = 0x00FF;
	MidiOutDev[numsynthdevs + i].caps.wPid = 0x0001; 	/* FIXME Product ID */
309
	/* Product Version. We simply say "1" */
310 311
	MidiOutDev[numsynthdevs + i].caps.vDriverVersion = 0x001;
        if (status == -1) {
312
            static const WCHAR fmt[] = {'W','i','n','e',' ','O','S','S',' ','M','i','d','i',' ','O','u','t',' ','(','#','%','d',')',' ','d','i','s','a','b','l','e','d',0};
313
            wsprintfW(MidiOutDev[numsynthdevs + i].caps.szPname, fmt, numsynthdevs + i);
314 315
            MidiOutDev[numsynthdevs + i].bEnabled = FALSE;
        } else {
316
            MultiByteToWideChar(CP_UNIXCP, 0, minfo.name, -1,
317 318
                                MidiOutDev[numsynthdevs + i].caps.szPname,
                                sizeof(MidiOutDev[numsynthdevs + i].caps.szPname) / sizeof(WCHAR));
319 320 321
            MidiOutDev[numsynthdevs + i].bEnabled = TRUE;
        }
	MidiOutDev[numsynthdevs + i].caps.wTechnology = MOD_MIDIPORT; /* FIXME Is this right? */
322
	/* Does it make any difference? */
323
	MidiOutDev[numsynthdevs + i].caps.wVoices     = 16;
324
	/* Does it make any difference? */
325 326
	MidiOutDev[numsynthdevs + i].caps.wNotes      = 16;
	MidiOutDev[numsynthdevs + i].caps.wChannelMask= 0xFFFF;
327

328
	/* FIXME Does it make any difference? */
329
	MidiOutDev[numsynthdevs + i].caps.dwSupport   = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;
330

331
	/* This whole part is somewhat obscure to me. I'll keep trying to dig
332
	   info about it. If you happen to know, please tell us. The very
333
	   descriptive minfo.dev_type was not used here.
334 335 336 337
	*/
	/* Manufac ID. We do not have access to this with soundcard.h
	   Does not seem to be a problem, because in mmsystem.h only
	   Microsoft's ID is listed */
338 339
	MidiInDev[i].caps.wMid = 0x00FF;
	MidiInDev[i].caps.wPid = 0x0001; 	/* FIXME Product ID */
340
	/* Product Version. We simply say "1" */
341 342
	MidiInDev[i].caps.vDriverVersion = 0x001;
        if (status == -1) {
343
            static const WCHAR fmt[] = {'W','i','n','e',' ','O','S','S',' ','M','i','d','i',' ','I','n',' ','(','#','%','d',')',' ','d','i','s','a','b','l','e','d',0};
344
            wsprintfW(MidiInDev[i].caps.szPname, fmt, numsynthdevs + i);
345 346
            MidiInDev[i].state = -1;
        } else {
347
            MultiByteToWideChar(CP_UNIXCP, 0, minfo.name, -1,
348 349
                                MidiInDev[i].caps.szPname,
                                sizeof(MidiInDev[i].caps.szPname) / sizeof(WCHAR));
350 351
            MidiInDev[i].state = 0;
        }
352
	/* FIXME : could we get better information than that ? */
353
	MidiInDev[i].caps.dwSupport   = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;
354

355 356 357
	TRACE("MidiOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%d\n"
              "MidiIn [%d]\tname='%s' support=%d\n"
              "\tOSS info: midi dev-type=%d, capa=%lx\n",
358 359
	      i, wine_dbgstr_w(MidiOutDev[numsynthdevs + i].caps.szPname), 
              MidiOutDev[numsynthdevs + i].caps.wTechnology,
360 361
	      MidiOutDev[numsynthdevs + i].caps.wVoices, MidiOutDev[numsynthdevs + i].caps.wNotes,
	      MidiOutDev[numsynthdevs + i].caps.wChannelMask, MidiOutDev[numsynthdevs + i].caps.dwSupport,
362
	      i, wine_dbgstr_w(MidiInDev[i].caps.szPname), MidiInDev[i].caps.dwSupport,
Gerald Pfeifer's avatar
Gerald Pfeifer committed
363
	      minfo.dev_type, (long)minfo.capabilities);
364
    }
365

366
 wrapup:
367
    /* windows does not seem to differentiate Synth from MIDI devices */
368 369
    MODM_NumFMSynthDevs = numsynthdevs;
    MODM_NumDevs        = numsynthdevs + nummididevs;
370

371
    MIDM_NumDevs        = nummididevs;
372

373
    /* close file and exit */
374
    midiCloseSeq();
375

376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
    return 0;
}

/**************************************************************************
 * 			OSS_MidiExit				[internal]
 *
 * Release the MIDI devices information variables
 */
LRESULT OSS_MidiExit(void)
{
    TRACE("()\n");

    ZeroMemory(MidiInDev, sizeof(MidiInDev));
    ZeroMemory(MidiOutDev, sizeof(MidiOutDev));

    MODM_NumDevs = 0;
    MODM_NumFMSynthDevs = 0;
    MIDM_NumDevs = 0;

    return 0;
396 397
}

Alexandre Julliard's avatar
Alexandre Julliard committed
398
/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
399 400
 * 			MIDI_NotifyClient			[internal]
 */
401
static DWORD MIDI_NotifyClient(UINT wDevID, WORD wMsg,
Alexandre Julliard's avatar
Alexandre Julliard committed
402
			       DWORD dwParam1, DWORD dwParam2)
Alexandre Julliard's avatar
Alexandre Julliard committed
403
{
Alexandre Julliard's avatar
Alexandre Julliard committed
404
    DWORD 		dwCallBack;
405 406
    UINT 		uFlags;
    HANDLE		hDev;
Alexandre Julliard's avatar
Alexandre Julliard committed
407
    DWORD 		dwInstance;
408

409
    TRACE("wDevID = %04X wMsg = %d dwParm1 = %04X dwParam2 = %04X\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
410
	  wDevID, wMsg, dwParam1, dwParam2);
411

Alexandre Julliard's avatar
Alexandre Julliard committed
412 413 414 415
    switch (wMsg) {
    case MOM_OPEN:
    case MOM_CLOSE:
    case MOM_DONE:
416
    case MOM_POSITIONCB:
417 418
	if (wDevID > MODM_NumDevs)
	    return MMSYSERR_BADDEVICEID;
419

420
	dwCallBack = MidiOutDev[wDevID].midiDesc.dwCallback;
Alexandre Julliard's avatar
Alexandre Julliard committed
421
	uFlags = MidiOutDev[wDevID].wFlags;
422 423
	hDev = MidiOutDev[wDevID].midiDesc.hMidi;
	dwInstance = MidiOutDev[wDevID].midiDesc.dwInstance;
Alexandre Julliard's avatar
Alexandre Julliard committed
424
	break;
425

Alexandre Julliard's avatar
Alexandre Julliard committed
426 427 428
    case MIM_OPEN:
    case MIM_CLOSE:
    case MIM_DATA:
429
    case MIM_LONGDATA:
Alexandre Julliard's avatar
Alexandre Julliard committed
430
    case MIM_ERROR:
431 432
    case MIM_LONGERROR:
    case MIM_MOREDATA:
433 434
	if (wDevID > MIDM_NumDevs)
	    return MMSYSERR_BADDEVICEID;
435

436
	dwCallBack = MidiInDev[wDevID].midiDesc.dwCallback;
Alexandre Julliard's avatar
Alexandre Julliard committed
437
	uFlags = MidiInDev[wDevID].wFlags;
438 439
	hDev = MidiInDev[wDevID].midiDesc.hMidi;
	dwInstance = MidiInDev[wDevID].midiDesc.dwInstance;
Alexandre Julliard's avatar
Alexandre Julliard committed
440 441
	break;
    default:
442
	WARN("Unsupported MSW-MIDI message %u\n", wMsg);
443
	return MMSYSERR_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
444
    }
445

446
    return DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2) ?
447
	0 : MMSYSERR_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
448 449
}

Andreas Mohr's avatar
Andreas Mohr committed
450
static int midi_warn = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
451 452 453 454 455 456
/**************************************************************************
 * 			midiOpenSeq				[internal]
 */
static int midiOpenSeq(void)
{
    if (numOpenMidiSeq == 0) {
457 458 459 460
	const char* device;
	device=getenv("MIDIDEV");
	if (!device) device="/dev/sequencer";
	midiSeqFD = open(device, O_RDWR, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
461
	if (midiSeqFD == -1) {
Andreas Mohr's avatar
Andreas Mohr committed
462
	    if (midi_warn)
463
	    {
464
		WARN("Can't open MIDI device '%s' ! (%s). If your "
465
                        "program needs this (probably not): %s\n",
466
			device, strerror(errno),
467
			errno == ENOENT ?
468
			"create it ! (\"man MAKEDEV\" ?)" :
469
			errno == ENODEV ?
470
			"load MIDI sequencer kernel driver !" :
471
			errno == EACCES ?
472
			"grant access ! (\"man chmod\")" : ""
473 474
		);
	    }
Andreas Mohr's avatar
Andreas Mohr committed
475
	    midi_warn = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
476
	    return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
477
	}
478
#if 0
Alexandre Julliard's avatar
Alexandre Julliard committed
479
	if (fcntl(midiSeqFD, F_SETFL, O_NONBLOCK) < 0) {
Andreas Mohr's avatar
Andreas Mohr committed
480
	    WARN("can't set sequencer fd to non-blocking, errno %d (%s)\n", errno, strerror(errno));
Alexandre Julliard's avatar
Alexandre Julliard committed
481 482 483 484
	    close(midiSeqFD);
	    midiSeqFD = -1;
	    return -1;
	}
485
#endif
486
	fcntl(midiSeqFD, F_SETFD, 1); /* set close on exec flag */
Alexandre Julliard's avatar
Alexandre Julliard committed
487 488 489 490
	ioctl(midiSeqFD, SNDCTL_SEQ_RESET);
    }
    numOpenMidiSeq++;
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
491 492
}

Alexandre Julliard's avatar
Alexandre Julliard committed
493 494 495 496 497 498 499 500 501 502 503
/**************************************************************************
 * 			midiCloseSeq				[internal]
 */
static int midiCloseSeq(void)
{
    if (--numOpenMidiSeq == 0) {
	close(midiSeqFD);
	midiSeqFD = -1;
    }
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
504

Alexandre Julliard's avatar
Alexandre Julliard committed
505 506 507
/* FIXME: this is a bad idea, it's even not static... */
SEQ_DEFINEBUF(1024);

508 509
/* FIXME: this is not reentrant, not static - because of global variable
 * _seqbuf and al.
510
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
511 512
/**************************************************************************
 * 			seqbuf_dump				[internal]
513 514 515
 *
 * Used by SEQ_DUMPBUF to flush the buffer.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
516 517 518 519 520
 */
void seqbuf_dump(void)
{
    if (_seqbufptr) {
	if (write(midiSeqFD, _seqbuf, _seqbufptr) == -1) {
521
	    WARN("Can't write data to sequencer %d, errno %d (%s)!\n",
Andreas Mohr's avatar
Andreas Mohr committed
522
		 midiSeqFD, errno, strerror(errno));
Alexandre Julliard's avatar
Alexandre Julliard committed
523 524
	}
	/* FIXME:
525 526
	 *	in any case buffer is lost so that if many errors occur the buffer
	 * will not overrun
Alexandre Julliard's avatar
Alexandre Julliard committed
527 528 529 530 531
	 */
	_seqbufptr = 0;
    }
}

532
/**************************************************************************
Francois Gouget's avatar
Francois Gouget committed
533
 * 			midReceiveChar				[internal]
534
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
535 536 537
static void midReceiveChar(WORD wDevID, unsigned char value, DWORD dwTime)
{
    DWORD		toSend = 0;
538

539
    TRACE("Adding %02xh to %d[%d]\n", value, wDevID, MidiInDev[wDevID].incLen);
540

541
    if (wDevID >= MIDM_NumDevs) {
542
	WARN("bad devID\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
543 544
	return;
    }
545 546
    if (MidiInDev[wDevID].state <= 0) {
	TRACE("disabled or input not started, thrown away\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
547 548
	return;
    }
549

Alexandre Julliard's avatar
Alexandre Julliard committed
550
    if (MidiInDev[wDevID].state & 2) { /* system exclusive */
551
	LPMIDIHDR	lpMidiHdr;
552 553
	WORD 		sbfb = FALSE;

554 555
	EnterCriticalSection(&crit_sect);
	if ((lpMidiHdr = MidiInDev[wDevID].lpQueueHdr) != NULL) {
Mike McCormack's avatar
Mike McCormack committed
556
	    LPBYTE	lpData = (LPBYTE) lpMidiHdr->lpData;
557

558 559
	    lpData[lpMidiHdr->dwBytesRecorded++] = value;
	    if (lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) {
Alexandre Julliard's avatar
Alexandre Julliard committed
560
		sbfb = TRUE;
561
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
562 563 564 565 566
	}
	if (value == 0xF7) { /* then end */
	    MidiInDev[wDevID].state &= ~2;
	    sbfb = TRUE;
	}
567 568 569 570
	if (sbfb && lpMidiHdr != NULL) {
	    lpMidiHdr = MidiInDev[wDevID].lpQueueHdr;
	    lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
	    lpMidiHdr->dwFlags |= MHDR_DONE;
571
	    MidiInDev[wDevID].lpQueueHdr = lpMidiHdr->lpNext;
572
	    if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD_PTR)lpMidiHdr, dwTime) != MMSYSERR_NOERROR) {
573
		WARN("Couldn't notify client\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
574 575
	    }
	}
576
	LeaveCriticalSection(&crit_sect);
Alexandre Julliard's avatar
Alexandre Julliard committed
577 578
	return;
    }
579

Alexandre Julliard's avatar
Alexandre Julliard committed
580 581
#define IS_CMD(_x)	(((_x) & 0x80) == 0x80)
#define IS_SYS_CMD(_x)	(((_x) & 0xF0) == 0xF0)
582

Alexandre Julliard's avatar
Alexandre Julliard committed
583 584 585 586
    if (!IS_CMD(value) && MidiInDev[wDevID].incLen == 0) { /* try to reuse old cmd */
	if (IS_CMD(MidiInDev[wDevID].incPrev) && !IS_SYS_CMD(MidiInDev[wDevID].incPrev)) {
	    MidiInDev[wDevID].incoming[0] = MidiInDev[wDevID].incPrev;
	    MidiInDev[wDevID].incLen = 1;
587
	    TRACE("Reusing old command %02xh\n", MidiInDev[wDevID].incPrev);
Alexandre Julliard's avatar
Alexandre Julliard committed
588
	} else {
589
	    FIXME("error for midi-in, should generate MIM_ERROR notification:"
590
		  " prev=%02Xh, incLen=%02Xh\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
591 592 593 594 595 596 597 598 599
		  MidiInDev[wDevID].incPrev, MidiInDev[wDevID].incLen);
	    return;
	}
    }
    MidiInDev[wDevID].incoming[(int)(MidiInDev[wDevID].incLen++)] = value;
    if (MidiInDev[wDevID].incLen == 1 && !IS_SYS_CMD(MidiInDev[wDevID].incoming[0])) {
	/* store new cmd, just in case */
	MidiInDev[wDevID].incPrev = MidiInDev[wDevID].incoming[0];
    }
600 601 602 603

#undef IS_CMD
#undef IS_SYS_CMD

Alexandre Julliard's avatar
Alexandre Julliard committed
604 605 606 607 608 609 610
    switch (MidiInDev[wDevID].incoming[0] & 0xF0) {
    case MIDI_NOTEOFF:
    case MIDI_NOTEON:
    case MIDI_KEY_PRESSURE:
    case MIDI_CTL_CHANGE:
    case MIDI_PITCH_BEND:
	if (MidiInDev[wDevID].incLen == 3) {
611
	    toSend = (MidiInDev[wDevID].incoming[2] << 16) |
Alexandre Julliard's avatar
Alexandre Julliard committed
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
		(MidiInDev[wDevID].incoming[1] <<  8) |
		(MidiInDev[wDevID].incoming[0] <<  0);
	}
	break;
    case MIDI_PGM_CHANGE:
    case MIDI_CHN_PRESSURE:
	if (MidiInDev[wDevID].incLen == 2) {
	    toSend = (MidiInDev[wDevID].incoming[1] <<  8) |
		(MidiInDev[wDevID].incoming[0] <<  0);
	}
	break;
    case MIDI_SYSTEM_PREFIX:
	if (MidiInDev[wDevID].incoming[0] == 0xF0) {
	    MidiInDev[wDevID].state |= 2;
	    MidiInDev[wDevID].incLen = 0;
627
	} else {
Alexandre Julliard's avatar
Alexandre Julliard committed
628 629 630 631 632 633
	    if (MidiInDev[wDevID].incLen == 1) {
		toSend = (MidiInDev[wDevID].incoming[0] <<  0);
	    }
	}
	break;
    default:
634
	WARN("This shouldn't happen (%02X)\n", MidiInDev[wDevID].incoming[0]);
Alexandre Julliard's avatar
Alexandre Julliard committed
635 636
    }
    if (toSend != 0) {
637
	TRACE("Sending event %08x\n", toSend);
Alexandre Julliard's avatar
Alexandre Julliard committed
638 639 640
	MidiInDev[wDevID].incLen =	0;
	dwTime -= MidiInDev[wDevID].startTime;
	if (MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime) != MMSYSERR_NOERROR) {
641
	    WARN("Couldn't notify client\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
642 643 644
	}
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
645

646
static DWORD WINAPI midRecThread(LPVOID arg)
Alexandre Julliard's avatar
Alexandre Julliard committed
647
{
Christian Costa's avatar
Christian Costa committed
648 649
    unsigned char buffer[256];
    int len, idx;
650 651
    DWORD dwTime;
    struct pollfd pfd;
652

653
    TRACE("Thread startup\n");
654

655 656 657 658 659 660
    pfd.fd = midiSeqFD;
    pfd.fd = POLLIN;
    
    while(!end_thread) {
	TRACE("Thread loop\n");

661
	/* Check if an event is present */
662 663 664 665
	if (poll(&pfd, 1, 250) <= 0)
	    continue;
	
	len = read(midiSeqFD, buffer, sizeof(buffer));
666
	TRACE("Received %d bytes\n", len);
667 668 669 670 671 672

	if (len < 0) continue;
	if ((len % 4) != 0) {
	    WARN("Bad length %d, errno %d (%s)\n", len, errno, strerror(errno));
	    continue;
	}
673

674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
	dwTime = GetTickCount();
	
	for (idx = 0; idx < len; ) {
	    if (buffer[idx] & 0x80) {
		TRACE(
		      "Reading<8> %02x %02x %02x %02x %02x %02x %02x %02x\n",
		      buffer[idx + 0], buffer[idx + 1],
		      buffer[idx + 2], buffer[idx + 3],
		      buffer[idx + 4], buffer[idx + 5],
		      buffer[idx + 6], buffer[idx + 7]);
		      idx += 8;
	    } else {
		switch (buffer[idx + 0]) {
		case SEQ_WAIT:
		case SEQ_ECHO:
		    break;
		case SEQ_MIDIPUTC:
		    midReceiveChar(buffer[idx + 2], buffer[idx + 1], dwTime);
		    break;
		default:
		    TRACE("Unsupported event %d\n", buffer[idx + 0]);
		    break;
		}
		idx += 4;
Alexandre Julliard's avatar
Alexandre Julliard committed
698
	    }
699
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
700
    }
701
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
702
}
Alexandre Julliard's avatar
Alexandre Julliard committed
703 704

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
705 706
 * 				midGetDevCaps			[internal]
 */
707
static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPSW lpCaps, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
708
{
709
    TRACE("(%04X, %p, %08X);\n", wDevID, lpCaps, dwSize);
710

711
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
712 713
    if (lpCaps == NULL)		return MMSYSERR_INVALPARAM;

714
    memcpy(lpCaps, &MidiInDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
715

Alexandre Julliard's avatar
Alexandre Julliard committed
716
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
717 718 719
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
720 721
 * 			midOpen					[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
722
static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
723
{
724
    TRACE("(%04X, %p, %08X);\n", wDevID, lpDesc, dwFlags);
725

Alexandre Julliard's avatar
Alexandre Julliard committed
726
    if (lpDesc == NULL) {
727
	WARN("Invalid Parameter !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
728 729
	return MMSYSERR_INVALPARAM;
    }
730

Alexandre Julliard's avatar
Alexandre Julliard committed
731 732 733
    /* FIXME :
     *	how to check that content of lpDesc is correct ?
     */
734
    if (wDevID >= MIDM_NumDevs) {
735
	WARN("wDevID too large (%u) !\n", wDevID);
Alexandre Julliard's avatar
Alexandre Julliard committed
736 737
	return MMSYSERR_BADDEVICEID;
    }
738 739 740 741
    if (MidiInDev[wDevID].state == -1) {        
        WARN("device disabled\n");
        return MIDIERR_NODEVICE;
    }
742
    if (MidiInDev[wDevID].midiDesc.hMidi != 0) {
743
	WARN("device already open !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
744 745
	return MMSYSERR_ALLOCATED;
    }
746
    if ((dwFlags & MIDI_IO_STATUS) != 0) {
747 748 749
	WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n");
	dwFlags &= ~MIDI_IO_STATUS;
    }
750
    if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
751
	FIXME("Bad dwFlags\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
752 753
	return MMSYSERR_INVALFLAG;
    }
754

Alexandre Julliard's avatar
Alexandre Julliard committed
755 756 757
    if (midiOpenSeq() < 0) {
	return MMSYSERR_ERROR;
    }
758

Alexandre Julliard's avatar
Alexandre Julliard committed
759
    if (numStartedMidiIn++ == 0) {
760 761 762
	end_thread = 0;
	hThread = CreateThread(NULL, 0, midRecThread, NULL, 0, NULL);
	if (!hThread) {
Alexandre Julliard's avatar
Alexandre Julliard committed
763
	    numStartedMidiIn = 0;
764
	    WARN("Couldn't create thread for midi-in\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
765 766
	    midiCloseSeq();
	    return MMSYSERR_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
767
	}
768
        SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
769
	TRACE("Created thread for midi-in\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
770
    }
771

Alexandre Julliard's avatar
Alexandre Julliard committed
772
    MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
773

Alexandre Julliard's avatar
Alexandre Julliard committed
774 775 776
    MidiInDev[wDevID].lpQueueHdr = NULL;
    MidiInDev[wDevID].dwTotalPlayed = 0;
    MidiInDev[wDevID].bufsize = 0x3FFF;
777
    MidiInDev[wDevID].midiDesc = *lpDesc;
Alexandre Julliard's avatar
Alexandre Julliard committed
778 779 780
    MidiInDev[wDevID].state = 0;
    MidiInDev[wDevID].incLen = 0;
    MidiInDev[wDevID].startTime = 0;
781

Alexandre Julliard's avatar
Alexandre Julliard committed
782
    if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
783
	WARN("can't notify client !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
784 785 786
	return MMSYSERR_INVALPARAM;
    }
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
787 788 789
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
790 791
 * 			midClose				[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
792
static DWORD midClose(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
793
{
Alexandre Julliard's avatar
Alexandre Julliard committed
794
    int		ret = MMSYSERR_NOERROR;
795

796
    TRACE("(%04X);\n", wDevID);
797

798
    if (wDevID >= MIDM_NumDevs) {
Andreas Mohr's avatar
Andreas Mohr committed
799
	WARN("wDevID too big (%u) !\n", wDevID);
Alexandre Julliard's avatar
Alexandre Julliard committed
800 801
	return MMSYSERR_BADDEVICEID;
    }
802
    if (MidiInDev[wDevID].midiDesc.hMidi == 0) {
803
	WARN("device not opened !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
804 805 806 807 808
	return MMSYSERR_ERROR;
    }
    if (MidiInDev[wDevID].lpQueueHdr != 0) {
	return MIDIERR_STILLPLAYING;
    }
809

Alexandre Julliard's avatar
Alexandre Julliard committed
810
    if (midiSeqFD == -1) {
811
	WARN("ooops !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
812 813 814
	return MMSYSERR_ERROR;
    }
    if (--numStartedMidiIn == 0) {
815 816 817 818 819
	TRACE("Stopping thread for midi-in\n");
	end_thread = 1;
	if (WaitForSingleObject(hThread, 5000) != WAIT_OBJECT_0) {
	    WARN("Thread end not signaled, force termination\n");
	    TerminateThread(hThread, 0);
820
	}
821
    	TRACE("Stopped thread for midi-in\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
822 823
    }
    midiCloseSeq();
824

Alexandre Julliard's avatar
Alexandre Julliard committed
825 826
    MidiInDev[wDevID].bufsize = 0;
    if (MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
827
	WARN("can't notify client !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
828 829
	ret = MMSYSERR_INVALPARAM;
    }
830
    MidiInDev[wDevID].midiDesc.hMidi = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
831
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
832 833 834
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
835
 * 				midAddBuffer			[internal]
Alexandre Julliard's avatar
Alexandre Julliard committed
836
 */
837
static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
838
{
839
    TRACE("(%04X, %p, %08X);\n", wDevID, lpMidiHdr, dwSize);
840

841 842 843
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;

Alexandre Julliard's avatar
Alexandre Julliard committed
844
    if (lpMidiHdr == NULL)	return MMSYSERR_INVALPARAM;
845
    if (sizeof(MIDIHDR) > dwSize) return MMSYSERR_INVALPARAM;
Alexandre Julliard's avatar
Alexandre Julliard committed
846 847 848
    if (lpMidiHdr->dwBufferLength == 0) return MMSYSERR_INVALPARAM;
    if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
849

850
    EnterCriticalSection(&crit_sect);
851
    lpMidiHdr->dwFlags &= ~WHDR_DONE;
852
    lpMidiHdr->dwFlags |= MHDR_INQUEUE;
853 854
    lpMidiHdr->dwBytesRecorded = 0;
    lpMidiHdr->lpNext = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
855 856 857
    if (MidiInDev[wDevID].lpQueueHdr == 0) {
	MidiInDev[wDevID].lpQueueHdr = lpMidiHdr;
    } else {
858
	LPMIDIHDR	ptr;
859 860 861

	for (ptr = MidiInDev[wDevID].lpQueueHdr;
	     ptr->lpNext != 0;
862 863
	     ptr = ptr->lpNext);
	ptr->lpNext = lpMidiHdr;
Alexandre Julliard's avatar
Alexandre Julliard committed
864
    }
865 866
    LeaveCriticalSection(&crit_sect);

Alexandre Julliard's avatar
Alexandre Julliard committed
867
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
868 869 870
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
871 872
 * 				midPrepare			[internal]
 */
873
static DWORD midPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
874
{
875
    TRACE("(%04X, %p, %08X);\n", wDevID, lpMidiHdr, dwSize);
876 877

    if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 ||
878
	lpMidiHdr->lpData == 0 || (lpMidiHdr->dwFlags & MHDR_INQUEUE) != 0 ||
Alexandre Julliard's avatar
Alexandre Julliard committed
879 880
	lpMidiHdr->dwBufferLength >= 0x10000ul)
	return MMSYSERR_INVALPARAM;
881

Alexandre Julliard's avatar
Alexandre Julliard committed
882 883 884
    lpMidiHdr->lpNext = 0;
    lpMidiHdr->dwFlags |= MHDR_PREPARED;
    lpMidiHdr->dwBytesRecorded = 0;
885

Alexandre Julliard's avatar
Alexandre Julliard committed
886
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
887 888 889
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
890 891
 * 				midUnprepare			[internal]
 */
892
static DWORD midUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
893
{
894
    TRACE("(%04X, %p, %08X);\n", wDevID, lpMidiHdr, dwSize);
895

896 897 898
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;

899
    if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 ||
Alexandre Julliard's avatar
Alexandre Julliard committed
900 901
	lpMidiHdr->lpData == 0 || lpMidiHdr->dwBufferLength >= 0x10000ul)
	return MMSYSERR_INVALPARAM;
902

Alexandre Julliard's avatar
Alexandre Julliard committed
903 904
    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
    if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
905

Alexandre Julliard's avatar
Alexandre Julliard committed
906
    lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
907

Alexandre Julliard's avatar
Alexandre Julliard committed
908
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
909 910 911
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
912 913
 * 			midReset				[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
914
static DWORD midReset(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
915
{
Alexandre Julliard's avatar
Alexandre Julliard committed
916
    DWORD		dwTime = GetTickCount();
917

918
    TRACE("(%04X);\n", wDevID);
919

920 921 922
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;

923
    EnterCriticalSection(&crit_sect);
Alexandre Julliard's avatar
Alexandre Julliard committed
924 925 926
    while (MidiInDev[wDevID].lpQueueHdr) {
	MidiInDev[wDevID].lpQueueHdr->dwFlags &= ~MHDR_INQUEUE;
	MidiInDev[wDevID].lpQueueHdr->dwFlags |= MHDR_DONE;
927
	/* FIXME: when called from 16 bit, lpQueueHdr needs to be a segmented ptr */
928
	if (MIDI_NotifyClient(wDevID, MIM_LONGDATA,
929
			      (DWORD_PTR)MidiInDev[wDevID].lpQueueHdr, dwTime) != MMSYSERR_NOERROR) {
930
	    WARN("Couldn't notify client\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
931
	}
932
	MidiInDev[wDevID].lpQueueHdr = MidiInDev[wDevID].lpQueueHdr->lpNext;
Alexandre Julliard's avatar
Alexandre Julliard committed
933
    }
934
    LeaveCriticalSection(&crit_sect);
935

Alexandre Julliard's avatar
Alexandre Julliard committed
936
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
937 938 939 940
}


/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
941 942
 * 			midStart				[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
943
static DWORD midStart(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
944
{
945
    TRACE("(%04X);\n", wDevID);
946

947 948
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;
949

Alexandre Julliard's avatar
Alexandre Julliard committed
950 951 952
    MidiInDev[wDevID].state = 1;
    MidiInDev[wDevID].startTime = GetTickCount();
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
953 954 955
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
956 957
 *			midStop					[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
958
static DWORD midStop(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
959
{
960
    TRACE("(%04X);\n", wDevID);
961

962 963 964
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;

Alexandre Julliard's avatar
Alexandre Julliard committed
965 966
    MidiInDev[wDevID].state = 0;
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
967 968 969 970
}

/*-----------------------------------------------------------------------*/

Alexandre Julliard's avatar
Alexandre Julliard committed
971 972 973 974 975 976 977 978 979 980 981 982
typedef struct sVoice {
    int			note;			/* 0 means not used */
    int			channel;
    unsigned		cntMark : 30,
	                status : 2;
#define sVS_UNUSED	0
#define sVS_PLAYING	1
#define sVS_SUSTAINED	2
} sVoice;

typedef struct sChannel {
    int			program;
983

Alexandre Julliard's avatar
Alexandre Julliard committed
984 985
    int			bender;
    int			benderRange;
Austin English's avatar
Austin English committed
986
    /* controllers */
Alexandre Julliard's avatar
Alexandre Julliard committed
987 988 989 990 991
    int			bank;		/* CTL_BANK_SELECT */
    int			volume;		/* CTL_MAIN_VOLUME */
    int			balance;	/* CTL_BALANCE     */
    int			expression;	/* CTL_EXPRESSION  */
    int			sustain;	/* CTL_SUSTAIN     */
992

Alexandre Julliard's avatar
Alexandre Julliard committed
993 994 995 996 997 998 999 1000 1001 1002 1003
    unsigned char	nrgPmtMSB;	/* Non register Parameters */
    unsigned char	nrgPmtLSB;
    unsigned char	regPmtMSB;	/* Non register Parameters */
    unsigned char	regPmtLSB;
} sChannel;

typedef struct sFMextra {
    unsigned		counter;
    int			drumSetMask;
    sChannel		channel[16];	/* MIDI has only 16 channels */
    sVoice		voice[1];	/* dyn allocated according to sound card */
1004
    /* do not append fields below voice[1] since the size of this structure
Alexandre Julliard's avatar
Alexandre Julliard committed
1005 1006 1007 1008
     * depends on the number of available voices on the FM synth...
     */
} sFMextra;

1009 1010
extern const unsigned char midiFMInstrumentPatches[16 * 128];
extern const unsigned char midiFMDrumsPatches     [16 * 128];
Alexandre Julliard's avatar
Alexandre Julliard committed
1011

Alexandre Julliard's avatar
Alexandre Julliard committed
1012
/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1013
 * 			modFMLoad				[internal]
Alexandre Julliard's avatar
Alexandre Julliard committed
1014
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1015
static int modFMLoad(int dev)
Alexandre Julliard's avatar
Alexandre Julliard committed
1016
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1017 1018
    int				i;
    struct sbi_instrument	sbi;
1019

Alexandre Julliard's avatar
Alexandre Julliard committed
1020 1021
    sbi.device = dev;
    sbi.key = FM_PATCH;
1022

Alexandre Julliard's avatar
Alexandre Julliard committed
1023 1024 1025 1026
    memset(sbi.operators + 16, 0, 16);
    for (i = 0; i < 128; i++) {
	sbi.channel = i;
	memcpy(sbi.operators, midiFMInstrumentPatches + i * 16, 16);
1027

1028
        if (write(midiSeqFD, &sbi, sizeof(sbi)) == -1) {
Andreas Mohr's avatar
Andreas Mohr committed
1029
	    WARN("Couldn't write patch for instrument %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno));
Alexandre Julliard's avatar
Alexandre Julliard committed
1030 1031
	    return -1;
	}
1032
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1033 1034 1035
    for (i = 0; i < 128; i++) {
	sbi.channel = 128 + i;
	memcpy(sbi.operators, midiFMDrumsPatches + i * 16, 16);
1036

1037
        if (write(midiSeqFD, &sbi, sizeof(sbi)) == -1) {
Andreas Mohr's avatar
Andreas Mohr committed
1038
	    WARN("Couldn't write patch for drum %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno));
Alexandre Julliard's avatar
Alexandre Julliard committed
1039 1040
	    return -1;
	}
1041
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1042 1043 1044 1045 1046 1047 1048 1049
    return 0;
}

/**************************************************************************
 * 			modFMReset				[internal]
 */
static	void modFMReset(WORD wDevID)
{
1050
    sFMextra*   extra   = MidiOutDev[wDevID].lpExtra;
Alexandre Julliard's avatar
Alexandre Julliard committed
1051 1052 1053
    sVoice* 	voice   = extra->voice;
    sChannel*	channel = extra->channel;
    int		i;
1054

1055
    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
	if (voice[i].status != sVS_UNUSED) {
	    SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
	}
	SEQ_KEY_PRESSURE(wDevID, i, 127, 0);
	SEQ_CONTROL(wDevID, i, SEQ_VOLMODE, VOL_METHOD_LINEAR);
	voice[i].note = 0;
	voice[i].channel = -1;
	voice[i].cntMark = 0;
	voice[i].status = sVS_UNUSED;
    }
    for (i = 0; i < 16; i++) {
	channel[i].program = 0;
	channel[i].bender = 8192;
	channel[i].benderRange = 2;
	channel[i].bank = 0;
	channel[i].volume = 127;
	channel[i].balance = 64;
1073 1074
	channel[i].expression = 0;
	channel[i].sustain = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1075 1076 1077 1078 1079 1080 1081
    }
    extra->counter = 0;
    extra->drumSetMask = 1 << 9; /* channel 10 is normally drums, sometimes 16 also */
    SEQ_DUMPBUF();
}

#define		IS_DRUM_CHANNEL(_xtra, _chn)	((_xtra)->drumSetMask & (1 << (_chn)))
Alexandre Julliard's avatar
Alexandre Julliard committed
1082

Alexandre Julliard's avatar
Alexandre Julliard committed
1083 1084 1085
/**************************************************************************
 * 				modGetDevCaps			[internal]
 */
1086
static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPSW lpCaps, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1087
{
1088
    TRACE("(%04X, %p, %08X);\n", wDevID, lpCaps, dwSize);
1089

1090
    if (wDevID >= MODM_NumDevs)	return MMSYSERR_BADDEVICEID;
1091 1092
    if (lpCaps == NULL) 	return MMSYSERR_INVALPARAM;

1093
    memcpy(lpCaps, &MidiOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
1094

Alexandre Julliard's avatar
Alexandre Julliard committed
1095
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1096 1097 1098
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1099 1100
 * 			modOpen					[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1101
static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1102
{
1103
    TRACE("(%04X, %p, %08X);\n", wDevID, lpDesc, dwFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
1104
    if (lpDesc == NULL) {
1105
	WARN("Invalid Parameter !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1106 1107
	return MMSYSERR_INVALPARAM;
    }
1108
    if (wDevID >= MODM_NumDevs) {
1109
	TRACE("MAX_MIDIOUTDRV reached !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1110 1111
	return MMSYSERR_BADDEVICEID;
    }
1112
    if (MidiOutDev[wDevID].midiDesc.hMidi != 0) {
1113
	WARN("device already open !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1114 1115
	return MMSYSERR_ALLOCATED;
    }
1116 1117 1118 1119
    if (!MidiOutDev[wDevID].bEnabled) {
	WARN("device disabled !\n");
	return MIDIERR_NODEVICE;
    }
1120
    if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
1121
	WARN("bad dwFlags\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1122 1123
	return MMSYSERR_INVALFLAG;
    }
1124 1125 1126
    if (!MidiOutDev[wDevID].bEnabled) {
	TRACE("disabled wDevID\n");
	return MMSYSERR_NOTENABLED;
1127
    }
1128

Alexandre Julliard's avatar
Alexandre Julliard committed
1129
    MidiOutDev[wDevID].lpExtra = 0;
1130

1131
    switch (MidiOutDev[wDevID].caps.wTechnology) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1132 1133
    case MOD_FMSYNTH:
	{
1134 1135 1136 1137 1138
	    void*	extra;

            extra = HeapAlloc(GetProcessHeap(), 0,
                              sizeof(struct sFMextra) +
                              sizeof(struct sVoice) * (MidiOutDev[wDevID].caps.wVoices - 1));
1139

Alexandre Julliard's avatar
Alexandre Julliard committed
1140
	    if (extra == 0) {
1141
		WARN("can't alloc extra data !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1142 1143 1144 1145 1146
		return MMSYSERR_NOMEM;
	    }
	    MidiOutDev[wDevID].lpExtra = extra;
	    if (midiOpenSeq() < 0) {
		MidiOutDev[wDevID].lpExtra = 0;
1147
		HeapFree(GetProcessHeap(), 0, extra);
Alexandre Julliard's avatar
Alexandre Julliard committed
1148 1149 1150 1151 1152
		return MMSYSERR_ERROR;
	    }
	    if (modFMLoad(wDevID) < 0) {
		midiCloseSeq();
		MidiOutDev[wDevID].lpExtra = 0;
1153
		HeapFree(GetProcessHeap(), 0, extra);
Alexandre Julliard's avatar
Alexandre Julliard committed
1154 1155 1156
		return MMSYSERR_ERROR;
	    }
	    modFMReset(wDevID);
Alexandre Julliard's avatar
Alexandre Julliard committed
1157
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1158 1159
	break;
    case MOD_MIDIPORT:
Christian Costa's avatar
Christian Costa committed
1160
    case MOD_SYNTH:
Alexandre Julliard's avatar
Alexandre Julliard committed
1161 1162
	if (midiOpenSeq() < 0) {
	    return MMSYSERR_ALLOCATED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1163
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1164 1165
	break;
    default:
1166
	WARN("Technology not supported (yet) %d !\n",
1167
	     MidiOutDev[wDevID].caps.wTechnology);
Alexandre Julliard's avatar
Alexandre Julliard committed
1168 1169
	return MMSYSERR_NOTENABLED;
    }
1170

Alexandre Julliard's avatar
Alexandre Julliard committed
1171
    MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1172

Alexandre Julliard's avatar
Alexandre Julliard committed
1173 1174 1175
    MidiOutDev[wDevID].lpQueueHdr = NULL;
    MidiOutDev[wDevID].dwTotalPlayed = 0;
    MidiOutDev[wDevID].bufsize = 0x3FFF;
1176
    MidiOutDev[wDevID].midiDesc = *lpDesc;
1177

Alexandre Julliard's avatar
Alexandre Julliard committed
1178
    if (MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
1179
	WARN("can't notify client !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1180 1181
	return MMSYSERR_INVALPARAM;
    }
Andreas Mohr's avatar
Andreas Mohr committed
1182
    TRACE("Successful !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1183
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1184 1185 1186 1187
}


/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1188 1189
 * 			modClose				[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1190
static DWORD modClose(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
1191
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1192 1193
    int	ret = MMSYSERR_NOERROR;

1194
    TRACE("(%04X);\n", wDevID);
1195

1196
    if (MidiOutDev[wDevID].midiDesc.hMidi == 0) {
1197
	WARN("device not opened !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1198 1199 1200 1201
	return MMSYSERR_ERROR;
    }
    /* FIXME: should test that no pending buffer is still in the queue for
     * playing */
1202

Alexandre Julliard's avatar
Alexandre Julliard committed
1203
    if (midiSeqFD == -1) {
1204
	WARN("can't close !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1205 1206
	return MMSYSERR_ERROR;
    }
1207

1208
    switch (MidiOutDev[wDevID].caps.wTechnology) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1209 1210 1211 1212 1213
    case MOD_FMSYNTH:
    case MOD_MIDIPORT:
	midiCloseSeq();
	break;
    default:
1214
	WARN("Technology not supported (yet) %d !\n",
1215
	     MidiOutDev[wDevID].caps.wTechnology);
Alexandre Julliard's avatar
Alexandre Julliard committed
1216 1217
	return MMSYSERR_NOTENABLED;
    }
1218

1219 1220
    HeapFree(GetProcessHeap(), 0, MidiOutDev[wDevID].lpExtra);
    MidiOutDev[wDevID].lpExtra = 0;
1221

Alexandre Julliard's avatar
Alexandre Julliard committed
1222 1223
    MidiOutDev[wDevID].bufsize = 0;
    if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
1224
	WARN("can't notify client !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1225 1226
	ret = MMSYSERR_INVALPARAM;
    }
1227
    MidiOutDev[wDevID].midiDesc.hMidi = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1228
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1229 1230 1231
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1232 1233
 * 			modData					[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1234
static DWORD modData(WORD wDevID, DWORD dwParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1235
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1236 1237 1238
    WORD	evt = LOBYTE(LOWORD(dwParam));
    WORD	d1  = HIBYTE(LOWORD(dwParam));
    WORD	d2  = LOBYTE(HIWORD(dwParam));
1239

1240
    TRACE("(%04X, %08X);\n", wDevID, dwParam);
1241

1242 1243 1244
    if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;

Alexandre Julliard's avatar
Alexandre Julliard committed
1245
    if (midiSeqFD == -1) {
1246
	WARN("can't play !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1247 1248
	return MIDIERR_NODEVICE;
    }
1249
    switch (MidiOutDev[wDevID].caps.wTechnology) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1250 1251 1252 1253 1254
    case MOD_FMSYNTH:
	/* FIXME:
	 *	- chorus depth controller is not used
	 */
	{
1255
            sFMextra*   extra   = MidiOutDev[wDevID].lpExtra;
Alexandre Julliard's avatar
Alexandre Julliard committed
1256 1257 1258 1259
	    sVoice* 	voice   = extra->voice;
	    sChannel*	channel = extra->channel;
	    int		chn = (evt & 0x0F);
	    int		i, nv;
1260

Alexandre Julliard's avatar
Alexandre Julliard committed
1261 1262
	    switch (evt & 0xF0) {
	    case MIDI_NOTEOFF:
1263
		for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1264 1265 1266 1267 1268 1269
				/* don't stop sustained notes */
		    if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) {
			voice[i].status = sVS_UNUSED;
			SEQ_STOP_NOTE(wDevID, i, d1, d2);
		    }
		}
1270
		break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1271 1272
	    case MIDI_NOTEON:
		if (d2 == 0) { /* note off if velocity == 0 */
1273
		    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286
			/* don't stop sustained notes */
			if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) {
			    voice[i].status = sVS_UNUSED;
			    SEQ_STOP_NOTE(wDevID, i, d1, 64);
			}
		    }
		    break;
		}
		/* finding out in this order :
		 *	- an empty voice
		 *	- if replaying the same note on the same channel
		 *	- the older voice (LRU)
		 */
1287
		for (i = nv = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
1288
		    if (voice[i].status == sVS_UNUSED ||
Alexandre Julliard's avatar
Alexandre Julliard committed
1289 1290 1291 1292 1293 1294 1295 1296
			(voice[i].note == d1 && voice[i].channel == chn)) {
			nv = i;
			break;
		    }
		    if (voice[i].cntMark < voice[0].cntMark) {
			nv = i;
		    }
		}
1297
		TRACE(
Alexandre Julliard's avatar
Alexandre Julliard committed
1298
		      "playing on voice=%d, pgm=%d, pan=0x%02X, vol=0x%02X, "
1299 1300 1301 1302
		      "bender=0x%02X, note=0x%02X, vel=0x%02X\n",
		      nv, channel[chn].program,
		      channel[chn].balance,
		      channel[chn].volume,
Alexandre Julliard's avatar
Alexandre Julliard committed
1303
		      channel[chn].bender, d1, d2);
1304 1305

		SEQ_SET_PATCH(wDevID, nv, IS_DRUM_CHANNEL(extra, chn) ?
Alexandre Julliard's avatar
Alexandre Julliard committed
1306 1307 1308 1309 1310
			      (128 + d1) : channel[chn].program);
		SEQ_BENDER_RANGE(wDevID, nv, channel[chn].benderRange * 100);
		SEQ_BENDER(wDevID, nv, channel[chn].bender);
		SEQ_CONTROL(wDevID, nv, CTL_PAN, channel[chn].balance);
		SEQ_CONTROL(wDevID, nv, CTL_EXPRESSION, channel[chn].expression);
1311
#if 0
Alexandre Julliard's avatar
Alexandre Julliard committed
1312 1313 1314 1315
		/* FIXME: does not really seem to work on my SB card and
		 * screws everything up... so lay it down
		 */
		SEQ_CONTROL(wDevID, nv, CTL_MAIN_VOLUME, channel[chn].volume);
1316
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
1317 1318 1319 1320 1321 1322 1323
		SEQ_START_NOTE(wDevID, nv, d1, d2);
		voice[nv].status = channel[chn].sustain ? sVS_SUSTAINED : sVS_PLAYING;
		voice[nv].note = d1;
		voice[nv].channel = chn;
		voice[nv].cntMark = extra->counter++;
		break;
	    case MIDI_KEY_PRESSURE:
1324
		for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
		    if (voice[i].status != sVS_UNUSED && voice[i].channel == chn && voice[i].note == d1) {
			SEQ_KEY_PRESSURE(wDevID, i, d1, d2);
		    }
		}
		break;
	    case MIDI_CTL_CHANGE:
		switch (d1) {
		case CTL_BANK_SELECT:	channel[chn].bank = d2;		break;
		case CTL_MAIN_VOLUME:	channel[chn].volume = d2;	break;
		case CTL_PAN:		channel[chn].balance = d2;	break;
		case CTL_EXPRESSION:	channel[chn].expression = d2;	break;
		case CTL_SUSTAIN:	channel[chn].sustain = d2;
		    if (d2) {
1338
			for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1339 1340 1341 1342 1343
			    if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {
				voice[i].status = sVS_SUSTAINED;
			    }
			}
		    } else {
1344
			for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1345 1346 1347 1348 1349 1350 1351 1352 1353 1354
			    if (voice[i].status == sVS_SUSTAINED && voice[i].channel == chn) {
				voice[i].status = sVS_UNUSED;
				SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
			    }
			}
		    }
		    break;
		case CTL_NONREG_PARM_NUM_LSB:	channel[chn].nrgPmtLSB = d2;	break;
		case CTL_NONREG_PARM_NUM_MSB:	channel[chn].nrgPmtMSB = d2;	break;
		case CTL_REGIST_PARM_NUM_LSB:	channel[chn].regPmtLSB = d2;	break;
1355
		case CTL_REGIST_PARM_NUM_MSB:	channel[chn].regPmtMSB = d2;	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1356 1357
		case CTL_DATA_ENTRY:
		    switch ((channel[chn].regPmtMSB << 8) | channel[chn].regPmtLSB) {
1358
		    case 0x0000:
Alexandre Julliard's avatar
Alexandre Julliard committed
1359 1360
			if (channel[chn].benderRange != d2) {
			    channel[chn].benderRange = d2;
1361
			    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1362 1363 1364 1365 1366 1367
				if (voice[i].channel == chn) {
				    SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);
				}
			    }
			}
			break;
1368

Alexandre Julliard's avatar
Alexandre Julliard committed
1369 1370
		    case 0x7F7F:
			channel[chn].benderRange = 2;
1371
			for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1372 1373 1374 1375 1376 1377
			    if (voice[i].channel == chn) {
				SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);
			    }
			}
			break;
		    default:
1378
			TRACE("Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1379 1380 1381 1382 1383 1384
			      channel[chn].regPmtMSB, channel[chn].regPmtLSB,
			      channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB,
			      d2);
			break;
		    }
		    break;
1385

Alexandre Julliard's avatar
Alexandre Julliard committed
1386
		case 0x78: /* all sounds off */
1387
		    /* FIXME: I don't know if I have to take care of the channel
1388 1389
		     * for this control ?
		     */
1390
		    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1391 1392
			if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) {
			    voice[i].status = sVS_UNUSED;
1393
			    SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
Alexandre Julliard's avatar
Alexandre Julliard committed
1394 1395 1396 1397
			}
		    }
		    break;
		case 0x7B: /* all notes off */
1398
		    /* FIXME: I don't know if I have to take care of the channel
1399 1400
		     * for this control ?
		     */
1401
		    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1402 1403
			if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {
			    voice[i].status = sVS_UNUSED;
1404
			    SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
Alexandre Julliard's avatar
Alexandre Julliard committed
1405 1406
			}
		    }
1407
		    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1408
		default:
1409
		    TRACE("Dropping MIDI control event 0x%02x(%02x) on channel %d\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1410 1411 1412 1413 1414 1415 1416 1417
			  d1, d2, chn);
		    break;
		}
		break;
	    case MIDI_PGM_CHANGE:
		channel[chn].program = d1;
		break;
	    case MIDI_CHN_PRESSURE:
1418
		for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1419 1420 1421 1422 1423 1424 1425
		    if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) {
			SEQ_KEY_PRESSURE(wDevID, i, voice[i].note, d1);
		    }
		}
		break;
	    case MIDI_PITCH_BEND:
		channel[chn].bender = (d2 << 7) + d1;
1426
		for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1427 1428 1429 1430 1431 1432 1433 1434 1435
		    if (voice[i].channel == chn) {
			SEQ_BENDER(wDevID, i, channel[chn].bender);
		    }
		}
		break;
	    case MIDI_SYSTEM_PREFIX:
		switch (evt & 0x0F) {
		case 0x0F: 	/* Reset */
		    modFMReset(wDevID);
1436
		    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1437
		default:
1438
		    WARN("Unsupported (yet) system event %02x\n", evt & 0x0F);
Alexandre Julliard's avatar
Alexandre Julliard committed
1439 1440
		}
		break;
1441
	    default:
1442
		WARN("Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1443 1444 1445 1446 1447 1448
		return MMSYSERR_NOTENABLED;
	    }
	}
	break;
    case MOD_MIDIPORT:
	{
1449
	    int	dev = wDevID - MODM_NumFMSynthDevs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1450
	    if (dev < 0) {
1451
		WARN("Internal error on devID (%u) !\n", wDevID);
Alexandre Julliard's avatar
Alexandre Julliard committed
1452
		return MIDIERR_NODEVICE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1453
	    }
1454

Alexandre Julliard's avatar
Alexandre Julliard committed
1455 1456 1457 1458 1459 1460
	    switch (evt & 0xF0) {
	    case MIDI_NOTEOFF:
	    case MIDI_NOTEON:
	    case MIDI_KEY_PRESSURE:
	    case MIDI_CTL_CHANGE:
	    case MIDI_PITCH_BEND:
1461 1462 1463
		SEQ_MIDIOUT(dev, evt);
		SEQ_MIDIOUT(dev, d1);
		SEQ_MIDIOUT(dev, d2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1464 1465 1466
		break;
	    case MIDI_PGM_CHANGE:
	    case MIDI_CHN_PRESSURE:
1467 1468 1469
		SEQ_MIDIOUT(dev, evt);
		SEQ_MIDIOUT(dev, d1);
		break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1470 1471
	    case MIDI_SYSTEM_PREFIX:
		switch (evt & 0x0F) {
1472
		case 0x00:	/* System Exclusive, don't do it on modData,
Alexandre Julliard's avatar
Alexandre Julliard committed
1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
				 * should require modLongData*/
		case 0x01:	/* Undefined */
		case 0x04:	/* Undefined. */
		case 0x05:	/* Undefined. */
		case 0x07:	/* End of Exclusive. */
		case 0x09:	/* Undefined. */
		case 0x0D:	/* Undefined. */
		    break;
		case 0x06:	/* Tune Request */
		case 0x08:	/* Timing Clock. */
		case 0x0A:	/* Start. */
		case 0x0B:	/* Continue */
		case 0x0C:	/* Stop */
		case 0x0E: 	/* Active Sensing. */
1487
		    SEQ_MIDIOUT(dev, evt);
Alexandre Julliard's avatar
Alexandre Julliard committed
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
		    break;
		case 0x0F: 	/* Reset */
				/* SEQ_MIDIOUT(dev, evt);
				   this other way may be better */
		    SEQ_MIDIOUT(dev, MIDI_SYSTEM_PREFIX);
		    SEQ_MIDIOUT(dev, 0x7e);
		    SEQ_MIDIOUT(dev, 0x7f);
		    SEQ_MIDIOUT(dev, 0x09);
		    SEQ_MIDIOUT(dev, 0x01);
		    SEQ_MIDIOUT(dev, 0xf7);
		    break;
		case 0x03:	/* Song Select. */
1500 1501
		    SEQ_MIDIOUT(dev, evt);
		    SEQ_MIDIOUT(dev, d1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1502
		case 0x02:	/* Song Position Pointer. */
1503
		    SEQ_MIDIOUT(dev, evt);
Alexandre Julliard's avatar
Alexandre Julliard committed
1504 1505 1506 1507 1508
		    SEQ_MIDIOUT(dev, d1);
		    SEQ_MIDIOUT(dev, d2);
		}
		break;
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1509
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1510 1511
	break;
    default:
1512
	WARN("Technology not supported (yet) %d !\n",
1513
	     MidiOutDev[wDevID].caps.wTechnology);
Alexandre Julliard's avatar
Alexandre Julliard committed
1514 1515
	return MMSYSERR_NOTENABLED;
    }
1516

Alexandre Julliard's avatar
Alexandre Julliard committed
1517
    SEQ_DUMPBUF();
1518

Alexandre Julliard's avatar
Alexandre Julliard committed
1519
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1520 1521 1522
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1523 1524
 *		modLongData					[internal]
 */
1525
static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1526
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1527
    int		count;
1528 1529
    LPBYTE	lpData;

1530
    TRACE("(%04X, %p, %08X);\n", wDevID, lpMidiHdr, dwSize);
1531

Christian Costa's avatar
Christian Costa committed
1532 1533 1534 1535 1536
    /* Note: MS doc does not say much about the dwBytesRecorded member of the MIDIHDR structure
     * but it seems to be used only for midi input.
     * Taking a look at the WAVEHDR structure (which is quite similar) confirms this assumption.
     */
    
1537 1538 1539
    if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;

Alexandre Julliard's avatar
Alexandre Julliard committed
1540
    if (midiSeqFD == -1) {
1541
	WARN("can't play !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1542 1543
	return MIDIERR_NODEVICE;
    }
1544

Mike McCormack's avatar
Mike McCormack committed
1545
    lpData = (LPBYTE) lpMidiHdr->lpData;
1546

1547
    if (lpData == NULL)
Alexandre Julliard's avatar
Alexandre Julliard committed
1548
	return MIDIERR_UNPREPARED;
1549
    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED))
Alexandre Julliard's avatar
Alexandre Julliard committed
1550
	return MIDIERR_UNPREPARED;
1551
    if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1552 1553 1554
	return MIDIERR_STILLPLAYING;
    lpMidiHdr->dwFlags &= ~MHDR_DONE;
    lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1555

1556
    /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive
1557
     * data, or can it also contain raw MIDI data, to be split up and sent to
1558 1559 1560
     * modShortData() ?
     * If the latest is true, then the following WARNing will fire up
     */
1561 1562
    if (lpData[0] != 0xF0 || lpData[lpMidiHdr->dwBufferLength - 1] != 0xF7) {
	WARN("Alledged system exclusive buffer is not correct\n\tPlease report with MIDI file\n");
1563 1564
    }

1565
    TRACE("dwBufferLength=%u !\n", lpMidiHdr->dwBufferLength);
1566
    TRACE("                 %02X %02X %02X ... %02X %02X %02X\n",
1567
	  lpData[0], lpData[1], lpData[2], lpData[lpMidiHdr->dwBufferLength-3],
1568
	  lpData[lpMidiHdr->dwBufferLength-2], lpData[lpMidiHdr->dwBufferLength-1]);
1569

1570
    switch (MidiOutDev[wDevID].caps.wTechnology) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1571 1572 1573 1574
    case MOD_FMSYNTH:
	/* FIXME: I don't think there is much to do here */
	break;
    case MOD_MIDIPORT:
1575
	if (lpData[0] != 0xF0) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1576
	    /* Send end of System Exclusive */
1577
	    SEQ_MIDIOUT(wDevID - MODM_NumFMSynthDevs, 0xF0);
1578
	    WARN("Adding missing 0xF0 marker at the beginning of "
1579
		 "system exclusive byte stream\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1580
	}
Christian Costa's avatar
Christian Costa committed
1581
	for (count = 0; count < lpMidiHdr->dwBufferLength; count++) {
1582
	    SEQ_MIDIOUT(wDevID - MODM_NumFMSynthDevs, lpData[count]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1583
	}
1584
	if (lpData[count - 1] != 0xF7) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1585
	    /* Send end of System Exclusive */
1586
	    SEQ_MIDIOUT(wDevID - MODM_NumFMSynthDevs, 0xF7);
1587
	    WARN("Adding missing 0xF7 marker at the end of "
1588
		 "system exclusive byte stream\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1589 1590 1591 1592
	}
	SEQ_DUMPBUF();
	break;
    default:
1593
	WARN("Technology not supported (yet) %d !\n",
1594
	     MidiOutDev[wDevID].caps.wTechnology);
Alexandre Julliard's avatar
Alexandre Julliard committed
1595 1596
	return MMSYSERR_NOTENABLED;
    }
1597

Alexandre Julliard's avatar
Alexandre Julliard committed
1598 1599
    lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
    lpMidiHdr->dwFlags |= MHDR_DONE;
1600
    if (MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD_PTR)lpMidiHdr, 0L) != MMSYSERR_NOERROR) {
1601
	WARN("can't notify client !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1602 1603 1604
	return MMSYSERR_INVALPARAM;
    }
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1605 1606 1607
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1608 1609
 * 			modPrepare				[internal]
 */
1610
static DWORD modPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1611
{
1612
    TRACE("(%04X, %p, %08X);\n", wDevID, lpMidiHdr, dwSize);
1613

Alexandre Julliard's avatar
Alexandre Julliard committed
1614
    if (midiSeqFD == -1) {
1615
	WARN("can't prepare !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1616 1617
	return MMSYSERR_NOTENABLED;
    }
1618

1619
    /* MS doc says that dwFlags must be set to zero, but (kinda funny) MS mciseq drivers
1620 1621 1622
     * asks to prepare MIDIHDR which dwFlags != 0.
     * So at least check for the inqueue flag
     */
1623 1624
    if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 ||
	lpMidiHdr->lpData == 0 || (lpMidiHdr->dwFlags & MHDR_INQUEUE) != 0 ||
1625
	lpMidiHdr->dwBufferLength >= 0x10000ul) {
1626 1627
	WARN("%p %p %08x %d\n", lpMidiHdr, lpMidiHdr ? lpMidiHdr->lpData : NULL,
	           lpMidiHdr ? lpMidiHdr->dwFlags : 0, dwSize);
Alexandre Julliard's avatar
Alexandre Julliard committed
1628
	return MMSYSERR_INVALPARAM;
1629
    }
1630

Alexandre Julliard's avatar
Alexandre Julliard committed
1631 1632 1633 1634
    lpMidiHdr->lpNext = 0;
    lpMidiHdr->dwFlags |= MHDR_PREPARED;
    lpMidiHdr->dwFlags &= ~MHDR_DONE;
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1635 1636 1637
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1638 1639
 * 				modUnprepare			[internal]
 */
1640
static DWORD modUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1641
{
1642
    TRACE("(%04X, %p, %08X);\n", wDevID, lpMidiHdr, dwSize);
1643

Alexandre Julliard's avatar
Alexandre Julliard committed
1644
    if (midiSeqFD == -1) {
1645
	WARN("can't unprepare !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1646 1647
	return MMSYSERR_NOTENABLED;
    }
1648

1649
    if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1650 1651 1652 1653 1654
	return MMSYSERR_INVALPARAM;
    if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
	return MIDIERR_STILLPLAYING;
    lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1655 1656 1657
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1658 1659
 * 			modReset				[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1660
static DWORD modReset(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
1661
{
1662
    unsigned chn;
1663

1664
    TRACE("(%04X);\n", wDevID);
1665

1666 1667 1668
    if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;

1669
    /* stop all notes */
1670
    /* FIXME: check if 0x78B0 is channel dependent or not. I coded it so that
1671
     * it's channel dependent...
Alexandre Julliard's avatar
Alexandre Julliard committed
1672
     */
1673 1674 1675 1676 1677 1678 1679 1680
    for (chn = 0; chn < 16; chn++) {
	/* turn off every note */
	modData(wDevID, 0x7800 | MIDI_CTL_CHANGE | chn);
	/* remove sustain on all channels */
	modData(wDevID, (CTL_SUSTAIN << 8) | MIDI_CTL_CHANGE | chn);
    }
    /* FIXME: the LongData buffers must also be returned to the app */
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1681
}
1682

1683 1684
#else /* HAVE_OSS_MIDI */

1685
LRESULT OSS_MidiInit(void)
1686
{
1687
    TRACE("()\n");
1688 1689 1690
    return FALSE;
}

1691 1692 1693 1694 1695 1696 1697
LRESULT OSS_MidiExit(void)
{
    TRACE("()\n");
    return 0;
}


1698
#endif /* HAVE_OSS_MIDI */
Alexandre Julliard's avatar
Alexandre Julliard committed
1699

1700 1701 1702 1703
/*======================================================================*
 *                  	    MIDI entry points 				*
 *======================================================================*/

1704
/**************************************************************************
1705
 * 			midMessage (WINEOSS.@)
1706
 */
1707 1708
DWORD WINAPI OSS_midMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
			    DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1709
{
1710
    TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n",
1711 1712
	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
    switch (wMsg) {
1713
#ifdef HAVE_OSS_MIDI
1714
    case DRVM_INIT:
1715
    case DRVM_EXIT:
1716 1717 1718 1719
    case DRVM_ENABLE:
    case DRVM_DISABLE:
	/* FIXME: Pretend this is supported */
	return 0;
1720
    case MIDM_OPEN:
1721
	return midOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
1722 1723 1724
    case MIDM_CLOSE:
	return midClose(wDevID);
    case MIDM_ADDBUFFER:
1725
	return midAddBuffer(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1726
    case MIDM_PREPARE:
1727
	return midPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1728
    case MIDM_UNPREPARE:
1729
	return midUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1730
    case MIDM_GETDEVCAPS:
1731
	return midGetDevCaps(wDevID, (LPMIDIINCAPSW)dwParam1,dwParam2);
1732
    case MIDM_GETNUMDEVS:
1733
	return MIDM_NumDevs;
1734 1735 1736 1737 1738 1739 1740 1741
    case MIDM_RESET:
	return midReset(wDevID);
    case MIDM_START:
	return midStart(wDevID);
    case MIDM_STOP:
	return midStop(wDevID);
#endif
    default:
1742
	TRACE("Unsupported message\n");
1743 1744 1745 1746
    }
    return MMSYSERR_NOTSUPPORTED;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1747
/**************************************************************************
1748
 * 				modMessage (WINEOSS.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1749
 */
1750 1751
DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
			    DWORD_PTR dwParam1, DWORD_PTR dwParam2)
Alexandre Julliard's avatar
Alexandre Julliard committed
1752
{
1753
    TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1754
	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
1755 1756

    switch (wMsg) {
1757
#ifdef HAVE_OSS_MIDI
1758 1759 1760 1761 1762 1763
    case DRVM_INIT:
    case DRVM_EXIT:
    case DRVM_ENABLE:
    case DRVM_DISABLE:
	/* FIXME: Pretend this is supported */
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1764 1765 1766 1767 1768 1769 1770
    case MODM_OPEN:
	return modOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
    case MODM_CLOSE:
	return modClose(wDevID);
    case MODM_DATA:
	return modData(wDevID, dwParam1);
    case MODM_LONGDATA:
1771
	return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1772
    case MODM_PREPARE:
1773
	return modPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1774
    case MODM_UNPREPARE:
1775
	return modUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1776
    case MODM_GETDEVCAPS:
1777
	return modGetDevCaps(wDevID, (LPMIDIOUTCAPSW)dwParam1, dwParam2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1778
    case MODM_GETNUMDEVS:
1779
	return MODM_NumDevs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1780 1781 1782 1783 1784 1785
    case MODM_GETVOLUME:
	return 0;
    case MODM_SETVOLUME:
	return 0;
    case MODM_RESET:
	return modReset(wDevID);
1786
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
1787
    default:
1788
	TRACE("Unsupported message\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1789 1790
    }
    return MMSYSERR_NOTSUPPORTED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1791 1792 1793
}

/*-----------------------------------------------------------------------*/