midi.c 53.1 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
#include <sys/soundcard.h>
64

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

74
WINE_DEFAULT_DEBUG_CHANNEL(midi);
75

76
#ifdef SNDCTL_SEQ_NRMIDIS
77

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

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

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

106 107
/* 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
108
/* this is the number of FM synthesizers (index from 0 to NUMFMSYNTHDEVS - 1) */
109 110
static	int		MODM_NumFMSynthDevs = 0;
/* the Midi ports have index from NUMFMSYNTHDEVS to NumDevs - 1 */
Alexandre Julliard's avatar
Alexandre Julliard committed
111 112

/* this is the total number of MIDI out devices found */
113
static	int 		MIDM_NumDevs = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
114 115 116 117 118

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

119 120 121 122 123
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 },
124
      0, 0, { (DWORD_PTR)(__FILE__ ": crit_sect") }
125 126 127 128 129 130
};
static CRITICAL_SECTION crit_sect = { &critsect_debug, -1, 0, 0, 0, 0 };

static int end_thread;
static HANDLE hThread;

131
/*======================================================================*
132
 *                  Low level MIDI implementation			*
133
 *======================================================================*/
134

135 136 137
static int midiOpenSeq(void);
static int midiCloseSeq(void);

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

    /* FIXME Is this really the correct equivalence from UNIX to
156
       Windows Sound type */
157

158 159 160 161 162 163 164 165 166 167 168
    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;
    }
}

169
static int MIDI_loadcount;
170
/**************************************************************************
171
 * 			OSS_MidiInit				[internal]
172 173 174
 *
 * Initializes the MIDI devices information variables
 */
175
static LRESULT OSS_MidiInit(void)
176 177 178 179
{
    int 		i, status, numsynthdevs = 255, nummididevs = 255;
    struct synth_info 	sinfo;
    struct midi_info 	minfo;
180

181 182 183
    TRACE("(%i)\n", MIDI_loadcount);
    if (MIDI_loadcount++)
        return 1;
184

185
    TRACE("Initializing the MIDI variables.\n");
186

187
    /* try to open device */
188
    if (midiOpenSeq() == -1) {
189
	return -1;
190
    }
191

192
    /* find how many Synth devices are there in the system */
193
    status = ioctl(midiSeqFD, SNDCTL_SEQ_NRSYNTHS, &numsynthdevs);
194

195 196
    if (status == -1) {
	ERR("ioctl for nr synth failed.\n");
197
	midiCloseSeq();
198
	return -1;
199 200 201 202 203 204 205
    }

    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;
    }
206

207 208 209 210 211
    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.
	 */
212 213
	MidiOutDev[i].caps.wMid = 0x00FF;
	MidiOutDev[i].caps.wPid = 0x0001; 	/* FIXME Product ID  */
214
	/* Product Version. We simply say "1" */
215
	MidiOutDev[i].caps.vDriverVersion = 0x001;
216
	/* The following are mandatory for MOD_MIDIPORT */
217
	MidiOutDev[i].caps.wChannelMask   = 0xFFFF;
218 219 220
	MidiOutDev[i].caps.wVoices        = 0;
	MidiOutDev[i].caps.wNotes         = 0;
	MidiOutDev[i].caps.dwSupport      = 0;
221 222 223 224

	sinfo.device = i;
	status = ioctl(midiSeqFD, SNDCTL_SYNTH_INFO, &sinfo);
	if (status == -1) {
225
            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};
226 227
	    ERR("ioctl for synth info failed on %d, disabling it.\n", i);

228
            wsprintfW(MidiOutDev[i].caps.szPname, fmt, i);
229 230 231 232

            MidiOutDev[i].caps.wTechnology = MOD_MIDIPORT;
            MidiOutDev[i].bEnabled = FALSE;
	} else {
233
            MultiByteToWideChar( CP_UNIXCP, 0, sinfo.name, -1,
234 235
                                 MidiOutDev[i].caps.szPname,
                                 sizeof(MidiOutDev[i].caps.szPname)/sizeof(WCHAR) );
236 237
            MidiOutDev[i].caps.wTechnology = MIDI_UnixToWindowsDeviceType(sinfo.synth_type);

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
            if (MOD_MIDIPORT != MidiOutDev[i].caps.wTechnology) {
                /* FIXME Do we have this information?
                 * Assuming the soundcards can handle
                 * MIDICAPS_VOLUME and MIDICAPS_LRVOLUME but
                 * not MIDICAPS_CACHE.
                 */
                MidiOutDev[i].caps.dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;
                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;
            }
254 255
            MidiOutDev[i].bEnabled = TRUE;

256 257 258 259 260 261 262 263
            /* We also have the information sinfo.synth_subtype, not used here
             */
            if (sinfo.capabilities & SYNTH_CAP_INPUT) {
                FIXME("Synthesizer supports MIDI in. Not yet supported.\n");
            }
            TRACE("SynthOut[%d]\tOSS info: synth type=%d/%d capa=%lx\n",
                  i, sinfo.synth_type, sinfo.synth_subtype, (long)sinfo.capabilities);
        }
264

265
        TRACE("SynthOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%d\n",
266 267
	      i, wine_dbgstr_w(MidiOutDev[i].caps.szPname), 
              MidiOutDev[i].caps.wTechnology, 
268
              MidiOutDev[i].caps.wVoices, MidiOutDev[i].caps.wNotes, 
269
              MidiOutDev[i].caps.wChannelMask, MidiOutDev[i].caps.dwSupport);
270
    }
271

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

280
    /* FIXME: the two restrictions below could be loosened in some cases */
281 282 283 284 285
    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;
    }
286

287 288 289 290 291
    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;
    }
292

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

298
	/* This whole part is somewhat obscure to me. I'll keep trying to dig
299
	   info about it. If you happen to know, please tell us. The very
Austin English's avatar
Austin English committed
300
	   descriptive minfo.dev_type was not used here.
301
	*/
Austin English's avatar
Austin English committed
302
	/* Manufacturer ID. We do not have access to this with soundcard.h
303 304
	   Does not seem to be a problem, because in mmsystem.h only
	   Microsoft's ID is listed */
305 306
	MidiOutDev[numsynthdevs + i].caps.wMid = 0x00FF;
	MidiOutDev[numsynthdevs + i].caps.wPid = 0x0001; 	/* FIXME Product ID */
307
	/* Product Version. We simply say "1" */
308 309
	MidiOutDev[numsynthdevs + i].caps.vDriverVersion = 0x001;
        if (status == -1) {
310
            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};
311
            wsprintfW(MidiOutDev[numsynthdevs + i].caps.szPname, fmt, numsynthdevs + i);
312 313
            MidiOutDev[numsynthdevs + i].bEnabled = FALSE;
        } else {
314
            MultiByteToWideChar(CP_UNIXCP, 0, minfo.name, -1,
315 316
                                MidiOutDev[numsynthdevs + i].caps.szPname,
                                sizeof(MidiOutDev[numsynthdevs + i].caps.szPname) / sizeof(WCHAR));
317 318
            MidiOutDev[numsynthdevs + i].bEnabled = TRUE;
        }
319 320 321
	MidiOutDev[numsynthdevs + i].caps.wTechnology = MOD_MIDIPORT;
	MidiOutDev[numsynthdevs + i].caps.wVoices     = 0;
	MidiOutDev[numsynthdevs + i].caps.wNotes      = 0;
322
	MidiOutDev[numsynthdevs + i].caps.wChannelMask= 0xFFFF;
323
	MidiOutDev[numsynthdevs + i].caps.dwSupport   = 0;
324

325
	/* This whole part is somewhat obscure to me. I'll keep trying to dig
326
	   info about it. If you happen to know, please tell us. The very
327
	   descriptive minfo.dev_type was not used here.
328 329 330 331
	*/
	/* 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 */
332 333
	MidiInDev[i].caps.wMid = 0x00FF;
	MidiInDev[i].caps.wPid = 0x0001; 	/* FIXME Product ID */
334
	/* Product Version. We simply say "1" */
335 336
	MidiInDev[i].caps.vDriverVersion = 0x001;
        if (status == -1) {
337
            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};
338
            wsprintfW(MidiInDev[i].caps.szPname, fmt, numsynthdevs + i);
339 340
            MidiInDev[i].state = -1;
        } else {
341
            MultiByteToWideChar(CP_UNIXCP, 0, minfo.name, -1,
342 343
                                MidiInDev[i].caps.szPname,
                                sizeof(MidiInDev[i].caps.szPname) / sizeof(WCHAR));
344 345
            MidiInDev[i].state = 0;
        }
346
	MidiInDev[i].caps.dwSupport   = 0; /* mandatory with MIDIINCAPS */
347

348 349 350 351 352
        TRACE("OSS info: midi[%d] dev-type=%d capa=%lx\n"
              "\tMidiOut[%d] name='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%d\n"
              "\tMidiIn [%d] name='%s' support=%d\n",
              i, minfo.dev_type, (long)minfo.capabilities,
              numsynthdevs + i, wine_dbgstr_w(MidiOutDev[numsynthdevs + i].caps.szPname),
353
              MidiOutDev[numsynthdevs + i].caps.wTechnology,
354 355
	      MidiOutDev[numsynthdevs + i].caps.wVoices, MidiOutDev[numsynthdevs + i].caps.wNotes,
	      MidiOutDev[numsynthdevs + i].caps.wChannelMask, MidiOutDev[numsynthdevs + i].caps.dwSupport,
356
              i, wine_dbgstr_w(MidiInDev[i].caps.szPname), MidiInDev[i].caps.dwSupport);
357
    }
358

359
 wrapup:
360
    /* windows does not seem to differentiate Synth from MIDI devices */
361 362
    MODM_NumFMSynthDevs = numsynthdevs;
    MODM_NumDevs        = numsynthdevs + nummididevs;
363

364
    MIDM_NumDevs        = nummididevs;
365

366
    /* close file and exit */
367
    midiCloseSeq();
368

369 370 371 372 373 374 375 376
    return 0;
}

/**************************************************************************
 * 			OSS_MidiExit				[internal]
 *
 * Release the MIDI devices information variables
 */
377
static LRESULT OSS_MidiExit(void)
378
{
379 380 381 382
    TRACE("(%i)\n", MIDI_loadcount);

    if (--MIDI_loadcount)
        return 1;
383 384 385 386 387 388 389 390 391

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

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

    return 0;
392 393
}

Alexandre Julliard's avatar
Alexandre Julliard committed
394
/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
395 396
 * 			MIDI_NotifyClient			[internal]
 */
397
static void MIDI_NotifyClient(UINT wDevID, WORD wMsg,
398
			      DWORD_PTR dwParam1, DWORD_PTR dwParam2)
Alexandre Julliard's avatar
Alexandre Julliard committed
399
{
400
    DWORD_PTR 		dwCallBack;
401 402
    UINT 		uFlags;
    HANDLE		hDev;
403
    DWORD_PTR 		dwInstance;
404

405
    TRACE("wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
406
	  wDevID, wMsg, dwParam1, dwParam2);
407

Alexandre Julliard's avatar
Alexandre Julliard committed
408 409 410 411
    switch (wMsg) {
    case MOM_OPEN:
    case MOM_CLOSE:
    case MOM_DONE:
412
    case MOM_POSITIONCB:
413
	if (wDevID > MODM_NumDevs) return;
414

415
	dwCallBack = MidiOutDev[wDevID].midiDesc.dwCallback;
Alexandre Julliard's avatar
Alexandre Julliard committed
416
	uFlags = MidiOutDev[wDevID].wFlags;
417 418
	hDev = MidiOutDev[wDevID].midiDesc.hMidi;
	dwInstance = MidiOutDev[wDevID].midiDesc.dwInstance;
Alexandre Julliard's avatar
Alexandre Julliard committed
419
	break;
420

Alexandre Julliard's avatar
Alexandre Julliard committed
421 422 423
    case MIM_OPEN:
    case MIM_CLOSE:
    case MIM_DATA:
424
    case MIM_LONGDATA:
Alexandre Julliard's avatar
Alexandre Julliard committed
425
    case MIM_ERROR:
426 427
    case MIM_LONGERROR:
    case MIM_MOREDATA:
428
	if (wDevID > MIDM_NumDevs) return;
429

430
	dwCallBack = MidiInDev[wDevID].midiDesc.dwCallback;
Alexandre Julliard's avatar
Alexandre Julliard committed
431
	uFlags = MidiInDev[wDevID].wFlags;
432 433
	hDev = MidiInDev[wDevID].midiDesc.hMidi;
	dwInstance = MidiInDev[wDevID].midiDesc.dwInstance;
Alexandre Julliard's avatar
Alexandre Julliard committed
434 435
	break;
    default:
436 437
	ERR("Unsupported MSW-MIDI message %u\n", wMsg);
	return;
Alexandre Julliard's avatar
Alexandre Julliard committed
438
    }
439

440
    DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2);
Alexandre Julliard's avatar
Alexandre Julliard committed
441 442
}

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

Alexandre Julliard's avatar
Alexandre Julliard committed
486 487 488 489 490 491 492 493 494 495 496
/**************************************************************************
 * 			midiCloseSeq				[internal]
 */
static int midiCloseSeq(void)
{
    if (--numOpenMidiSeq == 0) {
	close(midiSeqFD);
	midiSeqFD = -1;
    }
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
497

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

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

525
/**************************************************************************
Francois Gouget's avatar
Francois Gouget committed
526
 * 			midReceiveChar				[internal]
527
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
528 529 530
static void midReceiveChar(WORD wDevID, unsigned char value, DWORD dwTime)
{
    DWORD		toSend = 0;
531

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

534
    if (wDevID >= MIDM_NumDevs) {
535
	WARN("bad devID\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
536 537
	return;
    }
538 539
    if (MidiInDev[wDevID].state <= 0) {
	TRACE("disabled or input not started, thrown away\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
540 541
	return;
    }
542

Alexandre Julliard's avatar
Alexandre Julliard committed
543
    if (MidiInDev[wDevID].state & 2) { /* system exclusive */
544
	LPMIDIHDR	lpMidiHdr;
545
        BOOL            sbfb = FALSE;
546

547 548
	EnterCriticalSection(&crit_sect);
	if ((lpMidiHdr = MidiInDev[wDevID].lpQueueHdr) != NULL) {
Mike McCormack's avatar
Mike McCormack committed
549
	    LPBYTE	lpData = (LPBYTE) lpMidiHdr->lpData;
550

551 552
	    lpData[lpMidiHdr->dwBytesRecorded++] = value;
	    if (lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) {
Alexandre Julliard's avatar
Alexandre Julliard committed
553
		sbfb = TRUE;
554
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
555 556 557 558 559
	}
	if (value == 0xF7) { /* then end */
	    MidiInDev[wDevID].state &= ~2;
	    sbfb = TRUE;
	}
560 561
	if (sbfb && lpMidiHdr != NULL) {
	    lpMidiHdr = MidiInDev[wDevID].lpQueueHdr;
562
	    MidiInDev[wDevID].lpQueueHdr = lpMidiHdr->lpNext;
563 564
	    lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
	    lpMidiHdr->dwFlags |= MHDR_DONE;
565
	    MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD_PTR)lpMidiHdr, dwTime);
Alexandre Julliard's avatar
Alexandre Julliard committed
566
	}
567
	LeaveCriticalSection(&crit_sect);
Alexandre Julliard's avatar
Alexandre Julliard committed
568 569
	return;
    }
570

Alexandre Julliard's avatar
Alexandre Julliard committed
571 572
#define IS_CMD(_x)	(((_x) & 0x80) == 0x80)
#define IS_SYS_CMD(_x)	(((_x) & 0xF0) == 0xF0)
573

Alexandre Julliard's avatar
Alexandre Julliard committed
574 575 576 577
    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;
578
	    TRACE("Reusing old command %02xh\n", MidiInDev[wDevID].incPrev);
Alexandre Julliard's avatar
Alexandre Julliard committed
579
	} else {
580
	    FIXME("error for midi-in, should generate MIM_ERROR notification:"
581
		  " prev=%02Xh, incLen=%02Xh\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
582 583 584 585 586 587 588 589 590
		  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];
    }
591 592 593 594

#undef IS_CMD
#undef IS_SYS_CMD

Alexandre Julliard's avatar
Alexandre Julliard committed
595 596 597 598 599 600 601
    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) {
602
	    toSend = (MidiInDev[wDevID].incoming[2] << 16) |
Alexandre Julliard's avatar
Alexandre Julliard committed
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
		(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;
618
	} else {
Alexandre Julliard's avatar
Alexandre Julliard committed
619 620 621 622 623 624
	    if (MidiInDev[wDevID].incLen == 1) {
		toSend = (MidiInDev[wDevID].incoming[0] <<  0);
	    }
	}
	break;
    default:
625
	WARN("This shouldn't happen (%02X)\n", MidiInDev[wDevID].incoming[0]);
Alexandre Julliard's avatar
Alexandre Julliard committed
626 627
    }
    if (toSend != 0) {
628
	TRACE("Sending event %08x\n", toSend);
Alexandre Julliard's avatar
Alexandre Julliard committed
629 630
	MidiInDev[wDevID].incLen =	0;
	dwTime -= MidiInDev[wDevID].startTime;
631
	MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime);
Alexandre Julliard's avatar
Alexandre Julliard committed
632 633
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
634

635
static DWORD WINAPI midRecThread(LPVOID arg)
Alexandre Julliard's avatar
Alexandre Julliard committed
636
{
Christian Costa's avatar
Christian Costa committed
637 638
    unsigned char buffer[256];
    int len, idx;
639 640
    DWORD dwTime;
    struct pollfd pfd;
641

642
    TRACE("Thread startup\n");
643

644
    pfd.fd = midiSeqFD;
645
    pfd.events = POLLIN;
646 647 648 649
    
    while(!end_thread) {
	TRACE("Thread loop\n");

650
	/* Check if an event is present */
651 652 653 654
	if (poll(&pfd, 1, 250) <= 0)
	    continue;
	
	len = read(midiSeqFD, buffer, sizeof(buffer));
655
	TRACE("Received %d bytes\n", len);
656 657 658 659 660 661

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

663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686
	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
687
	    }
688
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
689
    }
690
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
691
}
Alexandre Julliard's avatar
Alexandre Julliard committed
692 693

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
694 695
 * 				midGetDevCaps			[internal]
 */
696
static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPSW lpCaps, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
697
{
698
    TRACE("(%04X, %p, %08X);\n", wDevID, lpCaps, dwSize);
699

700
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
701 702
    if (lpCaps == NULL)		return MMSYSERR_INVALPARAM;

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

Alexandre Julliard's avatar
Alexandre Julliard committed
705
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
706 707 708
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
709 710
 * 			midOpen					[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
711
static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
712
{
713
    TRACE("(%04X, %p, %08X);\n", wDevID, lpDesc, dwFlags);
714

Alexandre Julliard's avatar
Alexandre Julliard committed
715
    if (lpDesc == NULL) {
716
	WARN("Invalid Parameter !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
717 718
	return MMSYSERR_INVALPARAM;
    }
719

Alexandre Julliard's avatar
Alexandre Julliard committed
720 721 722
    /* FIXME :
     *	how to check that content of lpDesc is correct ?
     */
723
    if (wDevID >= MIDM_NumDevs) {
724
	WARN("wDevID too large (%u) !\n", wDevID);
Alexandre Julliard's avatar
Alexandre Julliard committed
725 726
	return MMSYSERR_BADDEVICEID;
    }
727 728 729 730
    if (MidiInDev[wDevID].state == -1) {        
        WARN("device disabled\n");
        return MIDIERR_NODEVICE;
    }
731
    if (MidiInDev[wDevID].midiDesc.hMidi != 0) {
732
	WARN("device already open !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
733 734
	return MMSYSERR_ALLOCATED;
    }
735
    if ((dwFlags & MIDI_IO_STATUS) != 0) {
736 737 738
	WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n");
	dwFlags &= ~MIDI_IO_STATUS;
    }
739
    if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
740
	FIXME("Bad dwFlags\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
741 742
	return MMSYSERR_INVALFLAG;
    }
743

Alexandre Julliard's avatar
Alexandre Julliard committed
744 745 746
    if (midiOpenSeq() < 0) {
	return MMSYSERR_ERROR;
    }
747

Alexandre Julliard's avatar
Alexandre Julliard committed
748
    if (numStartedMidiIn++ == 0) {
749 750 751
	end_thread = 0;
	hThread = CreateThread(NULL, 0, midRecThread, NULL, 0, NULL);
	if (!hThread) {
Alexandre Julliard's avatar
Alexandre Julliard committed
752
	    numStartedMidiIn = 0;
753
	    WARN("Couldn't create thread for midi-in\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
754 755
	    midiCloseSeq();
	    return MMSYSERR_ERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
756
	}
757
        SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
758
	TRACE("Created thread for midi-in\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
759
    }
760

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

Alexandre Julliard's avatar
Alexandre Julliard committed
763 764 765
    MidiInDev[wDevID].lpQueueHdr = NULL;
    MidiInDev[wDevID].dwTotalPlayed = 0;
    MidiInDev[wDevID].bufsize = 0x3FFF;
766
    MidiInDev[wDevID].midiDesc = *lpDesc;
Alexandre Julliard's avatar
Alexandre Julliard committed
767 768 769
    MidiInDev[wDevID].state = 0;
    MidiInDev[wDevID].incLen = 0;
    MidiInDev[wDevID].startTime = 0;
770

771
    MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L);
Alexandre Julliard's avatar
Alexandre Julliard committed
772
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
773 774 775
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
776 777
 * 			midClose				[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
778
static DWORD midClose(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
779
{
Alexandre Julliard's avatar
Alexandre Julliard committed
780
    int		ret = MMSYSERR_NOERROR;
781

782
    TRACE("(%04X);\n", wDevID);
783

784
    if (wDevID >= MIDM_NumDevs) {
Andreas Mohr's avatar
Andreas Mohr committed
785
	WARN("wDevID too big (%u) !\n", wDevID);
Alexandre Julliard's avatar
Alexandre Julliard committed
786 787
	return MMSYSERR_BADDEVICEID;
    }
788
    if (MidiInDev[wDevID].midiDesc.hMidi == 0) {
789
	WARN("device not opened !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
790 791 792 793 794
	return MMSYSERR_ERROR;
    }
    if (MidiInDev[wDevID].lpQueueHdr != 0) {
	return MIDIERR_STILLPLAYING;
    }
795

Alexandre Julliard's avatar
Alexandre Julliard committed
796
    if (midiSeqFD == -1) {
797
	WARN("ooops !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
798 799 800
	return MMSYSERR_ERROR;
    }
    if (--numStartedMidiIn == 0) {
801 802 803 804 805
	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);
806
	}
807
    	TRACE("Stopped thread for midi-in\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
808 809
    }
    midiCloseSeq();
810

Alexandre Julliard's avatar
Alexandre Julliard committed
811
    MidiInDev[wDevID].bufsize = 0;
812
    MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L);
813
    MidiInDev[wDevID].midiDesc.hMidi = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
814
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
815 816 817
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
818
 * 				midAddBuffer			[internal]
Alexandre Julliard's avatar
Alexandre Julliard committed
819
 */
820
static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
821
{
822
    TRACE("(%04X, %p, %d);\n", wDevID, lpMidiHdr, dwSize);
823

824 825 826
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;

Alexandre Julliard's avatar
Alexandre Julliard committed
827
    if (lpMidiHdr == NULL)	return MMSYSERR_INVALPARAM;
828
    if (dwSize < offsetof(MIDIHDR,dwOffset)) return MMSYSERR_INVALPARAM;
Alexandre Julliard's avatar
Alexandre Julliard committed
829 830 831
    if (lpMidiHdr->dwBufferLength == 0) return MMSYSERR_INVALPARAM;
    if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
832

833
    EnterCriticalSection(&crit_sect);
834
    lpMidiHdr->dwFlags &= ~WHDR_DONE;
835
    lpMidiHdr->dwFlags |= MHDR_INQUEUE;
836 837
    lpMidiHdr->dwBytesRecorded = 0;
    lpMidiHdr->lpNext = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
838 839 840
    if (MidiInDev[wDevID].lpQueueHdr == 0) {
	MidiInDev[wDevID].lpQueueHdr = lpMidiHdr;
    } else {
841
	LPMIDIHDR	ptr;
842 843 844

	for (ptr = MidiInDev[wDevID].lpQueueHdr;
	     ptr->lpNext != 0;
845 846
	     ptr = ptr->lpNext);
	ptr->lpNext = lpMidiHdr;
Alexandre Julliard's avatar
Alexandre Julliard committed
847
    }
848 849
    LeaveCriticalSection(&crit_sect);

Alexandre Julliard's avatar
Alexandre Julliard committed
850
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
851 852 853
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
854 855
 * 				midPrepare			[internal]
 */
856
static DWORD midPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
857
{
858
    TRACE("(%04X, %p, %d);\n", wDevID, lpMidiHdr, dwSize);
859

860
    if (dwSize < offsetof(MIDIHDR,dwOffset) || lpMidiHdr == 0 || lpMidiHdr->lpData == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
861
	return MMSYSERR_INVALPARAM;
862 863
    if (lpMidiHdr->dwFlags & MHDR_PREPARED)
	return MMSYSERR_NOERROR;
864

Alexandre Julliard's avatar
Alexandre Julliard committed
865 866
    lpMidiHdr->lpNext = 0;
    lpMidiHdr->dwFlags |= MHDR_PREPARED;
867
    lpMidiHdr->dwFlags &= ~(MHDR_DONE|MHDR_INQUEUE); /* flags cleared since w2k */
868

Alexandre Julliard's avatar
Alexandre Julliard committed
869
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
870 871 872
}

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

879
    if (dwSize < offsetof(MIDIHDR,dwOffset) || lpMidiHdr == 0 || lpMidiHdr->lpData == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
880
	return MMSYSERR_INVALPARAM;
881 882 883 884
    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED))
	return MMSYSERR_NOERROR;
    if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
	return MIDIERR_STILLPLAYING;
885

Alexandre Julliard's avatar
Alexandre Julliard committed
886
    lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
887

Alexandre Julliard's avatar
Alexandre Julliard committed
888
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
889 890 891
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
892 893
 * 			midReset				[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
894
static DWORD midReset(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
895
{
Alexandre Julliard's avatar
Alexandre Julliard committed
896
    DWORD		dwTime = GetTickCount();
897

898
    TRACE("(%04X);\n", wDevID);
899

900 901 902
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;

903
    EnterCriticalSection(&crit_sect);
Alexandre Julliard's avatar
Alexandre Julliard committed
904
    while (MidiInDev[wDevID].lpQueueHdr) {
905 906 907 908 909
	LPMIDIHDR lpMidiHdr = MidiInDev[wDevID].lpQueueHdr;
	MidiInDev[wDevID].lpQueueHdr = lpMidiHdr->lpNext;
	lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
	lpMidiHdr->dwFlags |= MHDR_DONE;
	MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD_PTR)lpMidiHdr, dwTime);
Alexandre Julliard's avatar
Alexandre Julliard committed
910
    }
911
    LeaveCriticalSection(&crit_sect);
912

Alexandre Julliard's avatar
Alexandre Julliard committed
913
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
914 915 916
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
917 918
 * 			midStart				[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
919
static DWORD midStart(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
920
{
921
    TRACE("(%04X);\n", wDevID);
922

923 924
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;
925

Alexandre Julliard's avatar
Alexandre Julliard committed
926 927 928
    MidiInDev[wDevID].state = 1;
    MidiInDev[wDevID].startTime = GetTickCount();
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
929 930 931
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
932 933
 *			midStop					[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
934
static DWORD midStop(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
935
{
936
    TRACE("(%04X);\n", wDevID);
937

938 939 940
    if (wDevID >= MIDM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (MidiInDev[wDevID].state == -1) return MIDIERR_NODEVICE;

Alexandre Julliard's avatar
Alexandre Julliard committed
941 942
    MidiInDev[wDevID].state = 0;
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
943 944 945 946
}

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

Alexandre Julliard's avatar
Alexandre Julliard committed
947 948 949 950 951 952 953 954 955 956 957 958
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;
959

Alexandre Julliard's avatar
Alexandre Julliard committed
960 961
    int			bender;
    int			benderRange;
Austin English's avatar
Austin English committed
962
    /* controllers */
Alexandre Julliard's avatar
Alexandre Julliard committed
963 964 965 966 967
    int			bank;		/* CTL_BANK_SELECT */
    int			volume;		/* CTL_MAIN_VOLUME */
    int			balance;	/* CTL_BALANCE     */
    int			expression;	/* CTL_EXPRESSION  */
    int			sustain;	/* CTL_SUSTAIN     */
968

Alexandre Julliard's avatar
Alexandre Julliard committed
969 970 971 972 973 974 975 976 977 978 979
    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 */
980
    /* do not append fields below voice[1] since the size of this structure
Alexandre Julliard's avatar
Alexandre Julliard committed
981 982 983 984
     * depends on the number of available voices on the FM synth...
     */
} sFMextra;

985 986
extern const unsigned char midiFMInstrumentPatches[16 * 128];
extern const unsigned char midiFMDrumsPatches     [16 * 128];
Alexandre Julliard's avatar
Alexandre Julliard committed
987

Alexandre Julliard's avatar
Alexandre Julliard committed
988
/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
989
 * 			modFMLoad				[internal]
Alexandre Julliard's avatar
Alexandre Julliard committed
990
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
991
static int modFMLoad(int dev)
Alexandre Julliard's avatar
Alexandre Julliard committed
992
{
Alexandre Julliard's avatar
Alexandre Julliard committed
993 994
    int				i;
    struct sbi_instrument	sbi;
995

Alexandre Julliard's avatar
Alexandre Julliard committed
996 997
    sbi.device = dev;
    sbi.key = FM_PATCH;
998

Alexandre Julliard's avatar
Alexandre Julliard committed
999 1000 1001 1002
    memset(sbi.operators + 16, 0, 16);
    for (i = 0; i < 128; i++) {
	sbi.channel = i;
	memcpy(sbi.operators, midiFMInstrumentPatches + i * 16, 16);
1003

1004
        if (write(midiSeqFD, &sbi, sizeof(sbi)) == -1) {
Andreas Mohr's avatar
Andreas Mohr committed
1005
	    WARN("Couldn't write patch for instrument %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno));
Alexandre Julliard's avatar
Alexandre Julliard committed
1006 1007
	    return -1;
	}
1008
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1009 1010 1011
    for (i = 0; i < 128; i++) {
	sbi.channel = 128 + i;
	memcpy(sbi.operators, midiFMDrumsPatches + i * 16, 16);
1012

1013
        if (write(midiSeqFD, &sbi, sizeof(sbi)) == -1) {
Andreas Mohr's avatar
Andreas Mohr committed
1014
	    WARN("Couldn't write patch for drum %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno));
Alexandre Julliard's avatar
Alexandre Julliard committed
1015 1016
	    return -1;
	}
1017
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1018 1019 1020 1021 1022 1023 1024 1025
    return 0;
}

/**************************************************************************
 * 			modFMReset				[internal]
 */
static	void modFMReset(WORD wDevID)
{
1026
    sFMextra*   extra   = MidiOutDev[wDevID].lpExtra;
Alexandre Julliard's avatar
Alexandre Julliard committed
1027 1028 1029
    sVoice* 	voice   = extra->voice;
    sChannel*	channel = extra->channel;
    int		i;
1030

1031
    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
	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;
1049 1050
	channel[i].expression = 0;
	channel[i].sustain = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1051 1052 1053 1054 1055 1056 1057
    }
    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
1058

Alexandre Julliard's avatar
Alexandre Julliard committed
1059 1060 1061
/**************************************************************************
 * 				modGetDevCaps			[internal]
 */
1062
static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPSW lpCaps, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1063
{
1064
    TRACE("(%04X, %p, %08X);\n", wDevID, lpCaps, dwSize);
1065

1066
    if (wDevID >= MODM_NumDevs)	return MMSYSERR_BADDEVICEID;
1067 1068
    if (lpCaps == NULL) 	return MMSYSERR_INVALPARAM;

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1071
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1072 1073 1074
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1075 1076
 * 			modOpen					[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1077
static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
Alexandre Julliard's avatar
Alexandre Julliard committed
1078
{
1079
    TRACE("(%04X, %p, %08X);\n", wDevID, lpDesc, dwFlags);
Alexandre Julliard's avatar
Alexandre Julliard committed
1080
    if (lpDesc == NULL) {
1081
	WARN("Invalid Parameter !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1082 1083
	return MMSYSERR_INVALPARAM;
    }
1084
    if (wDevID >= MODM_NumDevs) {
1085
	TRACE("MAX_MIDIOUTDRV reached !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1086 1087
	return MMSYSERR_BADDEVICEID;
    }
1088
    if (MidiOutDev[wDevID].midiDesc.hMidi != 0) {
1089
	WARN("device already open !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1090 1091
	return MMSYSERR_ALLOCATED;
    }
1092 1093 1094 1095
    if (!MidiOutDev[wDevID].bEnabled) {
	WARN("device disabled !\n");
	return MIDIERR_NODEVICE;
    }
1096
    if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
1097
	WARN("bad dwFlags\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1098 1099
	return MMSYSERR_INVALFLAG;
    }
1100

Alexandre Julliard's avatar
Alexandre Julliard committed
1101
    MidiOutDev[wDevID].lpExtra = 0;
1102

1103
    switch (MidiOutDev[wDevID].caps.wTechnology) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1104 1105
    case MOD_FMSYNTH:
	{
1106 1107 1108
	    void*	extra;

            extra = HeapAlloc(GetProcessHeap(), 0,
1109
                              offsetof(struct sFMextra, voice[MidiOutDev[wDevID].caps.wVoices]));
1110

Alexandre Julliard's avatar
Alexandre Julliard committed
1111
	    if (extra == 0) {
1112
		WARN("can't alloc extra data !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1113 1114 1115 1116 1117
		return MMSYSERR_NOMEM;
	    }
	    MidiOutDev[wDevID].lpExtra = extra;
	    if (midiOpenSeq() < 0) {
		MidiOutDev[wDevID].lpExtra = 0;
1118
		HeapFree(GetProcessHeap(), 0, extra);
Alexandre Julliard's avatar
Alexandre Julliard committed
1119 1120 1121 1122 1123
		return MMSYSERR_ERROR;
	    }
	    if (modFMLoad(wDevID) < 0) {
		midiCloseSeq();
		MidiOutDev[wDevID].lpExtra = 0;
1124
		HeapFree(GetProcessHeap(), 0, extra);
Alexandre Julliard's avatar
Alexandre Julliard committed
1125 1126 1127
		return MMSYSERR_ERROR;
	    }
	    modFMReset(wDevID);
Alexandre Julliard's avatar
Alexandre Julliard committed
1128
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1129 1130
	break;
    case MOD_MIDIPORT:
Christian Costa's avatar
Christian Costa committed
1131
    case MOD_SYNTH:
Alexandre Julliard's avatar
Alexandre Julliard committed
1132 1133
	if (midiOpenSeq() < 0) {
	    return MMSYSERR_ALLOCATED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1134
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1135 1136
	break;
    default:
1137
	WARN("Technology not supported (yet) %d !\n",
1138
	     MidiOutDev[wDevID].caps.wTechnology);
Alexandre Julliard's avatar
Alexandre Julliard committed
1139 1140
	return MMSYSERR_NOTENABLED;
    }
1141

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1144 1145 1146
    MidiOutDev[wDevID].lpQueueHdr = NULL;
    MidiOutDev[wDevID].dwTotalPlayed = 0;
    MidiOutDev[wDevID].bufsize = 0x3FFF;
1147
    MidiOutDev[wDevID].midiDesc = *lpDesc;
1148

1149
    MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L);
Andreas Mohr's avatar
Andreas Mohr committed
1150
    TRACE("Successful !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1151
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1152 1153 1154 1155
}


/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1156 1157
 * 			modClose				[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1158
static DWORD modClose(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
1159
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1160 1161
    int	ret = MMSYSERR_NOERROR;

1162
    TRACE("(%04X);\n", wDevID);
1163

1164
    if (MidiOutDev[wDevID].midiDesc.hMidi == 0) {
1165
	WARN("device not opened !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1166 1167 1168 1169
	return MMSYSERR_ERROR;
    }
    /* FIXME: should test that no pending buffer is still in the queue for
     * playing */
1170

Alexandre Julliard's avatar
Alexandre Julliard committed
1171
    if (midiSeqFD == -1) {
1172
	WARN("can't close !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1173 1174
	return MMSYSERR_ERROR;
    }
1175

1176
    switch (MidiOutDev[wDevID].caps.wTechnology) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1177 1178 1179 1180 1181
    case MOD_FMSYNTH:
    case MOD_MIDIPORT:
	midiCloseSeq();
	break;
    default:
1182
	WARN("Technology not supported (yet) %d !\n",
1183
	     MidiOutDev[wDevID].caps.wTechnology);
Alexandre Julliard's avatar
Alexandre Julliard committed
1184 1185
	return MMSYSERR_NOTENABLED;
    }
1186

1187 1188
    HeapFree(GetProcessHeap(), 0, MidiOutDev[wDevID].lpExtra);
    MidiOutDev[wDevID].lpExtra = 0;
1189

Alexandre Julliard's avatar
Alexandre Julliard committed
1190
    MidiOutDev[wDevID].bufsize = 0;
1191
    MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L);
1192
    MidiOutDev[wDevID].midiDesc.hMidi = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1193
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
1194 1195 1196
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1197 1198
 * 			modData					[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1199
static DWORD modData(WORD wDevID, DWORD dwParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1200
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1201 1202 1203
    WORD	evt = LOBYTE(LOWORD(dwParam));
    WORD	d1  = HIBYTE(LOWORD(dwParam));
    WORD	d2  = LOBYTE(HIWORD(dwParam));
1204

1205
    TRACE("(%04X, %08X);\n", wDevID, dwParam);
1206

1207 1208 1209
    if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;

Alexandre Julliard's avatar
Alexandre Julliard committed
1210
    if (midiSeqFD == -1) {
1211
	WARN("can't play !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1212 1213
	return MIDIERR_NODEVICE;
    }
1214
    switch (MidiOutDev[wDevID].caps.wTechnology) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1215 1216 1217 1218 1219
    case MOD_FMSYNTH:
	/* FIXME:
	 *	- chorus depth controller is not used
	 */
	{
1220
            sFMextra*   extra   = MidiOutDev[wDevID].lpExtra;
Alexandre Julliard's avatar
Alexandre Julliard committed
1221 1222 1223 1224
	    sVoice* 	voice   = extra->voice;
	    sChannel*	channel = extra->channel;
	    int		chn = (evt & 0x0F);
	    int		i, nv;
1225

Alexandre Julliard's avatar
Alexandre Julliard committed
1226 1227
	    switch (evt & 0xF0) {
	    case MIDI_NOTEOFF:
1228
		for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1229 1230 1231 1232 1233 1234
				/* 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);
		    }
		}
1235
		break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1236 1237
	    case MIDI_NOTEON:
		if (d2 == 0) { /* note off if velocity == 0 */
1238
		    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
			/* 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)
		 */
1252
		for (i = nv = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
1253
		    if (voice[i].status == sVS_UNUSED ||
Alexandre Julliard's avatar
Alexandre Julliard committed
1254 1255 1256 1257 1258 1259 1260 1261
			(voice[i].note == d1 && voice[i].channel == chn)) {
			nv = i;
			break;
		    }
		    if (voice[i].cntMark < voice[0].cntMark) {
			nv = i;
		    }
		}
1262
		TRACE(
Alexandre Julliard's avatar
Alexandre Julliard committed
1263
		      "playing on voice=%d, pgm=%d, pan=0x%02X, vol=0x%02X, "
1264 1265 1266 1267
		      "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
1268
		      channel[chn].bender, d1, d2);
1269 1270

		SEQ_SET_PATCH(wDevID, nv, IS_DRUM_CHANNEL(extra, chn) ?
Alexandre Julliard's avatar
Alexandre Julliard committed
1271 1272 1273 1274 1275
			      (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);
1276
#if 0
Alexandre Julliard's avatar
Alexandre Julliard committed
1277 1278 1279 1280
		/* 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);
1281
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
1282 1283 1284 1285 1286 1287 1288
		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:
1289
		for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
		    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) {
1303
			for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1304 1305 1306 1307 1308
			    if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {
				voice[i].status = sVS_SUSTAINED;
			    }
			}
		    } else {
1309
			for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
			    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;
1320
		case CTL_REGIST_PARM_NUM_MSB:	channel[chn].regPmtMSB = d2;	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1321 1322
		case CTL_DATA_ENTRY:
		    switch ((channel[chn].regPmtMSB << 8) | channel[chn].regPmtLSB) {
1323
		    case 0x0000:
Alexandre Julliard's avatar
Alexandre Julliard committed
1324 1325
			if (channel[chn].benderRange != d2) {
			    channel[chn].benderRange = d2;
1326
			    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1327 1328 1329 1330 1331 1332
				if (voice[i].channel == chn) {
				    SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);
				}
			    }
			}
			break;
1333

Alexandre Julliard's avatar
Alexandre Julliard committed
1334 1335
		    case 0x7F7F:
			channel[chn].benderRange = 2;
1336
			for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1337 1338 1339 1340 1341 1342
			    if (voice[i].channel == chn) {
				SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);
			    }
			}
			break;
		    default:
1343
			TRACE("Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1344 1345 1346 1347 1348 1349
			      channel[chn].regPmtMSB, channel[chn].regPmtLSB,
			      channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB,
			      d2);
			break;
		    }
		    break;
1350

Alexandre Julliard's avatar
Alexandre Julliard committed
1351
		case 0x78: /* all sounds off */
1352
		    /* FIXME: I don't know if I have to take care of the channel
1353 1354
		     * for this control ?
		     */
1355
		    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1356 1357
			if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) {
			    voice[i].status = sVS_UNUSED;
1358
			    SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
Alexandre Julliard's avatar
Alexandre Julliard committed
1359 1360 1361 1362
			}
		    }
		    break;
		case 0x7B: /* all notes off */
1363
		    /* FIXME: I don't know if I have to take care of the channel
1364 1365
		     * for this control ?
		     */
1366
		    for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1367 1368
			if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {
			    voice[i].status = sVS_UNUSED;
1369
			    SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
Alexandre Julliard's avatar
Alexandre Julliard committed
1370 1371
			}
		    }
1372
		    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1373
		default:
1374
		    TRACE("Dropping MIDI control event 0x%02x(%02x) on channel %d\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1375 1376 1377 1378 1379 1380 1381 1382
			  d1, d2, chn);
		    break;
		}
		break;
	    case MIDI_PGM_CHANGE:
		channel[chn].program = d1;
		break;
	    case MIDI_CHN_PRESSURE:
1383
		for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1384 1385 1386 1387 1388 1389 1390
		    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;
1391
		for (i = 0; i < MidiOutDev[wDevID].caps.wVoices; i++) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1392 1393 1394 1395 1396 1397 1398 1399 1400
		    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);
1401
		    break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1402
		default:
1403
		    WARN("Unsupported (yet) system event %02x\n", evt & 0x0F);
Alexandre Julliard's avatar
Alexandre Julliard committed
1404 1405
		}
		break;
1406
	    default:
1407
		WARN("Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1408 1409 1410 1411 1412 1413
		return MMSYSERR_NOTENABLED;
	    }
	}
	break;
    case MOD_MIDIPORT:
	{
1414
	    int	dev = wDevID - MODM_NumFMSynthDevs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1415
	    if (dev < 0) {
1416
		WARN("Internal error on devID (%u) !\n", wDevID);
Alexandre Julliard's avatar
Alexandre Julliard committed
1417
		return MIDIERR_NODEVICE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1418
	    }
1419

Alexandre Julliard's avatar
Alexandre Julliard committed
1420 1421 1422 1423 1424 1425
	    switch (evt & 0xF0) {
	    case MIDI_NOTEOFF:
	    case MIDI_NOTEON:
	    case MIDI_KEY_PRESSURE:
	    case MIDI_CTL_CHANGE:
	    case MIDI_PITCH_BEND:
1426 1427 1428
		SEQ_MIDIOUT(dev, evt);
		SEQ_MIDIOUT(dev, d1);
		SEQ_MIDIOUT(dev, d2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1429 1430 1431
		break;
	    case MIDI_PGM_CHANGE:
	    case MIDI_CHN_PRESSURE:
1432 1433 1434
		SEQ_MIDIOUT(dev, evt);
		SEQ_MIDIOUT(dev, d1);
		break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1435 1436
	    case MIDI_SYSTEM_PREFIX:
		switch (evt & 0x0F) {
1437
		case 0x00:	/* System Exclusive, don't do it on modData,
Alexandre Julliard's avatar
Alexandre Julliard committed
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450
				 * should require modLongData*/
		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. */
1451
		    SEQ_MIDIOUT(dev, evt);
Alexandre Julliard's avatar
Alexandre Julliard committed
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462
		    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;
1463
		case 0x01:	/* MTC Quarter frame */
Alexandre Julliard's avatar
Alexandre Julliard committed
1464
		case 0x03:	/* Song Select. */
1465 1466
		    SEQ_MIDIOUT(dev, evt);
		    SEQ_MIDIOUT(dev, d1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1467
		case 0x02:	/* Song Position Pointer. */
1468
		    SEQ_MIDIOUT(dev, evt);
Alexandre Julliard's avatar
Alexandre Julliard committed
1469 1470 1471 1472 1473
		    SEQ_MIDIOUT(dev, d1);
		    SEQ_MIDIOUT(dev, d2);
		}
		break;
	    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1474
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1475 1476
	break;
    default:
1477
	WARN("Technology not supported (yet) %d !\n",
1478
	     MidiOutDev[wDevID].caps.wTechnology);
Alexandre Julliard's avatar
Alexandre Julliard committed
1479 1480
	return MMSYSERR_NOTENABLED;
    }
1481

Alexandre Julliard's avatar
Alexandre Julliard committed
1482
    SEQ_DUMPBUF();
1483

Alexandre Julliard's avatar
Alexandre Julliard committed
1484
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1485 1486 1487
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1488 1489
 *		modLongData					[internal]
 */
1490
static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1491
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1492
    int		count;
1493 1494
    LPBYTE	lpData;

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

Christian Costa's avatar
Christian Costa committed
1497 1498 1499 1500 1501
    /* 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.
     */
    
1502 1503 1504
    if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;

Alexandre Julliard's avatar
Alexandre Julliard committed
1505
    if (midiSeqFD == -1) {
1506
	WARN("can't play !\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1507 1508
	return MIDIERR_NODEVICE;
    }
1509

Mike McCormack's avatar
Mike McCormack committed
1510
    lpData = (LPBYTE) lpMidiHdr->lpData;
1511

1512
    if (lpData == NULL)
Alexandre Julliard's avatar
Alexandre Julliard committed
1513
	return MIDIERR_UNPREPARED;
1514
    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED))
Alexandre Julliard's avatar
Alexandre Julliard committed
1515
	return MIDIERR_UNPREPARED;
1516
    if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
Alexandre Julliard's avatar
Alexandre Julliard committed
1517 1518 1519
	return MIDIERR_STILLPLAYING;
    lpMidiHdr->dwFlags &= ~MHDR_DONE;
    lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1520

1521
    /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive
1522
     * data, or can it also contain raw MIDI data, to be split up and sent to
1523
     * modShortData() ?
1524
     * If the latter is true, then the following WARNing will fire up
1525
     */
1526
    if (lpData[0] != 0xF0 || lpData[lpMidiHdr->dwBufferLength - 1] != 0xF7) {
1527
	WARN("The allegedly system exclusive buffer is not correct\n\tPlease report with MIDI file\n");
1528 1529
    }

1530
    TRACE("dwBufferLength=%u !\n", lpMidiHdr->dwBufferLength);
1531
    TRACE("                 %02X %02X %02X ... %02X %02X %02X\n",
1532
	  lpData[0], lpData[1], lpData[2], lpData[lpMidiHdr->dwBufferLength-3],
1533
	  lpData[lpMidiHdr->dwBufferLength-2], lpData[lpMidiHdr->dwBufferLength-1]);
1534

1535
    switch (MidiOutDev[wDevID].caps.wTechnology) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1536 1537 1538 1539
    case MOD_FMSYNTH:
	/* FIXME: I don't think there is much to do here */
	break;
    case MOD_MIDIPORT:
1540
	if (lpData[0] != 0xF0) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1541
	    /* Send end of System Exclusive */
1542
	    SEQ_MIDIOUT(wDevID - MODM_NumFMSynthDevs, 0xF0);
1543
	    WARN("Adding missing 0xF0 marker at the beginning of "
1544
		 "system exclusive byte stream\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1545
	}
Christian Costa's avatar
Christian Costa committed
1546
	for (count = 0; count < lpMidiHdr->dwBufferLength; count++) {
1547
	    SEQ_MIDIOUT(wDevID - MODM_NumFMSynthDevs, lpData[count]);
Alexandre Julliard's avatar
Alexandre Julliard committed
1548
	}
1549
	if (lpData[count - 1] != 0xF7) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1550
	    /* Send end of System Exclusive */
1551
	    SEQ_MIDIOUT(wDevID - MODM_NumFMSynthDevs, 0xF7);
1552
	    WARN("Adding missing 0xF7 marker at the end of "
1553
		 "system exclusive byte stream\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1554 1555 1556 1557
	}
	SEQ_DUMPBUF();
	break;
    default:
1558
	WARN("Technology not supported (yet) %d !\n",
1559
	     MidiOutDev[wDevID].caps.wTechnology);
Alexandre Julliard's avatar
Alexandre Julliard committed
1560 1561
	return MMSYSERR_NOTENABLED;
    }
1562

Alexandre Julliard's avatar
Alexandre Julliard committed
1563 1564
    lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
    lpMidiHdr->dwFlags |= MHDR_DONE;
1565
    MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD_PTR)lpMidiHdr, 0L);
Alexandre Julliard's avatar
Alexandre Julliard committed
1566
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1567 1568 1569
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1570 1571
 * 			modPrepare				[internal]
 */
1572
static DWORD modPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1573
{
1574
    TRACE("(%04X, %p, %d);\n", wDevID, lpMidiHdr, dwSize);
1575

1576
    if (dwSize < offsetof(MIDIHDR,dwOffset) || lpMidiHdr == 0 || lpMidiHdr->lpData == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1577
	return MMSYSERR_INVALPARAM;
1578 1579
    if (lpMidiHdr->dwFlags & MHDR_PREPARED)
	return MMSYSERR_NOERROR;
1580

Alexandre Julliard's avatar
Alexandre Julliard committed
1581 1582
    lpMidiHdr->lpNext = 0;
    lpMidiHdr->dwFlags |= MHDR_PREPARED;
1583
    lpMidiHdr->dwFlags &= ~(MHDR_DONE|MHDR_INQUEUE); /* flags cleared since w2k */
Alexandre Julliard's avatar
Alexandre Julliard committed
1584
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1585 1586 1587
}

/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1588 1589
 * 				modUnprepare			[internal]
 */
1590
static DWORD modUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1591
{
1592
    TRACE("(%04X, %p, %d);\n", wDevID, lpMidiHdr, dwSize);
1593

1594
    if (dwSize < offsetof(MIDIHDR,dwOffset) || lpMidiHdr == 0 || lpMidiHdr->lpData == 0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1595
	return MMSYSERR_INVALPARAM;
1596 1597
    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED))
	return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1598 1599 1600 1601
    if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
	return MIDIERR_STILLPLAYING;
    lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
    return MMSYSERR_NOERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
1602 1603
}

1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614
/**************************************************************************
 * 			modGetVolume				[internal]
 */
static DWORD modGetVolume(WORD wDevID, DWORD* lpdwVolume)
{
    if (!lpdwVolume) return MMSYSERR_INVALPARAM;
    if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
    *lpdwVolume = 0xFFFFFFFF;
    return (MidiOutDev[wDevID].caps.dwSupport & MIDICAPS_VOLUME) ? 0 : MMSYSERR_NOTSUPPORTED;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1615
/**************************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1616 1617
 * 			modReset				[internal]
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1618
static DWORD modReset(WORD wDevID)
Alexandre Julliard's avatar
Alexandre Julliard committed
1619
{
1620
    unsigned chn;
1621

1622
    TRACE("(%04X);\n", wDevID);
1623

1624 1625 1626
    if (wDevID >= MODM_NumDevs) return MMSYSERR_BADDEVICEID;
    if (!MidiOutDev[wDevID].bEnabled) return MIDIERR_NODEVICE;

1627
    /* stop all notes */
1628
    /* FIXME: check if 0x78B0 is channel dependent or not. I coded it so that
1629
     * it's channel dependent...
Alexandre Julliard's avatar
Alexandre Julliard committed
1630
     */
1631 1632 1633 1634 1635 1636 1637 1638
    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
1639
}
1640

1641
#endif /* SNDCTL_SEQ_NRMIDIS */
Alexandre Julliard's avatar
Alexandre Julliard committed
1642

1643 1644 1645 1646
/*======================================================================*
 *                  	    MIDI entry points 				*
 *======================================================================*/

1647
/**************************************************************************
1648
 * 			midMessage (WINEOSS.@)
1649
 */
1650 1651
DWORD WINAPI OSS_midMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
			    DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1652
{
1653
    TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n",
1654 1655
	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
    switch (wMsg) {
1656
#ifdef SNDCTL_SEQ_NRMIDIS
1657
    case DRVM_INIT:
1658
        return OSS_MidiInit();
1659
    case DRVM_EXIT:
1660
        return OSS_MidiExit();
1661 1662 1663 1664
    case DRVM_ENABLE:
    case DRVM_DISABLE:
	/* FIXME: Pretend this is supported */
	return 0;
1665
    case MIDM_OPEN:
1666
	return midOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
1667 1668 1669
    case MIDM_CLOSE:
	return midClose(wDevID);
    case MIDM_ADDBUFFER:
1670
	return midAddBuffer(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1671
    case MIDM_PREPARE:
1672
	return midPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1673
    case MIDM_UNPREPARE:
1674
	return midUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1675
    case MIDM_GETDEVCAPS:
1676
	return midGetDevCaps(wDevID, (LPMIDIINCAPSW)dwParam1,dwParam2);
1677
    case MIDM_GETNUMDEVS:
1678
	return MIDM_NumDevs;
1679 1680 1681 1682 1683 1684
    case MIDM_RESET:
	return midReset(wDevID);
    case MIDM_START:
	return midStart(wDevID);
    case MIDM_STOP:
	return midStop(wDevID);
1685 1686 1687 1688
#else
    case DRVM_INIT:
    case MIDM_GETNUMDEVS:
        return 0;
1689 1690
#endif
    default:
1691
	TRACE("Unsupported message\n");
1692 1693 1694 1695
    }
    return MMSYSERR_NOTSUPPORTED;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1696
/**************************************************************************
1697
 * 				modMessage (WINEOSS.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1698
 */
1699 1700
DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser,
			    DWORD_PTR dwParam1, DWORD_PTR dwParam2)
Alexandre Julliard's avatar
Alexandre Julliard committed
1701
{
1702
    TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1703
	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
1704 1705

    switch (wMsg) {
1706
#ifdef SNDCTL_SEQ_NRMIDIS
1707
    case DRVM_INIT:
1708
        return OSS_MidiInit();
1709
    case DRVM_EXIT:
1710
        return OSS_MidiExit();
1711 1712 1713 1714
    case DRVM_ENABLE:
    case DRVM_DISABLE:
	/* FIXME: Pretend this is supported */
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1715 1716 1717 1718 1719 1720 1721
    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:
1722
	return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1723
    case MODM_PREPARE:
1724
	return modPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1725
    case MODM_UNPREPARE:
1726
	return modUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1727
    case MODM_GETDEVCAPS:
1728
	return modGetDevCaps(wDevID, (LPMIDIOUTCAPSW)dwParam1, dwParam2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1729
    case MODM_GETNUMDEVS:
1730
	return MODM_NumDevs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1731
    case MODM_GETVOLUME:
1732
	return modGetVolume(wDevID, (DWORD*)dwParam1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1733 1734 1735 1736
    case MODM_SETVOLUME:
	return 0;
    case MODM_RESET:
	return modReset(wDevID);
1737 1738 1739 1740
#else
    case DRVM_INIT:
    case MODM_GETNUMDEVS:
        return 0;
1741
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
1742
    default:
1743
	TRACE("Unsupported message\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1744 1745
    }
    return MMSYSERR_NOTSUPPORTED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1746 1747
}

1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
/**************************************************************************
 * 				DriverProc (WINEOSS.1)
 */
LRESULT CALLBACK OSS_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
                                LPARAM dwParam1, LPARAM dwParam2)
{
     TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
           dwDevID, hDriv, wMsg, dwParam1, dwParam2);

    switch(wMsg) {
    case DRV_LOAD:
    case DRV_FREE:
    case DRV_OPEN:
    case DRV_CLOSE:
    case DRV_ENABLE:
    case DRV_DISABLE:
    case DRV_QUERYCONFIGURE:
    case DRV_CONFIGURE:
        return 1;
    case DRV_INSTALL:
    case DRV_REMOVE:
        return DRV_SUCCESS;
    default:
	return 0;
    }
}