Release 980927

Sun Sep 27 14:25:38 1998  Petter Reinholdtsen <pere@td.org.uit.no>

	* [files/drive.c]
	Make sure GetDriveType32A() handles param NULL.  Added some
	doc on function.

Sun Sep 27 14:07:26 1998  Huw D M Davies <daviesh@abacus.physics.ox.ac.uk>

	* [controls/edit.c] [windows/win.c]
	Don't call SetWindowLong() in EDIT_WM_NCREATE.
	Fix SetWindowLong(GWL_[EX]STYLE) to work for 16bit windows. Remove
	UpdateWindow() call. 

Sun Sep 27 13:41:22 1998  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [scheduler/*.c] [server/event.c] [server/mutex.c]
	  [server/semaphore.c]
	Implemented server-side synchronisation objects.

Sun Sep 27 01:13:35 1998  Alex Priem <alexp@sci.kun.nl>

	* [dlls/comctl32/treeview.c] [include/treeview.h] [include/comctl.h]
	Treeview implementation.

	* [dlls/comctl32/trackbar.c] [include/trackbar.h] 
	Trackbar implementation.

Sat Sep 26 20:49:13 1998  Ulrich Weigand <weigand@informatik.uni-erlangen.de>

	* [if1632/thunk.c] [tools/build.c] [win32/kernel32.c]
	Bugfix: several problems with flat thunks fixed.

	* [memory/selector.c]
	Bugfix: IsBad...Ptr16 didn't work for limit_in_pages segments.

	* [scheduler/thread.c]
	Bugfix: CreateThread: Allow id parameter == NULL.

	* [objects/gdiobj.c]
	Bugfix: IsGDIObject: Return correct object type for stock objects.

	* [msdos/dpmi.c]
	Bugfix: fixed typo in INT_DoRealModeInt.

	* [msdos/int21.c]
	Bugfix: int21 READ *must* use WIN16_hread, not _hread16.

	* [if1632/kernel.spec] [if1632/dummy.c] [if1632/thunk.c]
	  [loader/ne/module.c] [scheduler/event.c] [scheduler/synchro.c]
	  [scheduler/thread.c] [win32/kernel32.c] [win32/ordinals.c]
	Added names/stubs for all undocumented KERNEL routines (Win95).
	Added the following undoc. 16-bit equivalents to Win32 routines:
	KERNEL.441-443,449-453,456-462,471-476,479-486,488.
	Added stubs for some other KERNEL routines.

	* [memory/heap.c] [memory/global.c] [include/global.h]
	Implemented Local32... 32-bit local heap routines (KERNEL.208-215, 229).

	* [miscemu/instr.c] [loader/module.c] [include/module.h]
	Implemented __GP fault handling and HasGPHandler (KERNEL.338).

	* [misc/error.c]
	Implemented LogParamErrorRegs (KERNEL.327).

	* [loader/task.c] [include/windows.h]
	Implemented GetCodeInfo (KERNEL.104).

	* [loader/task.c] [scheduler/thread.c] [include/thread.h]
	Implemented [GS]etThreadQueue and [GS]etFastQueue (KERNEL.463/4, 624/5).

	* [if1632/gdi.spec] [objects/dc.c] [objects/dib.c]
	  [objects/bitmap.c] [include/windows.h]
	Bugfix: fixed wrong parameter for CreateDIBSection16.
	Added [GS]etDIBColorTable16, stub for GetBoundsRect16.
	Partially implemented BITMAP_GetObject16 for DIBs.

	* [if1632/gdi.spec] [relay32/gdi32.spec] [objects/palette.c]
	Added some GDI stubs.

	* [if1632/Makefile.in] [if1632/display.spec] [if1632/mouse.spec]
	  [if1632/keyboard.spec] [if1632/builtin.c] [windows/keyboard.c]
	Added some stubs for Win16 drivers: KEYBOARD, MOUSE, DISPLAY.

	* [if1632/wprocs.spec] [msdos/vxd.c]
	Added some stubs for VxDs: VMM, ConfigMG, TimerAPI.

	* [msdos/int2f.c]
	Added some stubs for real-mode network drivers.

Sat Sep 26 18:18:18 1998  Marcus Meissner <marcus@jet.franken.de>

	* [configure.in]
	Merged in some more of the FreeBSD ports/emulators/wine patches. 
	(Maintainer(s) of this port: You can just submit these
	patches to Alexandre directly.)

	 * [loader/pe_image.c]
	Check filesize of image against size derived from header
	to spot truncated executeables without crashing.

	* [files/directory.c]
	Set envvar "COMSPEC". One win32(!!) program crashes without it.

	* [multimedia/mmio.c]
	Added mmioSetInfo32.

	* [include/file.h]
	Return STD_ERROR_HANDLE for AUX and PRT dos handles.

	* [loader/module.c]
	Handle executeables with spaces in their names a bit better in
	CreateProcess.

	* [relay32/msvfw32.spec][if1632/msvideo.spec][multimedia/msvideo.c][include/vfw.h]
	Started on MS Video support (can load Win32 ICMs).

	* [tools/testrun]
	A bit smarter use of ps.

	* [memory/virtual.c]
	Report PAGE_GUARDed pages as PAGE_PROTECTED (AutoCAD LT R17 fails
	without that check (since Win95 doesn't know about PAGE_GUARD)).

Sat Sep 26 15:04:05 1998  Ove Kaaven <ovek@arcticnet.no>

	* [include/miscemu.h] [if1632/builtin.c] [loader/task.c]
	  [miscemu/instr.c] [msdos/dpmi.c] [msdos/int21.c]
	  [msdos/interrupts.c] [windows/user.c]
	INT_[S|G]etHandler was renamed to INT_[S|G]etPMHandler.
	Added handlers to deal with real-mode interrupts; DOS
	programs are now able to hook real-mode interrupts.

	* [loader/dos/module.c] [msdos/dosmem.c] [msdos/int21.c]
	Moved real-mode interrupt table initialization to
	msdos/dosmem.c, and made new V86 tasks get a full copy
	of the existing "system memory" instead of almost empty
	space. Misc fixes.

	* [include/dosexe.h] [loader/dos/module.c] [msdos/dpmi.c]
	  [msdos/int2f.c]
	First shot at letting DOS programs start up DPMI (but DPMI
	is still disabled for DOS programs, for pkunzip's sake).

	* [include/debugger.h] [debugger/break.c] [debugger/dbg.y]
	  [debugger/registers.c] [debugger/memory.c] [debugger/info.c]
	  [loader/dos/dosvm.c]
	First shot at making Wine's debugger work for DOS programs.
	The -debug flag works, as do "nexti" and "stepi".

Sat Sep 26 13:13:13 1998  Juergen Schmied <juergen.schmied@metronet.de>

	* [dlls/shell32/dataobject.c]
	New classes IEnumFORMATETC implemented, IDataObject stubs.
	
	* [dlls/shell32/*.*][relay32/shell32.spec]
	Bugfixes.
	New: ICM_InsertItem(), ILCreateFromPath().
	Implemented: ILCloneFirst().
	Stubs: ILIsEqual(), ILFindChild(), SHLogILFromFSIL(),
	  PathMatchSpec(), PathIsExe().
	Changed: ILGetSize(), _ILIsDesktop(), PathCombine().

	* [include/shlobj.h]
	New SHLGUID's
	New structures: DVTARGETDEVICE32, STGMEDIUM32, FORMATETC32,
	CLIPFORMAT32.
	New interfaces: IEnumFORMATETC, IDataObject, ICommDlgBrowser
	IDockingWindowFrame, IServiceProvider.

	* [dlls/shell32/folders.c]
	Stubs for IShellLink.

	* [loader/resource.c]
	Small fixes.

	* [misc/crtdll.c][relay32/crtdll.spec]
	New __dllonexit().

	* [windows/message.c]
	SendNotifyMessageA, SendMessageCallBack32A half implemented.

	* [controls/edit.c]
	EDIT_WM_SetText set EF_UPDATE flag not for ES_MULTILINE.

	* [files/file.c]
	Handling of fileposition fixed.

Fri Sep 25 18:13:30 1998  Patrik Stridvall <ps@leissner.se>

	* [include/windows.h] [include/wintypes.h]
	  [ole/ole2nls.h] [relay32/kernel32.spec]
	Implemented EnumDateFormats and EnumTimeFormats.
	Only adds US English support.

	* [Makefile.in] [configure.in] 
	  [dlls/Makefile.in] [dlls/psapi/Makefile.in] 
	  [dlls/psapi/psapi_main.c] 
	New files to implement stubs for PSAPI.DLL (NT only).

	* [relay32/Makefile.in] [relay32/builtin32.c] 
	  [relay32/psapi.spec]
	New spec file for PSAPI.DLL (NT only).

	* [scheduler/handle.c]
	HANDLE_GetObjPtr should only interpret the pseudo handles as the
	current thread or the current process if a thread or a process is
	requested.

	* [include/winversion.h] [misc/version.c]
	Adds the global function VERSION_GetVersion() so functions can
	have different behavior depending on the -winver flag.

	* [include/oledlg.h] [ole/oledlg.c]
	Minor fixes. 

	* [windows/winproc.c]
	Minor changes.

	* [include/imm.h] [misc/imm.c]
	Now returns correct values under both Windows 95 and NT 4.0.

Thu Sep 24 22:11:44 1998  Kristian Nielsen  <kristian.nielsen@risoe.dk>

	* [configure.in] [include/acconfig.h] [include/thread.h]
	  [scheduler/sysdeps.c]
	Autoconfig test for non-reentrant libc.

Wed Sep 23 19:52:12 1998  Matthew Becker <mbecker@glasscity.net>

	* [*/*.c]
	Miscellaneous documentation updates and debugging output 
	standardizations.

	* [objects/clipping.c]
	Added ExtSelectClipRgn.

Wed Sep 23 00:03:28 EDT 1998  Pete Ratzlaff <pratzlaff@cfa.harvard.edu>

	* [include/windows.h] [if1632/user.spec] [relay32/user32.spec]
	  [windows/keyboard.c]
	Added, marginally implemented, GetKeyboardLayoutName().
	Only returns US English keyboard name.

Tue Sep 22 16:32:41 1998  Marcel Baur <mbaur@iiic.ethz.ch>

	* [programs/control/*]
	New Winelib application.

Mon Sep 21 00:29:18 1998  Peter Hunnisett <hunnise@nortel.ca>

	* [include/dplay.h][multimedia/dplay.c][ole/compobj.c]
	Added all DirectPlayLobby interfaces and enhanced DirectPlay
	and DirectPlayLobby support. Still not all that much. Useful
	enough if you just need to start a program, don't try any
	real dplay/lobby stuff.

	* [documentation/status/directplay]
	Added a very little bit.

	* [graphics/ddraw.c]
	- Call to SetWindowLong32A wasn't working because there was no
	  memory set aside when the window class was registered.
	- Fixed some xlib reference counting and change the behaviour
	  of DirectDrawSurface3_SetPalette to mimic observed behaviour
	  (palette is associated will all backbuffers)
	- Also stored all palette colour fields and spit back our saved
	  colour fields rather than query X for them.
	- Added plenty of AddRef and Release traces.
	- Added Xlib support for using -desktop option.
	- Fixed Xlib message handling. Messages weren't being passed to
	  the application. Fixes mouse movements in some xlib DDraw games.
	- Added a few stubs.

	* [windows/win.c][include/winerror.h]
	Fixed up some error handling in WIN_SetWindowLong. SetLastError
	wasn't being used. Could cause problems with 0 return codes.
	Added new error in winerror (1400).

	* [AUTHORS] [include/authors.h]
	Added myself as a Wine author.

Sun Sep 20 21:22:44 1998  Alexander Larsson  <alla@lysator.liu.se>

	* [loader/module.c]
	Changed GetModuleFileName32A so that is returns the
	long version of the filename. Note that just the name
	is long, not the directories.

Sat Sep 19 20:05:30 1998 Per Ångström <pang@mind.nu> 

	* [controls/menu.c]
	Made a couple of fixes to make life easier for applications that alter
	their menus at runtime.

	* [windows/defdlg.c]
	Removed the cast of the return value from dialog procedures to a 16-bit
	bool. The return value needs to retain all its 32 bits, since it is not 
	always a bool, such as when responding to the WM_NCHITTEST message.

Fri Sep 18 11:30:38 1998  Sergey Turchanov <turchanov@usa.net>

	* [loader/resource.c]
	Fixed very funny bug (though gravely affecting further excecution)
	with FindResource[Ex]32 functions.

	* [include/multimon.h] [windows/multimon.c] [relay32/user32.spec]
	  [include/windows.h] [windows/sysmetrics.c]
	Default implementation for Multimonitor API.

	* [include/windows.h] [windows/winpos.c]
	Fixed incorrect declaration (and behaviour) of GetWindowRect32.

Wed Sep 16 10:21:15 1998  Gerard Patel <G.Patel@Wanadoo.fr>

	* [controls/edit.c]
	Fixed EDIT_EM_GetLine to use correctly length of lines.

Tue Sep 15 20:40:16 1998  Eric Kohl <ekohl@abo.rhein-zeitung.de>

	* [misc/tweak.c][include/tweak.h][controls/menu.c]
	Replaced the tweak graphic routines by calls to DrawEdge32().

	* [misc/tweak.c][include/tweak.h][documentation/win95look]
	  [wine.ini][*/*]
	Changed "look and feel" selection. Allows Win3.1, Win95 and
	Win98 (no GUI code implemented) look and feel.

	* [dlls/comctl32/header.c][include/header.h][include/commctrl.h]
	Started callback item support and did some minor improvements.

	* [dlls/comctl32/imagelist.c]
	Fixed bug in transparent image display.
	ImageList_GetIcon is still buggy :-(

	* [dlls/comctl32/toolbar.c]
	Fixed button drawing (partial hack).

	* [dlls/comctl32/commctrl.c]
	Fixed MenuHelp().

	* [controls/button.c]
	Added 3d effect for groupbox.

	* [windows/msgbox.c]
	Added font support for message boxes.

	* [windows/nonclient.c]
	Fixed window moving bug.

	* [dlls/comctl32/*.c]
	Various improvements.

	* [dlls/comctl32/listview.c][dlls/comctl32/rebar.c]
	  [include/commctrl.h]
	More messages.

	* [windows/syscolor.c][include/windows.h]
	Introduced new Win98 system colors.

Tue Sep 15 18:29:45 1998 Wesley Filardo <eightknots@aol.com>

	* [files/profile.c]
	Added support in PROFILE_LoadWineIni for -config option

	* [misc/main.c] [include/options.h]
	Added -config option.

Tue Sep 15 18:22:26 1998  Petter Reinholdtsen <pere@td.org.uit.no>

	* [documentation/Makefile.in]
	Make sure directory exists before installing into it.

Tue Sep 15 01:47:33 1998  Pablo Saratxaga <pablo.sarachaga@ping.be>

	* [ole/nls/*] [ole/ole2nls.c] [include/winnls.h]
	Fixed a few errors and completed some NLS files.

Mon Sep 14 01:23:45 1998  Joseph Pranevich <knight@baltimore.wwaves.com>

	* [include/miscemu.h] [msdos/interrupts.c]
	Removed a compilation warning, added INT 25 to the list of interrupts
	callable from DOS applications, added a debug message when unsupported
	interrupts are used.

Sun Sep 13 19:55:22 1998  Lawson Whitney <lawson_whitney@juno.com>

	* [if1632/relay.c]
	CallProcEx32W should not reverse arguments.

Sun Aug 17 21:18:12 1998  Eric Pouech  <eric.pouech@lemel.fr>

	* [multimedia/midi.c] [multimedia/init.c] [multimedia/mmsys.c] 
	  [include/multimedia.h] [include/mmsystem.h] 
	  [multimedia/Makefile.in] [multimedia/midipatch.c]
	  [if1632/multimedia.spec]
	Made MIDI input and output functional on OSS capable systems.

	* [multimedia/timer.c]
	Changes to trigger callbacks at the accurate pace even when
	fake timers are used.
diff --git a/multimedia/midi.c b/multimedia/midi.c
index c7cae5a..3200e9e 100644
--- a/multimedia/midi.c
+++ b/multimedia/midi.c
@@ -1,15 +1,23 @@
+/* -*- tab-width: 8; c-basic-offset: 4 -*- */
+
 /*
  * Sample MIDI Wine Driver for Linux
  *
  * Copyright 1994 Martin Ayotte
  */
 
+/* 
+ * Eric POUECH : 98/7 changes for making this MIDI driver work on OSS
+ * current support is limited to MIDI ports of OSS systems
+ */
+
 #include <errno.h>
 #include <string.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/ioctl.h>
 #include "windows.h"
 #include "ldt.h"
 #include "multimedia.h"
@@ -18,294 +26,327 @@
 #include "mmsystem.h"
 #include "xmalloc.h"
 #include "debug.h"
+#include "callback.h"
+#include "options.h"
 
-static LINUX_MIDIIN	MidiInDev[MAX_MIDIINDRV];
+static LINUX_MIDIIN	MidiInDev [MAX_MIDIINDRV ];
 static LINUX_MIDIOUT	MidiOutDev[MAX_MIDIOUTDRV];
 static LINUX_MCIMIDI	MCIMidiDev[MAX_MCIMIDIDRV];
 
-/* this is the total number of MIDI devices found */
-int MODM_NUMDEVS = 0;
+/* this is the total number of MIDI out devices found */
+int 	MODM_NUMDEVS = 0;				
+/* this is the number of FM synthetizers (index from 0 to 
+   NUMFMSYNTHDEVS - 1) */
+int	MODM_NUMFMSYNTHDEVS = 0;	
+/* this is the number of Midi ports (index from NUMFMSYNTHDEVS to 
+   NUMFMSYNTHDEVS + NUMMIDIDEVS - 1) */
+int	MODM_NUMMIDIDEVS = 0;		
+
+/* this is the total number of MIDI out devices found */
+int 	MIDM_NUMDEVS = 0;				
+
+#ifdef HAVE_OSS
+static	int		midiSeqFD = -1;
+static	int		numOpenMidiSeq = 0;
+static	UINT32		midiInTimerID = 0;
+static	int		numStartedMidiIn = 0;
+#endif /* HAVE_OSS */
 
 /* this structure holds pointers with information for each MIDI
- * device found.
+ * out device found.
  */
-LPMIDIOUTCAPS16 midiDevices[MAX_MIDIOUTDRV];
+LPMIDIOUTCAPS16 midiOutDevices[MAX_MIDIOUTDRV];
+
+/* this structure holds pointers with information for each MIDI
+ * in device found.
+ */
+LPMIDIINCAPS16  midiInDevices [MAX_MIDIINDRV];
+
+/* 
+ * FIXME : all tests on device ID for midXXX and modYYY are made against 
+ * MAX_MIDIxxDRV (when they are made) but should be done against the actual
+ * number of midi devices found...
+ * check also when HAVE_OSS is defined that midiDesc is not NULL
+ */
 
 /**************************************************************************
  * 			MIDI_NotifyClient			[internal]
  */
 static DWORD MIDI_NotifyClient(UINT16 wDevID, WORD wMsg, 
-				DWORD dwParam1, DWORD dwParam2)
+			       DWORD dwParam1, DWORD dwParam2)
 {
-	TRACE(midi,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
-
-	switch (wMsg) {
-	case MOM_OPEN:
-	case MOM_CLOSE:
-	case MOM_DONE:
-	  if (wDevID > MAX_MIDIOUTDRV) return MCIERR_INTERNAL;
-	  
-	  if (MidiOutDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
-		MidiOutDev[wDevID].midiDesc.dwCallback, 
-		MidiOutDev[wDevID].wFlags, 
-		MidiOutDev[wDevID].midiDesc.hMidi, 
-                wMsg, 
-		MidiOutDev[wDevID].midiDesc.dwInstance, 
-                dwParam1, 
-                dwParam2)) {
-	    WARN(midi,"can't notify client !\n");
-	    return MMSYSERR_NOERROR;
-	  }
-	  break;
-
-	case MIM_OPEN:
-	case MIM_CLOSE:
-	  if (wDevID > MAX_MIDIINDRV) return MCIERR_INTERNAL;
-	  
-	if (MidiInDev[wDevID].wFlags != DCB_NULL && !DriverCallback(
-		MidiInDev[wDevID].midiDesc.dwCallback, MidiInDev[wDevID].wFlags, 
-		MidiInDev[wDevID].midiDesc.hMidi, wMsg, 
-		MidiInDev[wDevID].midiDesc.dwInstance, dwParam1, dwParam2)) {
-	    WARN(mciwave,"can't notify client !\n");
-		return MMSYSERR_NOERROR;
-		}
-	  break;
-	}
-        return 0;
+    DWORD 		dwCallBack;
+    UINT16 		uFlags;
+    HANDLE16 		hDev;
+    DWORD 		dwInstance;
+    
+    TRACE(midi,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n", 
+	  wDevID, wMsg, dwParam1, dwParam2);
+    
+    switch (wMsg) {
+    case MOM_OPEN:
+    case MOM_CLOSE:
+    case MOM_DONE:
+	if (wDevID > MAX_MIDIOUTDRV) 
+	    return MCIERR_INTERNAL;
+	
+	dwCallBack = MidiOutDev[wDevID].midiDesc->dwCallback;
+	uFlags = MidiOutDev[wDevID].wFlags;
+	hDev = MidiOutDev[wDevID].midiDesc->hMidi;
+	dwInstance = MidiOutDev[wDevID].midiDesc->dwInstance;
+	break;
+	
+    case MIM_OPEN:
+    case MIM_CLOSE:
+    case MIM_DATA:
+    case MIM_ERROR:
+	if (wDevID > MAX_MIDIINDRV) 
+	    return MCIERR_INTERNAL;
+	
+	dwCallBack = MidiInDev[wDevID].midiDesc->dwCallback;
+	uFlags = MidiInDev[wDevID].wFlags;
+	hDev = MidiInDev[wDevID].midiDesc->hMidi;
+	dwInstance = MidiInDev[wDevID].midiDesc->dwInstance;
+	break;
+    default:
+	WARN(midi, "Unsupported MSW-MIDI message %u\n", wMsg);
+	return MCIERR_INTERNAL;
+    }
+    
+    return DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2) ?
+	0 : MCIERR_INTERNAL;
 }
 
-
 /**************************************************************************
  * 				MIDI_ReadByte			[internal]	
  */
 static DWORD MIDI_ReadByte(UINT16 wDevID, BYTE *lpbyt)
 {
-	if (lpbyt != NULL) {
-		if (mmioRead32(MCIMidiDev[wDevID].hFile, (HPSTR)lpbyt,
-			(long) sizeof(BYTE)) == (long) sizeof(BYTE)) {
-			return 0;
-		}
+    if (lpbyt != NULL) {
+	if (mmioRead32(MCIMidiDev[wDevID].hFile, (HPSTR)lpbyt,
+		       (long) sizeof(BYTE)) == (long) sizeof(BYTE)) {
+	    return 0;
 	}
-	WARN(midi, "error reading wDevID=%04X\n", wDevID);
-	return MCIERR_INTERNAL;
-
+    }
+    WARN(midi, "error reading wDevID=%04X\n", wDevID);
+    return MCIERR_INTERNAL;
+    
 }
 
-
 /**************************************************************************
  * 				MIDI_ReadWord			[internal]	
  */
 static DWORD MIDI_ReadWord(UINT16 wDevID, LPWORD lpw)
 {
-	BYTE	hibyte, lobyte;
-	if (lpw != NULL) {
-		if (MIDI_ReadByte(wDevID, &hibyte) == 0) {
-			if (MIDI_ReadByte(wDevID, &lobyte) == 0) {
-				*lpw = ((WORD)hibyte << 8) + lobyte;
-				return 0;
-			}
-		}
-	}
-	WARN(midi, "error reading wDevID=%04X\n", wDevID);
-	return MCIERR_INTERNAL;
-}
+    BYTE	hibyte, lobyte;
 
+    if (lpw != NULL) {
+	if (MIDI_ReadByte(wDevID, &hibyte) == 0) {
+	    if (MIDI_ReadByte(wDevID, &lobyte) == 0) {
+		*lpw = ((WORD)hibyte << 8) + lobyte;
+		return 0;
+	    }
+	}
+    }
+    WARN(midi, "error reading wDevID=%04X\n", wDevID);
+    return MCIERR_INTERNAL;
+}
 
 /**************************************************************************
  * 				MIDI_ReadLong			[internal]	
  */
 static DWORD MIDI_ReadLong(UINT16 wDevID, LPDWORD lpdw)
 {
-	WORD	hiword, loword;
-	if (lpdw != NULL) {
-		if (MIDI_ReadWord(wDevID, &hiword) == 0) {
-			if (MIDI_ReadWord(wDevID, &loword) == 0) {
-				*lpdw = MAKELONG(loword, hiword);
-				return 0;
-			}
-		}
-	}
-	WARN(midi, "error reading wDevID=%04X\n", wDevID);
-	return MCIERR_INTERNAL;
-}
+    WORD	hiword, loword;
 
+    if (lpdw != NULL) {
+	if (MIDI_ReadWord(wDevID, &hiword) == 0) {
+	    if (MIDI_ReadWord(wDevID, &loword) == 0) {
+		*lpdw = MAKELONG(loword, hiword);
+		return 0;
+	    }
+	}
+    }
+    WARN(midi, "error reading wDevID=%04X\n", wDevID);
+    return MCIERR_INTERNAL;
+}
 
 /**************************************************************************
  *  				MIDI_ReadVaryLen		[internal]	
  */
 static DWORD MIDI_ReadVaryLen(UINT16 wDevID, LPDWORD lpdw)
 {
-	BYTE	byte;
-	DWORD	value;
-	if (lpdw == NULL) return MCIERR_INTERNAL;
-	if (MIDI_ReadByte(wDevID, &byte) != 0) {
-		WARN(midi, "error reading wDevID=%04X\n", wDevID);
-		return MCIERR_INTERNAL;
-	}
-	value = (DWORD)(byte & 0x7F);
-	while (byte & 0x80) {
-		if (MIDI_ReadByte(wDevID, &byte) != 0) {
-			WARN(midi, "error reading wDevID=%04X\n", wDevID);
-			return MCIERR_INTERNAL;
-		}
-		value = (value << 7) + (byte & 0x7F);
-	}
-	*lpdw = value;
-/*
-	TRACE(midi, "val=%08lX \n", value);
-*/
-	return 0;
-}
+    BYTE	byte;
+    DWORD	value;
 
+    if (lpdw == NULL) return MCIERR_INTERNAL;
+    if (MIDI_ReadByte(wDevID, &byte) != 0) {
+	WARN(midi, "error reading wDevID=%04X\n", wDevID);
+	return MCIERR_INTERNAL;
+    }
+    value = (DWORD)(byte & 0x7F);
+    while (byte & 0x80) {
+	if (MIDI_ReadByte(wDevID, &byte) != 0) {
+	    WARN(midi, "error reading wDevID=%04X\n", wDevID);
+	    return MCIERR_INTERNAL;
+	}
+	value = (value << 7) + (byte & 0x7F);
+    }
+    *lpdw = value;
+    /*
+      TRACE(midi, "val=%08lX \n", value);
+    */
+    return 0;
+}
 
 /**************************************************************************
  * 				MIDI_ReadMThd			[internal]	
  */
 static DWORD MIDI_ReadMThd(UINT16 wDevID, DWORD dwOffset)
 {
-	DWORD	toberead;
-	FOURCC	fourcc;
-	TRACE(midi, "(%04X, %08lX);\n", wDevID, dwOffset);
-	if (mmioSeek32(MCIMidiDev[wDevID].hFile, dwOffset, SEEK_SET) != dwOffset) {
-		WARN(midi, "can't seek at %08lX begin of 'MThd' \n", dwOffset);
-		return MCIERR_INTERNAL;
-	}
-	if (mmioRead32(MCIMidiDev[wDevID].hFile, (HPSTR)&fourcc,
-		(long) sizeof(FOURCC)) != (long) sizeof(FOURCC))
-		return MCIERR_INTERNAL;
-	if (MIDI_ReadLong(wDevID, &toberead) != 0)
-		return MCIERR_INTERNAL;
-	if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].wFormat) != 0)
-		return MCIERR_INTERNAL;
-	if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].nTracks) != 0)
-		return MCIERR_INTERNAL;
-	if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].nTempo) != 0)
-		return MCIERR_INTERNAL;
-	TRACE(midi, "toberead=%08lX, wFormat=%04X nTracks=%04X nTempo=%04X\n",
-		toberead, MCIMidiDev[wDevID].wFormat,
-		MCIMidiDev[wDevID].nTracks,
-		MCIMidiDev[wDevID].nTempo);
-	toberead -= 3 * sizeof(WORD);
-/*
-		ntrks = read16bit ();
-		Mf_division = division = read16bit ();
-*/
-	return 0;
-}
+    DWORD	toberead;
+    FOURCC	fourcc;
 
+    TRACE(midi, "(%04X, %08lX);\n", wDevID, dwOffset);
+    if (mmioSeek32(MCIMidiDev[wDevID].hFile, dwOffset, SEEK_SET) != dwOffset) {
+	WARN(midi, "can't seek at %08lX begin of 'MThd' \n", dwOffset);
+	return MCIERR_INTERNAL;
+    }
+    if (mmioRead32(MCIMidiDev[wDevID].hFile, (HPSTR)&fourcc,
+		   (long) sizeof(FOURCC)) != (long) sizeof(FOURCC))
+	return MCIERR_INTERNAL;
+    if (MIDI_ReadLong(wDevID, &toberead) != 0)
+	return MCIERR_INTERNAL;
+    if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].wFormat) != 0)
+	return MCIERR_INTERNAL;
+    if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].nTracks) != 0)
+	return MCIERR_INTERNAL;
+    if (MIDI_ReadWord(wDevID, &MCIMidiDev[wDevID].nTempo) != 0)
+	return MCIERR_INTERNAL;
+    TRACE(midi, "toberead=%08lX, wFormat=%04X nTracks=%04X nTempo=%04X\n",
+	  toberead, MCIMidiDev[wDevID].wFormat,
+	  MCIMidiDev[wDevID].nTracks,
+	  MCIMidiDev[wDevID].nTempo);
+    toberead -= 3 * sizeof(WORD);
+    /*
+      ntrks = read16bit ();
+      Mf_division = division = read16bit ();
+    */
+    return 0;
+}
 
 static DWORD MIDI_ReadMTrk(UINT16 wDevID, DWORD dwOffset)
 {
-	DWORD	toberead;
-	FOURCC	fourcc;
-	if (mmioSeek32(MCIMidiDev[wDevID].hFile, dwOffset, SEEK_SET) != dwOffset) {
-		WARN(midi, "can't seek at %08lX begin of 'MThd' \n", dwOffset);
-		}
-	if (mmioRead32(MCIMidiDev[wDevID].hFile, (HPSTR)&fourcc,
-		(long) sizeof(FOURCC)) != (long) sizeof(FOURCC)) {
-		return MCIERR_INTERNAL;
-		}
-	if (MIDI_ReadLong(wDevID, &toberead) != 0) {
-		return MCIERR_INTERNAL;
-		}
-	TRACE(midi, "toberead=%08lX\n", toberead);
-	toberead -= 3 * sizeof(WORD);
-	MCIMidiDev[wDevID].dwTotalLen = toberead;
-	return 0;
-}
+    DWORD	toberead;
+    FOURCC	fourcc;
 
+    if (mmioSeek32(MCIMidiDev[wDevID].hFile, dwOffset, SEEK_SET) != dwOffset) {
+	WARN(midi, "can't seek at %08lX begin of 'MThd' \n", dwOffset);
+    }
+    if (mmioRead32(MCIMidiDev[wDevID].hFile, (HPSTR)&fourcc,
+		   (long) sizeof(FOURCC)) != (long) sizeof(FOURCC)) {
+	return MCIERR_INTERNAL;
+    }
+    if (MIDI_ReadLong(wDevID, &toberead) != 0) {
+	return MCIERR_INTERNAL;
+    }
+    TRACE(midi, "toberead=%08lX\n", toberead);
+    toberead -= 3 * sizeof(WORD);
+    MCIMidiDev[wDevID].dwTotalLen = toberead;
+    return 0;
+}
 
 /**************************************************************************
  * 				MIDI_mciOpen			[internal]	
  */
 static DWORD MIDI_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_OPEN_PARMS16 lpParms)
 {
-	MIDIOPENDESC 	MidiDesc;
-	DWORD		dwRet;
-	DWORD		dwOffset;
-	LPSTR		lpstrElementName;
-	char		str[128];
-
-	TRACE(midi, "(%08lX, %p)\n", dwFlags, lpParms);
-	if (lpParms == NULL) return MCIERR_INTERNAL;
-
-	if (MCIMidiDev[wDevID].nUseCount > 0) {
-		/* The driver already open on this channel */
-		/* If the driver was opened shareable before and this open specifies */
-		/* shareable then increment the use count */
-		if (MCIMidiDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
-			++MCIMidiDev[wDevID].nUseCount;
-		else
-			return MCIERR_MUST_USE_SHAREABLE;
-	} else {
-		MCIMidiDev[wDevID].nUseCount = 1;
-		MCIMidiDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
-		MCIMidiDev[wDevID].hMidiHdr = USER_HEAP_ALLOC(sizeof(MIDIHDR));
+    MIDIOPENDESC 	MidiDesc;
+    DWORD		dwRet;
+    DWORD		dwOffset;
+    LPSTR		lpstrElementName;
+    char		str[128];
+    
+    TRACE(midi, "(%08lX, %p)\n", dwFlags, lpParms);
+    if (lpParms == NULL) return MCIERR_INTERNAL;
+    
+    if (MCIMidiDev[wDevID].nUseCount > 0) {
+	/* The driver already open on this channel */
+	/* If the driver was opened shareable before and this open specifies */
+	/* shareable then increment the use count */
+	if (MCIMidiDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
+	    ++MCIMidiDev[wDevID].nUseCount;
+	else
+	    return MCIERR_MUST_USE_SHAREABLE;
+    } else {
+	MCIMidiDev[wDevID].nUseCount = 1;
+	MCIMidiDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
+	MCIMidiDev[wDevID].hMidiHdr = USER_HEAP_ALLOC(sizeof(MIDIHDR));
+    }
+    
+    TRACE(midi, "wDevID=%04X\n", wDevID);
+    /*	lpParms->wDeviceID = wDevID;*/
+    TRACE(midi, "lpParms->wDevID=%04X\n", lpParms->wDeviceID);
+    TRACE(midi, "before OPEN_ELEMENT\n");
+    if (dwFlags & MCI_OPEN_ELEMENT) {
+	lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(lpParms->lpstrElementName);
+	TRACE(midi, "MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
+	if (strlen(lpstrElementName) > 0) {
+	    strcpy(str, lpstrElementName);
+	    CharUpper32A(str);
+	    MCIMidiDev[wDevID].hFile = mmioOpen16(str, NULL, 
+						  MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
+	    if (MCIMidiDev[wDevID].hFile == 0) {
+		WARN(midi, "can't find file='%s' !\n", str);
+		return MCIERR_FILE_NOT_FOUND;
+	    }
+	} else 
+	    MCIMidiDev[wDevID].hFile = 0;
+    }
+    TRACE(midi, "hFile=%u\n", MCIMidiDev[wDevID].hFile);
+    memcpy(&MCIMidiDev[wDevID].openParms, lpParms, sizeof(MCI_OPEN_PARMS16));
+    MCIMidiDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
+    MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
+    MCIMidiDev[wDevID].dwBeginData = 0;
+    MCIMidiDev[wDevID].dwTotalLen = 0;
+    MidiDesc.hMidi = 0;
+    if (MCIMidiDev[wDevID].hFile != 0) {
+	MMCKINFO	ckMainRIFF;
+	if (mmioDescend(MCIMidiDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0) {
+	    return MCIERR_INTERNAL;
 	}
-
-	TRACE(midi, "wDevID=%04X\n", wDevID);
-/*	lpParms->wDeviceID = wDevID;*/
-	TRACE(midi, "lpParms->wDevID=%04X\n", lpParms->wDeviceID);
-	TRACE(midi, "before OPEN_ELEMENT\n");
-	if (dwFlags & MCI_OPEN_ELEMENT) {
-		lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(lpParms->lpstrElementName);
-		TRACE(midi, "MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
-		if (strlen(lpstrElementName) > 0) {
-			strcpy(str, lpstrElementName);
-			CharUpper32A(str);
-			MCIMidiDev[wDevID].hFile = mmioOpen16(str, NULL, 
-				MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
-			if (MCIMidiDev[wDevID].hFile == 0) {
-				WARN(midi, "can't find file='%s' !\n", str);
-				return MCIERR_FILE_NOT_FOUND;
-			}
-		} else 
-			MCIMidiDev[wDevID].hFile = 0;
+	TRACE(midi,"ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
+	      (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
+	      ckMainRIFF.cksize);
+	dwOffset = 0;
+	if (ckMainRIFF.ckid == mmioFOURCC('R', 'M', 'I', 'D')) {
+	    TRACE(midi, "is a 'RMID' file \n");
+	    dwOffset = ckMainRIFF.dwDataOffset;
 	}
-	TRACE(midi, "hFile=%u\n", MCIMidiDev[wDevID].hFile);
-	memcpy(&MCIMidiDev[wDevID].openParms, lpParms, sizeof(MCI_OPEN_PARMS16));
-	MCIMidiDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
-	MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
-	MCIMidiDev[wDevID].dwBeginData = 0;
-	MCIMidiDev[wDevID].dwTotalLen = 0;
-	MidiDesc.hMidi = 0;
-	if (MCIMidiDev[wDevID].hFile != 0) {
-		MMCKINFO	ckMainRIFF;
-		if (mmioDescend(MCIMidiDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0) {
-			return MCIERR_INTERNAL;
-		}
-		TRACE(midi,"ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
-				(LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
-				ckMainRIFF.cksize);
-		dwOffset = 0;
-		if (ckMainRIFF.ckid == mmioFOURCC('R', 'M', 'I', 'D')) {
-			TRACE(midi, "is a 'RMID' file \n");
-			dwOffset = ckMainRIFF.dwDataOffset;
-		}
-		if (ckMainRIFF.ckid != mmioFOURCC('M', 'T', 'h', 'd')) {
-			WARN(midi, "unknown format !\n");
-			return MCIERR_INTERNAL;
-		}
-		if (MIDI_ReadMThd(wDevID, dwOffset) != 0) {
-			WARN(midi, "can't read 'MThd' header \n");
-			return MCIERR_INTERNAL;
-		}
-		dwOffset = mmioSeek32(MCIMidiDev[wDevID].hFile, 0, SEEK_CUR);
-		if (MIDI_ReadMTrk(wDevID, dwOffset) != 0) {
-			WARN(midi, "can't read 'MTrk' header \n");
-			return MCIERR_INTERNAL;
-		}
-		dwOffset = mmioSeek32(MCIMidiDev[wDevID].hFile, 0, SEEK_CUR);
-		MCIMidiDev[wDevID].dwBeginData = dwOffset;
-		TRACE(midi, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
-				(LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
-				ckMainRIFF.cksize);
+	if (ckMainRIFF.ckid != mmioFOURCC('M', 'T', 'h', 'd')) {
+	    WARN(midi, "unknown format !\n");
+	    return MCIERR_INTERNAL;
 	}
-
-	dwRet = modMessage(wDevID, MODM_OPEN, 0, (DWORD)&MidiDesc, CALLBACK_NULL);
-/*	dwRet = midMessage(wDevID, MIDM_OPEN, 0, (DWORD)&MidiDesc, CALLBACK_NULL);*/
-
-	return 0;
+	if (MIDI_ReadMThd(wDevID, dwOffset) != 0) {
+	    WARN(midi, "can't read 'MThd' header \n");
+	    return MCIERR_INTERNAL;
+	}
+	dwOffset = mmioSeek32(MCIMidiDev[wDevID].hFile, 0, SEEK_CUR);
+	if (MIDI_ReadMTrk(wDevID, dwOffset) != 0) {
+	    WARN(midi, "can't read 'MTrk' header \n");
+	    return MCIERR_INTERNAL;
+	}
+	dwOffset = mmioSeek32(MCIMidiDev[wDevID].hFile, 0, SEEK_CUR);
+	MCIMidiDev[wDevID].dwBeginData = dwOffset;
+	TRACE(midi, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
+	      (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
+	      ckMainRIFF.cksize);
+    }
+    
+    dwRet = modMessage(wDevID, MODM_OPEN, 0, (DWORD)&MidiDesc, CALLBACK_NULL);
+    /*	dwRet = midMessage(wDevID, MIDM_OPEN, 0, (DWORD)&MidiDesc, CALLBACK_NULL);*/
+    
+    return 0;
 }
 
 /**************************************************************************
@@ -313,458 +354,677 @@
  */
 static DWORD MIDI_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
-	TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (lpParms == NULL) return MCIERR_INTERNAL;
-	MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
-	TRACE(midi, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
-			&MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
-	return 0;
+    TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
+    if (lpParms == NULL) return MCIERR_INTERNAL;
+    MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
+    TRACE(midi, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
+	  &MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
+    return 0;
 }
 
-
 /**************************************************************************
- * 				MIDI_mciClose		[internal]
+ * 				MIDI_mciClose			[internal]
  */
 static DWORD MIDI_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
 {
-	DWORD		dwRet;
-
-	TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
-	if (MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
-		MIDI_mciStop(wDevID, MCI_WAIT, lpParms);
-		}
-	MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
-	MCIMidiDev[wDevID].nUseCount--;
-	if (MCIMidiDev[wDevID].nUseCount == 0) {
-		if (MCIMidiDev[wDevID].hFile != 0) {
-			mmioClose32(MCIMidiDev[wDevID].hFile, 0);
-			MCIMidiDev[wDevID].hFile = 0;
-			TRACE(midi, "hFile closed !\n");
-		}
-		USER_HEAP_FREE(MCIMidiDev[wDevID].hMidiHdr);
-		dwRet = modMessage(wDevID, MODM_CLOSE, 0, 0L, 0L);
-		if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
-/*
-		dwRet = midMessage(wDevID, MIDM_CLOSE, 0, 0L, 0L);
-		if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
-*/
-		}
-	return 0;
+    DWORD		dwRet;
+    
+    TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwParam, lpParms);
+    if (MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
+	MIDI_mciStop(wDevID, MCI_WAIT, lpParms);
+    }
+    MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
+    MCIMidiDev[wDevID].nUseCount--;
+    if (MCIMidiDev[wDevID].nUseCount == 0) {
+	if (MCIMidiDev[wDevID].hFile != 0) {
+	    mmioClose32(MCIMidiDev[wDevID].hFile, 0);
+	    MCIMidiDev[wDevID].hFile = 0;
+	    TRACE(midi, "hFile closed !\n");
+	}
+	USER_HEAP_FREE(MCIMidiDev[wDevID].hMidiHdr);
+	dwRet = modMessage(wDevID, MODM_CLOSE, 0, 0L, 0L);
+	if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
+	/*
+	  dwRet = midMessage(wDevID, MIDM_CLOSE, 0, 0L, 0L);
+	  if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
+	*/
+    }
+    return 0;
 }
 
-
 /**************************************************************************
- * 				MIDI_mciPlay		[internal]
+ * 				MIDI_mciPlay			[internal]
  */
 static DWORD MIDI_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
 {
-	int		count,start,end;
-	LPMIDIHDR	lpMidiHdr;
-	DWORD		dwData,dwRet;
-	LPWORD		ptr;
-
-	TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (MCIMidiDev[wDevID].hFile == 0) {
-		WARN(midi, "can't find file='%08lx' !\n", 
-				(DWORD)MCIMidiDev[wDevID].openParms.lpstrElementName);
-		return MCIERR_FILE_NOT_FOUND;
-	}
-	start = 1; 		end = 99999;
-	if (dwFlags & MCI_FROM) {
-		start = lpParms->dwFrom; 
-		TRACE(midi, "MCI_FROM=%d \n", start);
-	}
-	if (dwFlags & MCI_TO) {
-		end = lpParms->dwTo;
-		TRACE(midi, "MCI_TO=%d \n", end);
-	}
+    int			count,start,end;
+    LPMIDIHDR		lpMidiHdr;
+    DWORD		dwData,dwRet;
+    LPWORD		ptr;
+    
+    TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
+    if (MCIMidiDev[wDevID].hFile == 0) {
+	WARN(midi, "can't find file='%08lx' !\n", 
+	     (DWORD)MCIMidiDev[wDevID].openParms.lpstrElementName);
+	return MCIERR_FILE_NOT_FOUND;
+    }
+    start = 1; 		end = 99999;
+    if (dwFlags & MCI_FROM) {
+	start = lpParms->dwFrom; 
+	TRACE(midi, "MCI_FROM=%d \n", start);
+    }
+    if (dwFlags & MCI_TO) {
+	end = lpParms->dwTo;
+	TRACE(midi, "MCI_TO=%d \n", end);
+    }
 #if 0
-	if (dwFlags & MCI_NOTIFY) {
-		TRACE(midi, "MCI_NOTIFY %08lX !\n", lpParms->dwCallback);
-		switch(fork()) {
-		case -1:
-			WARN(midi, "Can't 'fork' process !\n");
-			break;
-		case 0:
-			TRACE(midi, "process started ! play in background ...\n");
-			break;
-		default:
-			TRACE(midi, "process started ! return to caller...\n");
-			return 0;
-		}
+    if (dwFlags & MCI_NOTIFY) {
+	TRACE(midi, "MCI_NOTIFY %08lX !\n", lpParms->dwCallback);
+	switch(fork()) {
+	case -1:
+	    WARN(midi, "Can't 'fork' process !\n");
+	    break;
+	case 0:
+	    TRACE(midi, "process started ! play in background ...\n");
+	    break;
+	default:
+	    TRACE(midi, "process started ! return to caller...\n");
+	    return 0;
 	}
+    }
 #endif
-
-	lpMidiHdr = USER_HEAP_LIN_ADDR(MCIMidiDev[wDevID].hMidiHdr);
-
-	lpMidiHdr->lpData = (LPSTR)xmalloc(1200);
-	if (lpMidiHdr->lpData == NULL) return MCIERR_INTERNAL;
-	lpMidiHdr->dwBufferLength = 1024;
-	lpMidiHdr->dwUser = 0L;
-	lpMidiHdr->dwFlags = 0L;
-	dwRet = modMessage(wDevID, MODM_PREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
-
-/*	TRACE(midi, "after MODM_PREPARE \n"); */
-
-	MCIMidiDev[wDevID].dwStatus = MCI_MODE_PLAY;
-	while(MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
-		TRACE(midi, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
-			&MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
-
-		ptr = (LPWORD)lpMidiHdr->lpData;
-		for (count = 0; count < lpMidiHdr->dwBufferLength; count++) {
-			if (MIDI_ReadVaryLen(wDevID, &dwData) != 0) break;
-			*ptr = LOWORD(dwData);
-		}
-/*
-		count = mmioRead32(MCIMidiDev[wDevID].hFile, lpMidiHdr->lpData, lpMidiHdr->dwBufferLength);
-*/
-		TRACE(midi, "after read count = %d\n",count);
-
-		if (count < 1) break;
-		lpMidiHdr->dwBytesRecorded = count;
-		TRACE(midi, "before MODM_LONGDATA lpMidiHdr=%p dwBytesRecorded=%lu\n",
-					lpMidiHdr, lpMidiHdr->dwBytesRecorded);
-		dwRet = modMessage(wDevID, MODM_LONGDATA, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
-		if (dwRet != MMSYSERR_NOERROR) {
-		  switch (dwRet) {
-		  case MMSYSERR_NOTENABLED:
-		    return MCIERR_DEVICE_NOT_READY;
-		    
-		  case MIDIERR_NODEVICE:
-		    return MCIERR_INVALID_DEVICE_ID;
-
-		  case MIDIERR_UNPREPARED:
-		    return MCIERR_DRIVER_INTERNAL;
-
-		  case MIDIERR_STILLPLAYING:
-		    return MCIERR_SEQ_PORT_INUSE;
-
-		  case MMSYSERR_INVALPARAM:
-		    return MCIERR_CANNOT_LOAD_DRIVER;
-		  
-		  default:
-		    return MCIERR_DRIVER;
-		  }	
-		}
-	      }
-	dwRet = modMessage(wDevID, MODM_UNPREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
-	if (lpMidiHdr->lpData != NULL) {
-		free(lpMidiHdr->lpData);
-		lpMidiHdr->lpData = NULL;
+    
+    lpMidiHdr = USER_HEAP_LIN_ADDR(MCIMidiDev[wDevID].hMidiHdr);
+    
+    lpMidiHdr->lpData = (LPSTR)xmalloc(1200);
+    if (lpMidiHdr->lpData == NULL) return MCIERR_INTERNAL;
+    lpMidiHdr->dwBufferLength = 1024;
+    lpMidiHdr->dwUser = 0L;
+    lpMidiHdr->dwFlags = 0L;
+    dwRet = modMessage(wDevID, MODM_PREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
+    
+    /*	TRACE(midi, "after MODM_PREPARE \n"); */
+    
+    MCIMidiDev[wDevID].dwStatus = MCI_MODE_PLAY;
+    while(MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
+	TRACE(midi, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
+	      &MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
+	
+	ptr = (LPWORD)lpMidiHdr->lpData;
+	for (count = 0; count < lpMidiHdr->dwBufferLength; count++) {
+	    if (MIDI_ReadVaryLen(wDevID, &dwData) != 0) break;
+	    *ptr = LOWORD(dwData);
 	}
-	MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
-	if (dwFlags & MCI_NOTIFY) {
-		TRACE(midi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
-		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
+	/*
+	  count = mmioRead32(MCIMidiDev[wDevID].hFile, lpMidiHdr->lpData, lpMidiHdr->dwBufferLength);
+	*/
+	TRACE(midi, "after read count = %d\n",count);
+	
+	if (count < 1) break;
+	lpMidiHdr->dwBytesRecorded = count;
+	TRACE(midi, "before MODM_LONGDATA lpMidiHdr=%p dwBytesRecorded=%lu\n",
+	      lpMidiHdr, lpMidiHdr->dwBytesRecorded);
+	dwRet = modMessage(wDevID, MODM_LONGDATA, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
+	if (dwRet != MMSYSERR_NOERROR) {
+	    switch (dwRet) {
+	    case MMSYSERR_NOTENABLED:
+		return MCIERR_DEVICE_NOT_READY;
+		
+	    case MIDIERR_NODEVICE:
+		return MCIERR_INVALID_DEVICE_ID;
+		
+	    case MIDIERR_UNPREPARED:
+		return MCIERR_DRIVER_INTERNAL;
+		
+	    case MIDIERR_STILLPLAYING:
+		return MCIERR_SEQ_PORT_INUSE;
+		
+	    case MMSYSERR_INVALPARAM:
+		return MCIERR_CANNOT_LOAD_DRIVER;
+		
+	    default:
+		return MCIERR_DRIVER;
+	    }	
+	}
+    }
+    dwRet = modMessage(wDevID, MODM_UNPREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
+    if (lpMidiHdr->lpData != NULL) {
+	free(lpMidiHdr->lpData);
+	lpMidiHdr->lpData = NULL;
+    }
+    MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
+    if (dwFlags & MCI_NOTIFY) {
+	TRACE(midi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
+	mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
 			MCIMidiDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
-	}
-	return 0;
-      }
-
+    }
+    return 0;
+}
 
 /**************************************************************************
  * 				MIDI_mciRecord			[internal]
  */
 static DWORD MIDI_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
 {
-	int			start, end;
-	LPMIDIHDR	lpMidiHdr;
-	DWORD		dwRet;
-
-	TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (MCIMidiDev[wDevID].hFile == 0) {
-		WARN(midi, "can't find file='%08lx' !\n", 
-			(DWORD)MCIMidiDev[wDevID].openParms.lpstrElementName);
-		return MCIERR_FILE_NOT_FOUND;
-	}
-	start = 1; 		end = 99999;
-	if (dwFlags & MCI_FROM) {
-		start = lpParms->dwFrom; 
-		TRACE(midi, "MCI_FROM=%d \n", start);
-	}
-	if (dwFlags & MCI_TO) {
-		end = lpParms->dwTo;
-		TRACE(midi, "MCI_TO=%d \n", end);
-	}
-	lpMidiHdr = USER_HEAP_LIN_ADDR(MCIMidiDev[wDevID].hMidiHdr);
-	lpMidiHdr->lpData = (LPSTR) xmalloc(1200);
-	lpMidiHdr->dwBufferLength = 1024;
-	lpMidiHdr->dwUser = 0L;
-	lpMidiHdr->dwFlags = 0L;
-	dwRet = midMessage(wDevID, MIDM_PREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
-	TRACE(midi, "after MIDM_PREPARE \n");
-	MCIMidiDev[wDevID].dwStatus = MCI_MODE_RECORD;
-	while(MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
-		TRACE(midi, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
-			&MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
-		lpMidiHdr->dwBytesRecorded = 0;
-		dwRet = midMessage(wDevID, MIDM_START, 0, 0L, 0L);
-		TRACE(midi, "after MIDM_START lpMidiHdr=%p dwBytesRecorded=%lu\n",
-					lpMidiHdr, lpMidiHdr->dwBytesRecorded);
-		if (lpMidiHdr->dwBytesRecorded == 0) break;
-	}
-	TRACE(midi, "before MIDM_UNPREPARE \n");
-	dwRet = midMessage(wDevID, MIDM_UNPREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
-	TRACE(midi, "after MIDM_UNPREPARE \n");
-	if (lpMidiHdr->lpData != NULL) {
-		free(lpMidiHdr->lpData);
-		lpMidiHdr->lpData = NULL;
-	}
-	MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
-	if (dwFlags & MCI_NOTIFY) {
-		TRACE(midi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
-		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
+    int			start, end;
+    LPMIDIHDR		lpMidiHdr;
+    DWORD		dwRet;
+    
+    TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
+    if (MCIMidiDev[wDevID].hFile == 0) {
+	WARN(midi, "can't find file='%08lx' !\n", 
+	     (DWORD)MCIMidiDev[wDevID].openParms.lpstrElementName);
+	return MCIERR_FILE_NOT_FOUND;
+    }
+    start = 1; 		end = 99999;
+    if (dwFlags & MCI_FROM) {
+	start = lpParms->dwFrom; 
+	TRACE(midi, "MCI_FROM=%d \n", start);
+    }
+    if (dwFlags & MCI_TO) {
+	end = lpParms->dwTo;
+	TRACE(midi, "MCI_TO=%d \n", end);
+    }
+    lpMidiHdr = USER_HEAP_LIN_ADDR(MCIMidiDev[wDevID].hMidiHdr);
+    lpMidiHdr->lpData = (LPSTR) xmalloc(1200);
+    lpMidiHdr->dwBufferLength = 1024;
+    lpMidiHdr->dwUser = 0L;
+    lpMidiHdr->dwFlags = 0L;
+    dwRet = midMessage(wDevID, MIDM_PREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
+    TRACE(midi, "after MIDM_PREPARE \n");
+    MCIMidiDev[wDevID].dwStatus = MCI_MODE_RECORD;
+    while(MCIMidiDev[wDevID].dwStatus != MCI_MODE_STOP) {
+	TRACE(midi, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
+	      &MCIMidiDev[wDevID].dwStatus, MCIMidiDev[wDevID].dwStatus);
+	lpMidiHdr->dwBytesRecorded = 0;
+	dwRet = midMessage(wDevID, MIDM_START, 0, 0L, 0L);
+	TRACE(midi, "after MIDM_START lpMidiHdr=%p dwBytesRecorded=%lu\n",
+	      lpMidiHdr, lpMidiHdr->dwBytesRecorded);
+	if (lpMidiHdr->dwBytesRecorded == 0) break;
+    }
+    TRACE(midi, "before MIDM_UNPREPARE \n");
+    dwRet = midMessage(wDevID, MIDM_UNPREPARE, 0, (DWORD)lpMidiHdr, sizeof(MIDIHDR));
+    TRACE(midi, "after MIDM_UNPREPARE \n");
+    if (lpMidiHdr->lpData != NULL) {
+	free(lpMidiHdr->lpData);
+	lpMidiHdr->lpData = NULL;
+    }
+    MCIMidiDev[wDevID].dwStatus = MCI_MODE_STOP;
+    if (dwFlags & MCI_NOTIFY) {
+	TRACE(midi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
+	mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
 			MCIMidiDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
-	}
-	return 0;
+    }
+    return 0;
 }
 
-
 /**************************************************************************
  * 				MIDI_mciPause			[internal]
  */
 static DWORD MIDI_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
-	TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (lpParms == NULL) return MCIERR_INTERNAL;
-	return 0;
+    TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
+    if (lpParms == NULL) return MCIERR_INTERNAL;
+    return 0;
 }
 
-
 /**************************************************************************
  * 				MIDI_mciResume			[internal]
  */
 static DWORD MIDI_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
 {
-	TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (lpParms == NULL) return MCIERR_INTERNAL;
-	return 0;
+    TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
+    if (lpParms == NULL) return MCIERR_INTERNAL;
+    return 0;
 }
 
-
 /**************************************************************************
  * 				MIDI_mciSet			[internal]
  */
 static DWORD MIDI_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
 {
-	TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (lpParms == NULL) return MCIERR_INTERNAL;
-	TRACE(midi, "dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
-	TRACE(midi, "dwAudio=%08lX\n", lpParms->dwAudio);
-	if (dwFlags & MCI_SET_TIME_FORMAT) {
-		switch (lpParms->dwTimeFormat) {
-		case MCI_FORMAT_MILLISECONDS:
-			TRACE(midi, "MCI_FORMAT_MILLISECONDS !\n");
-			break;
-		case MCI_FORMAT_BYTES:
-			TRACE(midi, "MCI_FORMAT_BYTES !\n");
-			break;
-		case MCI_FORMAT_SAMPLES:
-			TRACE(midi, "MCI_FORMAT_SAMPLES !\n");
-			break;
-		default:
-			WARN(midi, "bad time format !\n");
-			return MCIERR_BAD_TIME_FORMAT;
-		}
+    TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
+    if (lpParms == NULL) return MCIERR_INTERNAL;
+    TRACE(midi, "dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
+    TRACE(midi, "dwAudio=%08lX\n", lpParms->dwAudio);
+    if (dwFlags & MCI_SET_TIME_FORMAT) {
+	switch (lpParms->dwTimeFormat) {
+	case MCI_FORMAT_MILLISECONDS:
+	    TRACE(midi, "MCI_FORMAT_MILLISECONDS !\n");
+	    break;
+	case MCI_FORMAT_BYTES:
+	    TRACE(midi, "MCI_FORMAT_BYTES !\n");
+	    break;
+	case MCI_FORMAT_SAMPLES:
+	    TRACE(midi, "MCI_FORMAT_SAMPLES !\n");
+	    break;
+	default:
+	    WARN(midi, "bad time format !\n");
+	    return MCIERR_BAD_TIME_FORMAT;
 	}
-	if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
-	if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION;
-	if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION;
-	if (dwFlags & MCI_SET_AUDIO)
-		TRACE(midi, "MCI_SET_AUDIO !\n");
-	if (dwFlags && MCI_SET_ON) {
-		TRACE(midi, "MCI_SET_ON !\n");
-		if (dwFlags && MCI_SET_AUDIO_LEFT)
-			TRACE(midi, "MCI_SET_AUDIO_LEFT !\n");
-		if (dwFlags && MCI_SET_AUDIO_RIGHT)
-			TRACE(midi, "MCI_SET_AUDIO_RIGHT !\n");
-	}
-	if (dwFlags & MCI_SET_OFF)
-		TRACE(midi, "MCI_SET_OFF !\n");
-	if (dwFlags & MCI_SEQ_SET_MASTER)
-		TRACE(midi, "MCI_SEQ_SET_MASTER !\n");
-	if (dwFlags & MCI_SEQ_SET_SLAVE)
-		TRACE(midi, "MCI_SEQ_SET_SLAVE !\n");
-	if (dwFlags & MCI_SEQ_SET_OFFSET)
-		TRACE(midi, "MCI_SEQ_SET_OFFSET !\n");
-	if (dwFlags & MCI_SEQ_SET_PORT)
-		TRACE(midi, "MCI_SEQ_SET_PORT !\n");
-	if (dwFlags & MCI_SEQ_SET_TEMPO)
-		TRACE(midi, "MCI_SEQ_SET_TEMPO !\n");
- 	return 0;
+    }
+    if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
+    if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION;
+    if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION;
+    if (dwFlags & MCI_SET_AUDIO)
+	TRACE(midi, "MCI_SET_AUDIO !\n");
+    if (dwFlags && MCI_SET_ON) {
+	TRACE(midi, "MCI_SET_ON !\n");
+	if (dwFlags && MCI_SET_AUDIO_LEFT)
+	    TRACE(midi, "MCI_SET_AUDIO_LEFT !\n");
+	if (dwFlags && MCI_SET_AUDIO_RIGHT)
+	    TRACE(midi, "MCI_SET_AUDIO_RIGHT !\n");
+    }
+    if (dwFlags & MCI_SET_OFF)
+	TRACE(midi, "MCI_SET_OFF !\n");
+    if (dwFlags & MCI_SEQ_SET_MASTER)
+	TRACE(midi, "MCI_SEQ_SET_MASTER !\n");
+    if (dwFlags & MCI_SEQ_SET_SLAVE)
+	TRACE(midi, "MCI_SEQ_SET_SLAVE !\n");
+    if (dwFlags & MCI_SEQ_SET_OFFSET)
+	TRACE(midi, "MCI_SEQ_SET_OFFSET !\n");
+    if (dwFlags & MCI_SEQ_SET_PORT)
+	TRACE(midi, "MCI_SEQ_SET_PORT !\n");
+    if (dwFlags & MCI_SEQ_SET_TEMPO)
+	TRACE(midi, "MCI_SEQ_SET_TEMPO !\n");
+    return 0;
 }
 
-
 /**************************************************************************
- * 				MIDI_mciStatus		[internal]
+ * 				MIDI_mciStatus			[internal]
  */
 static DWORD MIDI_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
 {
-	TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (lpParms == NULL) return MCIERR_INTERNAL;
-	if (dwFlags & MCI_STATUS_ITEM) {
-		switch(lpParms->dwItem) {
-		case MCI_STATUS_CURRENT_TRACK:
-			lpParms->dwReturn = 1;
-			break;
-		case MCI_STATUS_LENGTH:
-			lpParms->dwReturn = 5555;
-			if (dwFlags & MCI_TRACK) {
-				lpParms->dwTrack = 1;
-				lpParms->dwReturn = 2222;
-			}
-			break;
-		case MCI_STATUS_MODE:
-			lpParms->dwReturn = MCI_MODE_STOP;
-			break;
-		case MCI_STATUS_MEDIA_PRESENT:
-			TRACE(midi, "MCI_STATUS_MEDIA_PRESENT !\n");
-			lpParms->dwReturn = TRUE;
-			break;
-		case MCI_STATUS_NUMBER_OF_TRACKS:
-			lpParms->dwReturn = 1;
-			break;
-		case MCI_STATUS_POSITION:
-			lpParms->dwReturn = 3333;
-			if (dwFlags & MCI_STATUS_START)
-				lpParms->dwItem = 1;
-			if (dwFlags & MCI_TRACK) {
-				lpParms->dwTrack = 1;
-				lpParms->dwReturn = 777;
-			}
-			break;
-		case MCI_STATUS_READY:
-			TRACE(midi, "MCI_STATUS_READY !\n");
-			lpParms->dwReturn = TRUE;
-			break;
-		case MCI_STATUS_TIME_FORMAT:
-			TRACE(midi, "MCI_STATUS_TIME_FORMAT !\n");
-			lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
-			break;
-		case MCI_SEQ_STATUS_DIVTYPE:
-			TRACE(midi, "MCI_SEQ_STATUS_DIVTYPE !\n");
-			lpParms->dwReturn = 0;
-			break;
-		case MCI_SEQ_STATUS_MASTER:
-			TRACE(midi, "MCI_SEQ_STATUS_MASTER !\n");
-			lpParms->dwReturn = 0;
-			break;
-		case MCI_SEQ_STATUS_SLAVE:
-			TRACE(midi, "MCI_SEQ_STATUS_SLAVE !\n");
-			lpParms->dwReturn = 0;
-			break;
-		case MCI_SEQ_STATUS_OFFSET:
-			TRACE(midi, "MCI_SEQ_STATUS_OFFSET !\n");
-			lpParms->dwReturn = 0;
-			break;
-		case MCI_SEQ_STATUS_PORT:
-			TRACE(midi, "MCI_SEQ_STATUS_PORT !\n");
-			lpParms->dwReturn = 0;
-			break;
-		case MCI_SEQ_STATUS_TEMPO:
-			TRACE(midi, "MCI_SEQ_STATUS_TEMPO !\n");
-			lpParms->dwReturn = 0;
-			break;
-		default:
-			WARN(midi, "unknowm command %08lX !\n", lpParms->dwItem);
-			return MCIERR_UNRECOGNIZED_COMMAND;
-		}
+    TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
+    if (lpParms == NULL) return MCIERR_INTERNAL;
+    if (dwFlags & MCI_STATUS_ITEM) {
+	switch(lpParms->dwItem) {
+	case MCI_STATUS_CURRENT_TRACK:
+	    lpParms->dwReturn = 1;
+	    break;
+	case MCI_STATUS_LENGTH:
+	    lpParms->dwReturn = 5555;
+	    if (dwFlags & MCI_TRACK) {
+		lpParms->dwTrack = 1;
+		lpParms->dwReturn = 2222;
+	    }
+	    break;
+	case MCI_STATUS_MODE:
+	    lpParms->dwReturn = MCI_MODE_STOP;
+	    break;
+	case MCI_STATUS_MEDIA_PRESENT:
+	    TRACE(midi, "MCI_STATUS_MEDIA_PRESENT !\n");
+	    lpParms->dwReturn = TRUE;
+	    break;
+	case MCI_STATUS_NUMBER_OF_TRACKS:
+	    lpParms->dwReturn = 1;
+	    break;
+	case MCI_STATUS_POSITION:
+	    lpParms->dwReturn = 3333;
+	    if (dwFlags & MCI_STATUS_START)
+		lpParms->dwItem = 1;
+	    if (dwFlags & MCI_TRACK) {
+		lpParms->dwTrack = 1;
+		lpParms->dwReturn = 777;
+	    }
+	    break;
+	case MCI_STATUS_READY:
+	    TRACE(midi, "MCI_STATUS_READY !\n");
+	    lpParms->dwReturn = TRUE;
+	    break;
+	case MCI_STATUS_TIME_FORMAT:
+	    TRACE(midi, "MCI_STATUS_TIME_FORMAT !\n");
+	    lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
+	    break;
+	case MCI_SEQ_STATUS_DIVTYPE:
+	    TRACE(midi, "MCI_SEQ_STATUS_DIVTYPE !\n");
+	    lpParms->dwReturn = 0;
+	    break;
+	case MCI_SEQ_STATUS_MASTER:
+	    TRACE(midi, "MCI_SEQ_STATUS_MASTER !\n");
+	    lpParms->dwReturn = 0;
+	    break;
+	case MCI_SEQ_STATUS_SLAVE:
+	    TRACE(midi, "MCI_SEQ_STATUS_SLAVE !\n");
+	    lpParms->dwReturn = 0;
+	    break;
+	case MCI_SEQ_STATUS_OFFSET:
+	    TRACE(midi, "MCI_SEQ_STATUS_OFFSET !\n");
+	    lpParms->dwReturn = 0;
+	    break;
+	case MCI_SEQ_STATUS_PORT:
+	    TRACE(midi, "MCI_SEQ_STATUS_PORT !\n");
+	    lpParms->dwReturn = 0;
+	    break;
+	case MCI_SEQ_STATUS_TEMPO:
+	    TRACE(midi, "MCI_SEQ_STATUS_TEMPO !\n");
+	    lpParms->dwReturn = 0;
+	    break;
+	default:
+	    WARN(midi, "unknowm command %08lX !\n", lpParms->dwItem);
+	    return MCIERR_UNRECOGNIZED_COMMAND;
 	}
-	if (dwFlags & MCI_NOTIFY) {
-		TRACE(midi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
-		mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
+    }
+    if (dwFlags & MCI_NOTIFY) {
+	TRACE(midi, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
+	mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback), 
 			MCIMidiDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
-	}
- 	return 0;
+    }
+    return 0;
 }
 
 /**************************************************************************
  * 				MIDI_mciGetDevCaps		[internal]
  */
 static DWORD MIDI_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags, 
-					LPMCI_GETDEVCAPS_PARMS lpParms)
+				LPMCI_GETDEVCAPS_PARMS lpParms)
 {
-	TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (lpParms == NULL) return MCIERR_INTERNAL;
-	if (dwFlags & MCI_GETDEVCAPS_ITEM) {
-		switch(lpParms->dwItem) {
-		case MCI_GETDEVCAPS_CAN_RECORD:
-			lpParms->dwReturn = TRUE;
-			break;
-		case MCI_GETDEVCAPS_HAS_AUDIO:
-			lpParms->dwReturn = TRUE;
-			break;
-		case MCI_GETDEVCAPS_HAS_VIDEO:
-			lpParms->dwReturn = FALSE;
-			break;
-		case MCI_GETDEVCAPS_DEVICE_TYPE:
-			lpParms->dwReturn = MCI_DEVTYPE_SEQUENCER;
-			break;
-		case MCI_GETDEVCAPS_USES_FILES:
-			lpParms->dwReturn = TRUE;
-			break;
-		case MCI_GETDEVCAPS_COMPOUND_DEVICE:
-			lpParms->dwReturn = TRUE;
-			break;
-		case MCI_GETDEVCAPS_CAN_EJECT:
-			lpParms->dwReturn = FALSE;
-			break;
-		case MCI_GETDEVCAPS_CAN_PLAY:
-			lpParms->dwReturn = TRUE;
-			break;
-		case MCI_GETDEVCAPS_CAN_SAVE:
-			lpParms->dwReturn = FALSE;
-			break;
-		default:
-			return MCIERR_UNRECOGNIZED_COMMAND;
-		}
+    TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
+    if (lpParms == NULL) return MCIERR_INTERNAL;
+    if (dwFlags & MCI_GETDEVCAPS_ITEM) {
+	switch(lpParms->dwItem) {
+	case MCI_GETDEVCAPS_CAN_RECORD:
+	    lpParms->dwReturn = TRUE;
+	    break;
+	case MCI_GETDEVCAPS_HAS_AUDIO:
+	    lpParms->dwReturn = TRUE;
+	    break;
+	case MCI_GETDEVCAPS_HAS_VIDEO:
+	    lpParms->dwReturn = FALSE;
+	    break;
+	case MCI_GETDEVCAPS_DEVICE_TYPE:
+	    lpParms->dwReturn = MCI_DEVTYPE_SEQUENCER;
+	    break;
+	case MCI_GETDEVCAPS_USES_FILES:
+	    lpParms->dwReturn = TRUE;
+	    break;
+	case MCI_GETDEVCAPS_COMPOUND_DEVICE:
+	    lpParms->dwReturn = TRUE;
+	    break;
+	case MCI_GETDEVCAPS_CAN_EJECT:
+	    lpParms->dwReturn = FALSE;
+	    break;
+	case MCI_GETDEVCAPS_CAN_PLAY:
+	    lpParms->dwReturn = TRUE;
+	    break;
+	case MCI_GETDEVCAPS_CAN_SAVE:
+	    lpParms->dwReturn = FALSE;
+	    break;
+	default:
+	    return MCIERR_UNRECOGNIZED_COMMAND;
 	}
- 	return 0;
+    }
+    return 0;
 }
 
-
 /**************************************************************************
  * 				MIDI_mciInfo			[internal]
  */
 static DWORD MIDI_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
 {
-	TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
-	if (lpParms == NULL) return MCIERR_INTERNAL;
-	lpParms->lpstrReturn = NULL;
-	switch(dwFlags) {
-	case MCI_INFO_PRODUCT:
-		lpParms->lpstrReturn = "Linux Sound System 0.5";
-		break;
-	case MCI_INFO_FILE:
-		lpParms->lpstrReturn = "FileName";
-		break;
-	default:
-		return MCIERR_UNRECOGNIZED_COMMAND;
-	}
-	if (lpParms->lpstrReturn != NULL)
-		lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
-	else
-		lpParms->dwRetSize = 0;
- 	return 0;
+    TRACE(midi, "(%04X, %08lX, %p);\n", wDevID, dwFlags, lpParms);
+    if (lpParms == NULL) return MCIERR_INTERNAL;
+    lpParms->lpstrReturn = NULL;
+    switch(dwFlags) {
+    case MCI_INFO_PRODUCT:
+	lpParms->lpstrReturn = "Linux Sound System 0.5";
+	break;
+    case MCI_INFO_FILE:
+	lpParms->lpstrReturn = "FileName";
+	break;
+    default:
+	return MCIERR_UNRECOGNIZED_COMMAND;
+    }
+    if (lpParms->lpstrReturn != NULL)
+	lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
+    else
+	lpParms->dwRetSize = 0;
+    return 0;
 }
 
-
 /*-----------------------------------------------------------------------*/
 
+#ifdef HAVE_OSS
+/**************************************************************************
+ * 			midiOpenSeq				[internal]
+ */
+static int midiOpenSeq(void)
+{
+    if (numOpenMidiSeq == 0) {
+	midiSeqFD = open(MIDI_SEQ, O_RDWR, 0);
+	if (midiSeqFD == -1) {
+	    ERR(midi, "can't open '%s' ! (%d)\n", MIDI_SEQ, errno);
+	    return -1;
+	}
+	if (fcntl(midiSeqFD, F_SETFL, O_NONBLOCK) < 0) {
+	    WARN(midi, "can't set sequencer fd to non blocking (%d)\n", errno);
+	    close(midiSeqFD);
+	    midiSeqFD = -1;
+	    return -1;
+	}
+	ioctl(midiSeqFD, SNDCTL_SEQ_RESET);
+    }
+    numOpenMidiSeq++;
+    return 0;
+}
+
+/**************************************************************************
+ * 			midiCloseSeq				[internal]
+ */
+static int midiCloseSeq(void)
+{
+    if (--numOpenMidiSeq == 0) {
+	close(midiSeqFD);
+	midiSeqFD = -1;
+    }
+    return 0;
+}
+
+/* FIXME: this is a bad idea, it's even not static... */
+SEQ_DEFINEBUF(1024);
+
+/* FIXME: this is not reentrant, not static - because of global variable 
+ * _seqbuf and al. */
+/**************************************************************************
+ * 			seqbuf_dump				[internal]
+ */
+void seqbuf_dump(void)
+{
+    if (_seqbufptr) {
+	if (write(midiSeqFD, _seqbuf, _seqbufptr) == -1) {
+	    WARN(midi, "Can't write data to sequencer (%d/%d)!\n", 
+		 midiSeqFD, errno);
+	}
+	/* FIXME:
+	 *	in any case buffer is lost so that if many errors occur the buffer 
+	 * will not overrun 
+	 */
+	_seqbufptr = 0;
+    }
+}
+#endif /* HAVE_OSS */
+
+#ifdef HAVE_OSS
+
+static void midReceiveChar(WORD wDevID, unsigned char value, DWORD dwTime)
+{
+    DWORD		toSend = 0;
+    
+    TRACE(midi, "Adding %02xh to %d[%d]\n",
+	  value, wDevID, MidiInDev[wDevID].incLen);
+    
+    if (wDevID >= MAX_MIDIINDRV) {
+	WARN(midi, "bad devID\n");
+	return;
+    }
+    if (MidiInDev[wDevID].state == 0) {
+	TRACE(midi, "input not started, thrown away\n");
+	return;
+    }
+    
+    if (MidiInDev[wDevID].state & 2) { /* system exclusive */
+	LPMIDIHDR	ptr = MidiInDev[wDevID].lpQueueHdr;
+	WORD 			sbfb = FALSE;
+	
+	if (ptr) {
+	    ((LPSTR)(ptr->reserved))[ptr->dwBytesRecorded++] = value;
+	    if (ptr->dwBytesRecorded == ptr->dwBufferLength) {
+		sbfb = TRUE;
+	    } 
+	}
+	if (value == 0xF7) { /* then end */
+	    MidiInDev[wDevID].state &= ~2;
+	    sbfb = TRUE;
+	}
+	if (sbfb && ptr != NULL) {
+	    ptr = MidiInDev[wDevID].lpQueueHdr;
+	    ptr->dwFlags &= ~MHDR_INQUEUE;
+	    ptr->dwFlags |= MHDR_DONE;
+	    MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)ptr->lpNext;
+	    if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD)ptr, dwTime) != MMSYSERR_NOERROR) {
+		WARN(midi, "Couldn't notify client\n");
+	    }
+	}
+	return;
+    }
+    
+#define IS_CMD(_x)	(((_x) & 0x80) == 0x80)
+#define IS_SYS_CMD(_x)	(((_x) & 0xF0) == 0xF0)
+    
+    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;
+	    TRACE(midi, "Reusing old command %02xh\n", MidiInDev[wDevID].incPrev);
+	} else {
+	    FIXME(midi, "error for midi-in, should generate MIM_ERROR notification:"
+		  " prev=%02Xh, incLen=%02Xh\n", 
+		  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];
+    }
+    
+#undef IS_CMD(_x)
+#undef IS_SYS_CMD(_x)
+    
+    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) {
+	    toSend = (MidiInDev[wDevID].incoming[2] << 16) | 
+		(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;
+	} else {		
+	    if (MidiInDev[wDevID].incLen == 1) {
+		toSend = (MidiInDev[wDevID].incoming[0] <<  0);
+	    }
+	}
+	break;
+    default:
+	WARN(midi, "This shouldn't happen (%02X)\n", MidiInDev[wDevID].incoming[0]);
+    }
+    if (toSend != 0) {
+	TRACE(midi, "Sending event %08lx\n", toSend);
+	MidiInDev[wDevID].incLen =	0;
+	dwTime -= MidiInDev[wDevID].startTime;
+	if (MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime) != MMSYSERR_NOERROR) {
+	    WARN(midi, "Couldn't notify client\n");
+	}
+    }
+}
+
+static VOID midTimeCallback(HWND32 hwnd, UINT32 msg, UINT32 id, DWORD dwTime)
+{
+    unsigned	char		buffer[256];
+    int					len, idx;
+    
+    TRACE(midi, "(%04X, %d, %d, %lu)\n", hwnd, msg, id, dwTime);
+    
+    len = read(midiSeqFD, buffer, sizeof(buffer));
+    
+    if ((len % 4) != 0) {
+	WARN(midi, "bad length %d (%d)\n", len, errno);
+	return;
+    }
+    
+    for (idx = 0; idx < len; ) {
+	if (buffer[idx] & 0x80) {
+	    TRACE(midi, 
+		  "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(midi, "Unsupported event %d\n", buffer[idx + 0]);
+		break;
+	    }
+	    idx += 4;
+	}				
+    }
+}
+#endif /* HAVE_OSS */
 
 /**************************************************************************
  * 				midGetDevCaps			[internal]
  */
 static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPS16 lpCaps, DWORD dwSize)
 {
-	TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
-	lpCaps->wMid = 0x00FF; 	        /* Manufac ID */
-	lpCaps->wPid = 0x0001; 	        /* Product ID */
-	lpCaps->vDriverVersion = 0x001; /* Product Version */
-	strcpy(lpCaps->szPname, "Linux MIDIIN Driver");
-
-	return MMSYSERR_NOERROR;
+    LPMIDIINCAPS16	tmplpCaps;
+    
+    TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
+    
+    if (wDevID >= MIDM_NUMDEVS) {
+	return MMSYSERR_BADDEVICEID;
+    }
+    if (lpCaps == NULL) {
+	return MMSYSERR_INVALPARAM;
+    }
+    
+    tmplpCaps = midiInDevices[wDevID];
+    lpCaps->wMid = tmplpCaps->wMid;  
+    lpCaps->wPid = tmplpCaps->wPid;  
+    lpCaps->vDriverVersion = tmplpCaps->vDriverVersion;  
+    strcpy(lpCaps->szPname, tmplpCaps->szPname);    
+    if (dwSize == sizeof(MIDIINCAPS16)) { 
+	/* we should run win 95, so make use of dwSupport */
+	lpCaps->dwSupport = tmplpCaps->dwSupport;
+    } else if (dwSize != sizeof(MIDIINCAPS16) - sizeof(DWORD)) {
+	TRACE(midi, "bad size for lpCaps\n");
+	return MMSYSERR_INVALPARAM;
+    }
+    
+    return MMSYSERR_NOERROR;
 }
 
 /**************************************************************************
@@ -772,46 +1032,85 @@
  */
 static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
 {
-	int		midi;
-	TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
-	if (lpDesc == NULL) {
-		WARN(midi, "Invalid Parameter !\n");
-		return MMSYSERR_INVALPARAM;
+    TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
+    
+    if (lpDesc == NULL) {
+	WARN(midi, "Invalid Parameter !\n");
+	return MMSYSERR_INVALPARAM;
+    }
+    /* FIXME :
+     *	how to check that content of lpDesc is correct ?
+     */
+    if (wDevID >= MAX_MIDIINDRV) {
+	WARN(midi,"wDevID too large (%u) !\n", wDevID);
+	return MMSYSERR_BADDEVICEID;
+    }
+    if (MidiInDev[wDevID].midiDesc != 0) {
+	WARN(midi, "device already open !\n");
+	return MMSYSERR_ALLOCATED;
+    }
+    if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) { 
+	FIXME(midi, "No support for MIDI_IO_STATUS in dwFlags\n");
+	return MMSYSERR_INVALFLAG;
+    }
+    
+#ifdef HAVE_OSS
+    if (midiOpenSeq() < 0) {
+	return MMSYSERR_ERROR;
+    }
+    
+    if (numStartedMidiIn++ == 0) {
+	midiInTimerID = SetTimer32(0, 0, 250, midTimeCallback);
+	if (!midiInTimerID) {
+	    numStartedMidiIn = 0;
+	    WARN(midi, "Couldn't start timer for midi-in\n");
+	    midiCloseSeq();
+	    return MMSYSERR_ERROR;
 	}
-	if (wDevID >= MAX_MIDIINDRV) {
-		TRACE(midi,"MAX_MIDIINDRV reached !\n");
-		return MMSYSERR_ALLOCATED;
-	}
+	TRACE(midi, "Starting timer (%u) for midi-in\n", midiInTimerID);
+    }
+#else /* HAVE_OSS */
+    {
+	int		midi = open(MIDI_DEV, O_WRONLY, 0);
+	
 	MidiInDev[wDevID].unixdev = 0;
-	midi = open (MIDI_DEV, O_RDONLY, 0);
 	if (midi == -1) {
-		WARN(midi,"can't open !\n");
-		return MMSYSERR_NOTENABLED;
+	    WARN(midi,"can't open '%s' (%d)!\n", MIDI_DEV, errno);			
+	    return MMSYSERR_ALLOCATED;
 	}
-	MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
-	switch(MidiInDev[wDevID].wFlags) {
-		case DCB_NULL:
-			TRACE(midi,"CALLBACK_NULL !\n");
-			break;
-		case DCB_WINDOW:
-			TRACE(midi, "CALLBACK_WINDOW !\n");
-			break;
-		case DCB_TASK:
-			TRACE(midi, "CALLBACK_TASK !\n");
-			break;
-		case DCB_FUNCTION:
-			TRACE(midi, "CALLBACK_FUNCTION !\n");
-			break;
-	}
-	MidiInDev[wDevID].lpQueueHdr = NULL;
 	MidiInDev[wDevID].unixdev = midi;
-	MidiInDev[wDevID].dwTotalPlayed = 0;
-	MidiInDev[wDevID].bufsize = 0x3FFF;
-	if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
-		WARN(midi,"can't notify client !\n");
-		return MMSYSERR_INVALPARAM;
-	}
-	return MMSYSERR_NOERROR;
+    }
+#endif /* HAVE_OSS */
+    
+    MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
+    switch(MidiInDev[wDevID].wFlags) {
+    case DCB_NULL:
+	TRACE(midi,"CALLBACK_NULL !\n");
+	break;
+    case DCB_WINDOW:
+	TRACE(midi, "CALLBACK_WINDOW !\n");
+	break;
+    case DCB_TASK:
+	TRACE(midi, "CALLBACK_TASK !\n");
+	break;
+    case DCB_FUNCTION:
+	TRACE(midi, "CALLBACK_FUNCTION (%08lX)!\n", lpDesc->dwCallback);
+	break;
+    }
+    MidiInDev[wDevID].lpQueueHdr = NULL;
+    MidiInDev[wDevID].dwTotalPlayed = 0;
+    MidiInDev[wDevID].bufsize = 0x3FFF;
+    MidiInDev[wDevID].midiDesc = lpDesc;
+    MidiInDev[wDevID].state = 0;
+#ifdef HAVE_OSS
+    MidiInDev[wDevID].incLen = 0;
+    MidiInDev[wDevID].startTime = 0;
+#endif /* HAVE_OSS */
+    if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
+	WARN(midi,"can't notify client !\n");
+	return MMSYSERR_INVALPARAM;
+    }
+    return MMSYSERR_NOERROR;
 }
 
 /**************************************************************************
@@ -819,28 +1118,76 @@
  */
 static DWORD midClose(WORD wDevID)
 {
-	TRACE(midi, "(%04X);\n", wDevID);
-	if (MidiInDev[wDevID].unixdev == 0) {
-		WARN(midi,"can't close !\n");
-		return MMSYSERR_NOTENABLED;
-	}
-	close(MidiInDev[wDevID].unixdev);
-	MidiInDev[wDevID].unixdev = 0;
-	MidiInDev[wDevID].bufsize = 0;
-	if (MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
-		WARN(midi,"can't notify client !\n");
-		return MMSYSERR_INVALPARAM;
-	}
-	return MMSYSERR_NOERROR;
+    int		ret = MMSYSERR_NOERROR;
+    
+    TRACE(midi, "(%04X);\n", wDevID);
+    
+    if (wDevID >= MAX_MIDIINDRV) {
+	WARN(midi,"wDevID too bif (%u) !\n", wDevID);
+	return MMSYSERR_BADDEVICEID;
+    }
+    if (MidiInDev[wDevID].midiDesc == 0) {
+	WARN(midi, "device not opened !\n");
+	return MMSYSERR_ERROR;
+    }
+    if (MidiInDev[wDevID].lpQueueHdr != 0) {
+	return MIDIERR_STILLPLAYING;
+    }
+    
+#ifdef HAVE_OSS
+    if (midiSeqFD == -1) {
+	WARN(midi,"ooops !\n");
+	return MMSYSERR_ERROR;
+    }
+    if (--numStartedMidiIn == 0) {
+	TRACE(midi, "Stopping timer for midi-in\n");
+	if (!KillTimer32(0, midiInTimerID)) {
+	    WARN(midi, "Couldn't stop timer for midi-in\n");
+	}			
+	midiInTimerID = 0;
+    }
+    midiCloseSeq();
+#else /* HAVE_OSS */
+    if (MidiInDev[wDevID].unixdev == 0) {
+	WARN(midi,"ooops !\n");
+	return MMSYSERR_ERROR;
+    }
+    close(MidiInDev[wDevID].unixdev);
+    MidiInDev[wDevID].unixdev = 0;
+#endif /* HAVE_OSS */
+    MidiInDev[wDevID].bufsize = 0;
+    if (MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
+	WARN(midi,"can't notify client !\n");
+	ret = MMSYSERR_INVALPARAM;
+    }
+    MidiInDev[wDevID].midiDesc = 0;
+    return ret;
 }
 
 /**************************************************************************
- * 				midAddBuffer		[internal]
+ * 				midAddBuffer			[internal]
  */
 static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
 {
-	TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
-	return MMSYSERR_NOTENABLED;
+    TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
+    
+    if (lpMidiHdr == NULL)	return MMSYSERR_INVALPARAM;
+    if (sizeof(MIDIHDR) != dwSize) return MMSYSERR_INVALPARAM;
+    if (lpMidiHdr->dwBufferLength == 0) return MMSYSERR_INVALPARAM;
+    if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
+    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
+    
+    if (MidiInDev[wDevID].lpQueueHdr == 0) {
+	MidiInDev[wDevID].lpQueueHdr = lpMidiHdr;
+    } else {
+	LPMIDIHDR	ptr;
+	
+	for (ptr = MidiInDev[wDevID].lpQueueHdr; 
+	     ptr->lpNext != 0; 
+	     ptr = (LPMIDIHDR)ptr->lpNext);
+	ptr->lpNext = (struct midihdr_tag*)lpMidiHdr;
+    }
+    return MMSYSERR_NOERROR;
 }
 
 /**************************************************************************
@@ -848,8 +1195,18 @@
  */
 static DWORD midPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
 {
-	TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
-	return MMSYSERR_NOTENABLED;
+    TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
+    
+    if (dwSize != sizeof(MIDIHDR) || lpMidiHdr == 0 || 
+	lpMidiHdr->lpData == 0 || lpMidiHdr->dwFlags != 0 || 
+	lpMidiHdr->dwBufferLength >= 0x10000ul)
+	return MMSYSERR_INVALPARAM;
+    
+    lpMidiHdr->lpNext = 0;
+    lpMidiHdr->dwFlags |= MHDR_PREPARED;
+    lpMidiHdr->dwBytesRecorded = 0;
+    
+    return MMSYSERR_NOERROR;
 }
 
 /**************************************************************************
@@ -857,8 +1214,18 @@
  */
 static DWORD midUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
 {
-	TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
-	return MMSYSERR_NOTENABLED;
+    TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
+    
+    if (dwSize != sizeof(MIDIHDR) || lpMidiHdr == 0 || 
+	lpMidiHdr->lpData == 0 || lpMidiHdr->dwBufferLength >= 0x10000ul)
+	return MMSYSERR_INVALPARAM;
+    
+    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
+    if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
+    
+    lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
+    
+    return MMSYSERR_NOERROR;
 }
 
 /**************************************************************************
@@ -866,8 +1233,21 @@
  */
 static DWORD midReset(WORD wDevID)
 {
-	TRACE(midi, "(%04X);\n", wDevID);
-	return MMSYSERR_NOTENABLED;
+    DWORD		dwTime = GetTickCount();
+    
+    TRACE(midi, "(%04X);\n", wDevID);
+    
+    while (MidiInDev[wDevID].lpQueueHdr) {
+	MidiInDev[wDevID].lpQueueHdr->dwFlags &= ~MHDR_INQUEUE;
+	MidiInDev[wDevID].lpQueueHdr->dwFlags |= MHDR_DONE;
+	if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, 
+			      (DWORD)MidiInDev[wDevID].lpQueueHdr, dwTime) != MMSYSERR_NOERROR) {
+	    WARN(midi, "Couldn't notify client\n");
+	}
+	MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)MidiInDev[wDevID].lpQueueHdr->lpNext;
+    }
+    
+    return MMSYSERR_NOERROR;
 }
 
 
@@ -876,88 +1256,229 @@
  */
 static DWORD midStart(WORD wDevID)
 {
-	TRACE(midi, "(%04X);\n", wDevID);
-	return MMSYSERR_NOTENABLED;
+    TRACE(midi, "(%04X);\n", wDevID);
+    
+    /* FIXME : should test value of wDevID */
+    
+#ifdef HAVE_OSS
+    MidiInDev[wDevID].state = 1;
+    MidiInDev[wDevID].startTime = GetTickCount();
+    return MMSYSERR_NOERROR;
+#else
+    return MMSYSERR_NOTENABLED;
+#endif /* HAVE_OSS */
 }
 
-
 /**************************************************************************
  *			midStop					[internal]
  */
 static DWORD midStop(WORD wDevID)
 {
-	TRACE(midi, "(%04X);\n", wDevID);
-	return MMSYSERR_NOTENABLED;
+    TRACE(midi, "(%04X);\n", wDevID);
+    
+    /* FIXME : should test value of wDevID */
+    
+#ifdef HAVE_OSS
+    MidiInDev[wDevID].state = 0;
+    return MMSYSERR_NOERROR;
+#else /* HAVE_OSS */
+    return MMSYSERR_NOTENABLED;
+#endif /* HAVE_OSS */
 }
 
-
 /**************************************************************************
  * 			midMessage				[sample driver]
  */
 DWORD WINAPI midMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
-					DWORD dwParam1, DWORD dwParam2)
+			DWORD dwParam1, DWORD dwParam2)
 {
-	TRACE(midi, "(%04X, %04X, %08lX, %08lX, %08lX);\n", 
-			wDevID, wMsg, dwUser, dwParam1, dwParam2);
-	switch(wMsg) {
-	case MIDM_OPEN:
-		return midOpen(wDevID,(LPMIDIOPENDESC)dwParam1, dwParam2);
-	case MIDM_CLOSE:
-		return midClose(wDevID);
-	case MIDM_ADDBUFFER:
-		return midAddBuffer(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
-	case MIDM_PREPARE:
-		return midPrepare(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
-	case MIDM_UNPREPARE:
-		return midUnprepare(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
-	case MIDM_GETDEVCAPS:
-		return midGetDevCaps(wDevID,(LPMIDIINCAPS16)dwParam1,dwParam2);
-	case MIDM_GETNUMDEVS:
-		return 0;
-	case MIDM_RESET:
-		return midReset(wDevID);
-	case MIDM_START:
-		return midStart(wDevID);
-	case MIDM_STOP:
-		return midStop(wDevID);
-	}
-	return MMSYSERR_NOTSUPPORTED;
+    TRACE(midi, "(%04X, %04X, %08lX, %08lX, %08lX);\n", 
+	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
+    switch(wMsg) {
+    case MIDM_OPEN:
+	return midOpen(wDevID,(LPMIDIOPENDESC)dwParam1, dwParam2);
+    case MIDM_CLOSE:
+	return midClose(wDevID);
+    case MIDM_ADDBUFFER:
+	return midAddBuffer(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
+    case MIDM_PREPARE:
+	return midPrepare(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
+    case MIDM_UNPREPARE:
+	return midUnprepare(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
+    case MIDM_GETDEVCAPS:
+	return midGetDevCaps(wDevID,(LPMIDIINCAPS16)dwParam1,dwParam2);
+    case MIDM_GETNUMDEVS:
+	return MIDM_NUMDEVS; 
+    case MIDM_RESET:
+	return midReset(wDevID);
+    case MIDM_START:
+	return midStart(wDevID);
+    case MIDM_STOP:
+	return midStop(wDevID);
+    default:
+	TRACE(midi, "Unsupported message\n");
+    }
+    return MMSYSERR_NOTSUPPORTED;
 }
 
 /*-----------------------------------------------------------------------*/
 
+#ifdef HAVE_OSS
+
+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;
+    
+    int			bender;
+    int			benderRange;
+    /* controlers */
+    int			bank;		/* CTL_BANK_SELECT */
+    int			volume;		/* CTL_MAIN_VOLUME */
+    int			balance;	/* CTL_BALANCE     */
+    int			expression;	/* CTL_EXPRESSION  */
+    int			sustain;	/* CTL_SUSTAIN     */
+    
+    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 */
+    /* do not append fields below voice[1] since the size of this structure 
+     * depends on the number of available voices on the FM synth...
+     */
+} sFMextra;
+
+extern	unsigned char midiFMInstrumentPatches[16 * 128];
+extern	unsigned char midiFMDrumsPatches     [16 * 128];
+
+/**************************************************************************
+ * 			modFMLoad				[internal]
+ */
+static int modFMLoad(int dev)
+{
+    int				i;
+    struct sbi_instrument	sbi;
+    
+    sbi.device = dev;
+    sbi.key = FM_PATCH;
+    
+    memset(sbi.operators + 16, 0, 16);
+    for (i = 0; i < 128; i++) {
+	sbi.channel = i;
+	memcpy(sbi.operators, midiFMInstrumentPatches + i * 16, 16);
+	
+	if (write(midiSeqFD, (char*)&sbi, sizeof(sbi)) == -1) {
+	    WARN(midi, "Couldn't write patch for instrument %d (%d)!\n", sbi.channel, errno);
+	    return -1;
+	}
+    } 
+    for (i = 0; i < 128; i++) {
+	sbi.channel = 128 + i;
+	memcpy(sbi.operators, midiFMDrumsPatches + i * 16, 16);
+	
+	if (write(midiSeqFD, (char*)&sbi, sizeof(sbi)) == -1) {
+	    WARN(midi, "Couldn't write patch for drum %d (%d)!\n", sbi.channel, errno);
+	    return -1;
+	}
+    } 
+    return 0;
+}
+
+/**************************************************************************
+ * 			modFMReset				[internal]
+ */
+static	void modFMReset(WORD wDevID)
+{
+    sFMextra*	extra   = (sFMextra*)MidiOutDev[wDevID].lpExtra;
+    sVoice* 	voice   = extra->voice;
+    sChannel*	channel = extra->channel;
+    int		i;
+    
+    for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+	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;
+	channel[i].expression = 0;	
+	channel[i].sustain = 0;	
+    }
+    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)))
+
+#endif /* HAVE_OSS */
+
 /**************************************************************************
  * 				modGetDevCaps			[internal]
  */
-static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPS16 lpCaps, DWORD dwSize)
+static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPS16 lpCaps, 
+			   DWORD dwSize)
 {
-  LPMIDIOUTCAPS16 tmplpCaps;
-
-	TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
-  if (wDevID == (WORD) MIDI_MAPPER) { 
+    TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
+    if (wDevID == (WORD) MIDI_MAPPER) { 
 	lpCaps->wMid = 0x00FF; 	/* Manufac ID */
 	lpCaps->wPid = 0x0001; 	/* Product ID */
 	lpCaps->vDriverVersion = 0x001; /* Product Version */
-    strcpy(lpCaps->szPname, "MIDI Maper (not functional yet)");
-    lpCaps->wTechnology = MOD_FMSYNTH; /* FIXME Does it make any difference ? */
-    lpCaps->wVoices     = 14;       /* FIXME */
-    lpCaps->wNotes      = 14;       /* FIXME */
-    lpCaps->dwSupport   = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME; /* FIXME Does it make any difference ? */
-  } else {
-    /* FIXME There is a way to do it so easily, but I'm too
-     * sleepy to think and I want to test
-*/
-    tmplpCaps = midiDevices [wDevID];
-    lpCaps->wMid = tmplpCaps->wMid;  
-    lpCaps->wPid = tmplpCaps->wPid;  
-    lpCaps->vDriverVersion = tmplpCaps->vDriverVersion;  
-    strcpy(lpCaps->szPname, tmplpCaps->szPname);    
-    lpCaps->wTechnology = tmplpCaps->wTechnology;
-    lpCaps->wVoices = tmplpCaps->wVoices;  
-    lpCaps->wNotes = tmplpCaps->wNotes;  
-    lpCaps->dwSupport = tmplpCaps->dwSupport;  
-  }
-	return MMSYSERR_NOERROR;
+	strcpy(lpCaps->szPname, "MIDI Mapper (not functional yet)");
+	/* FIXME Does it make any difference ? */
+	lpCaps->wTechnology = MOD_FMSYNTH; 
+	lpCaps->wVoices     = 14;       /* FIXME */
+	lpCaps->wNotes      = 14;       /* FIXME */
+	/* FIXME Does it make any difference ? */
+	lpCaps->dwSupport   = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME; 
+    } else {
+	LPMIDIOUTCAPS16	tmplpCaps;
+	
+	if (wDevID >= MODM_NUMDEVS) {
+	    TRACE(midi, "MAX_MIDIOUTDRV reached !\n");
+	    return MMSYSERR_BADDEVICEID;
+	}
+	/* FIXME There is a way to do it so easily, but I'm too
+	 * sleepy to think and I want to test
+	 */
+	
+	tmplpCaps = midiOutDevices[wDevID];
+	lpCaps->wMid = tmplpCaps->wMid;  
+	lpCaps->wPid = tmplpCaps->wPid;  
+	lpCaps->vDriverVersion = tmplpCaps->vDriverVersion;  
+	strcpy(lpCaps->szPname, tmplpCaps->szPname);    
+	lpCaps->wTechnology = tmplpCaps->wTechnology;
+	lpCaps->wVoices = tmplpCaps->wVoices;  
+	lpCaps->wNotes = tmplpCaps->wNotes;  
+	lpCaps->dwSupport = tmplpCaps->dwSupport;
+    }
+    return MMSYSERR_NOERROR;
 }
 
 /**************************************************************************
@@ -965,48 +1486,101 @@
  */
 static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
 {
-	int		midi;
-
-	TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
-	if (lpDesc == NULL) {
-		WARN(midi, "Invalid Parameter !\n");
-		return MMSYSERR_INVALPARAM;
+    TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
+    if (lpDesc == NULL) {
+	WARN(midi, "Invalid Parameter !\n");
+	return MMSYSERR_INVALPARAM;
+    }
+    if (wDevID >= MAX_MIDIOUTDRV) {
+	TRACE(midi,"MAX_MIDIOUTDRV reached !\n");
+	return MMSYSERR_BADDEVICEID;
+    }
+    if (MidiOutDev[wDevID].midiDesc != 0) {
+	WARN(midi, "device already open !\n");
+	return MMSYSERR_ALLOCATED;
+    }
+    if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) { 
+	WARN(midi, "bad dwFlags\n");
+	return MMSYSERR_INVALFLAG;
+    }
+    
+#ifdef HAVE_OSS
+    MidiOutDev[wDevID].lpExtra = 0;
+    
+    switch (midiOutDevices[wDevID]->wTechnology) {
+    case MOD_FMSYNTH:
+	{
+	    void*	extra = xmalloc(sizeof(struct sFMextra) + 
+					sizeof(struct sVoice) * 
+					(midiOutDevices[wDevID]->wVoices - 1));
+	    
+	    if (extra == 0) {
+		WARN(midi, "can't alloc extra data !\n");
+		return MMSYSERR_NOMEM;
+	    }
+	    MidiOutDev[wDevID].lpExtra = extra;
+	    if (midiOpenSeq() < 0) {
+		MidiOutDev[wDevID].lpExtra = 0;
+		free(extra);
+		return MMSYSERR_ERROR;
+	    }
+	    if (modFMLoad(wDevID) < 0) {
+		midiCloseSeq();
+		MidiOutDev[wDevID].lpExtra = 0;
+		free(extra);
+		return MMSYSERR_ERROR;
+	    }
+	    modFMReset(wDevID);
 	}
-	if (wDevID>= MAX_MIDIOUTDRV) {
-		TRACE(midi,"MAX_MIDIOUTDRV reached !\n");
-		return MMSYSERR_ALLOCATED; /* FIXME isn't MMSYSERR_BADDEVICEID the right answer ? */
+	break;
+    case MOD_MIDIPORT:
+	if (midiOpenSeq() < 0) {
+	    return MMSYSERR_ALLOCATED;
 	}
+	break;
+    default:
+	WARN(midi,"Technology not supported (yet) %d !\n", 
+	     midiOutDevices[wDevID]->wTechnology);
+	return MMSYSERR_NOTENABLED;
+    }
+#else /* HAVE_OSS */
+    {	
+	int	midi = open (MIDI_DEV, O_WRONLY, 0);
 	MidiOutDev[wDevID].unixdev = 0;
-	midi = open (MIDI_DEV, O_WRONLY, 0);
 	if (midi == -1) {
-		WARN(midi, "can't open !\n");
-		return MMSYSERR_NOTENABLED;
+	    WARN(midi, "can't open !\n");
+	    return MMSYSERR_ALLOCATED;
 	}
-	MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
-	switch(MidiOutDev[wDevID].wFlags) {
-	case DCB_NULL:
-		TRACE(midi,"CALLBACK_NULL !\n");
-		break;
-	case DCB_WINDOW:
-		TRACE(midi, "CALLBACK_WINDOW !\n");
-		break;
-	case DCB_TASK:
-		TRACE(midi, "CALLBACK_TASK !\n");
-		break;
-	case DCB_FUNCTION:
-		TRACE(midi, "CALLBACK_FUNCTION !\n");
-		break;
-	}
-	MidiOutDev[wDevID].lpQueueHdr = NULL;
 	MidiOutDev[wDevID].unixdev = midi;
-	MidiOutDev[wDevID].dwTotalPlayed = 0;
-	MidiOutDev[wDevID].bufsize = 0x3FFF;
-	if (MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
-		WARN(midi,"can't notify client !\n");
-		return MMSYSERR_INVALPARAM;
-	}
-	TRACE(midi, "Succesful unixdev=%d !\n", midi);
-	return MMSYSERR_NOERROR;
+    }
+#endif /* HAVE_OSS */	
+    
+    MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
+    switch(MidiOutDev[wDevID].wFlags) {
+    case DCB_NULL:
+	TRACE(midi,"CALLBACK_NULL !\n");
+	break;
+    case DCB_WINDOW:
+	TRACE(midi, "CALLBACK_WINDOW !\n");
+	break;
+    case DCB_TASK:
+	TRACE(midi, "CALLBACK_TASK !\n");
+	break;
+    case DCB_FUNCTION:
+	TRACE(midi, "CALLBACK_FUNCTION !\n");
+	break;
+    }
+    MidiOutDev[wDevID].lpQueueHdr = NULL;
+    MidiOutDev[wDevID].dwTotalPlayed = 0;
+    MidiOutDev[wDevID].bufsize = 0x3FFF;
+    MidiOutDev[wDevID].midiDesc = lpDesc;
+    
+    if (MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
+	WARN(midi,"can't notify client !\n");
+	return MMSYSERR_INVALPARAM;
+    }
+    TRACE(midi, "Succesful !\n");
+    return MMSYSERR_NOERROR;
 }
 
 
@@ -1015,19 +1589,54 @@
  */
 static DWORD modClose(WORD wDevID)
 {
-	TRACE(midi, "(%04X);\n", wDevID);
-	if (MidiOutDev[wDevID].unixdev == 0) {
-		WARN(midi,"can't close !\n");
-		return MMSYSERR_NOTENABLED;
-	}
-	close(MidiOutDev[wDevID].unixdev);
-	MidiOutDev[wDevID].unixdev = 0;
-	MidiOutDev[wDevID].bufsize = 0;
-	if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
-		WARN(midi,"can't notify client !\n");
-		return MMSYSERR_INVALPARAM;
-	}
-	return MMSYSERR_NOERROR;
+    int	ret = MMSYSERR_NOERROR;
+
+    TRACE(midi, "(%04X);\n", wDevID);
+    
+    if (MidiOutDev[wDevID].midiDesc == 0) {
+	WARN(midi, "device not opened !\n");
+	return MMSYSERR_ERROR;
+    }
+    /* FIXME: should test that no pending buffer is still in the queue for
+     * playing */
+    
+#ifdef HAVE_OSS	
+    if (midiSeqFD == -1) {
+	WARN(midi,"can't close !\n");
+	return MMSYSERR_ERROR;
+    }
+    
+    switch (midiOutDevices[wDevID]->wTechnology) {
+    case MOD_FMSYNTH:
+    case MOD_MIDIPORT:
+	midiCloseSeq();
+	break;
+    default:
+	WARN(midi,"Technology not supported (yet) %d !\n", 
+	     midiOutDevices[wDevID]->wTechnology);
+	return MMSYSERR_NOTENABLED;
+    }
+    
+    if (MidiOutDev[wDevID].lpExtra != 0) {
+	free(MidiOutDev[wDevID].lpExtra);
+	MidiOutDev[wDevID].lpExtra = 0;
+    }
+#else
+    if (MidiOutDev[wDevID].unixdev == 0) {
+	WARN(midi,"can't close !\n");
+	return MMSYSERR_NOTENABLED;
+    }
+    close(MidiOutDev[wDevID].unixdev);
+    MidiOutDev[wDevID].unixdev = 0;
+#endif /* HAVE_OSS */
+    
+    MidiOutDev[wDevID].bufsize = 0;
+    if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
+	WARN(midi,"can't notify client !\n");
+	ret = MMSYSERR_INVALPARAM;
+    }
+    MidiOutDev[wDevID].midiDesc = 0;
+    return ret;
 }
 
 /**************************************************************************
@@ -1035,19 +1644,298 @@
  */
 static DWORD modData(WORD wDevID, DWORD dwParam)
 {
-	WORD	event;
-
-	TRACE(midi, "(%04X, %08lX);\n", wDevID, dwParam);
-	if (MidiOutDev[wDevID].unixdev == 0) {
-        	WARN(midi,"can't play !\n");
+    WORD	evt = LOBYTE(LOWORD(dwParam));
+    WORD	d1  = HIBYTE(LOWORD(dwParam));
+    WORD	d2  = LOBYTE(HIWORD(dwParam));
+    
+    TRACE(midi, "(%04X, %08lX);\n", wDevID, dwParam);
+    
+#ifdef HAVE_OSS
+    if (midiSeqFD == -1) {
+	WARN(midi,"can't play !\n");
+	return MIDIERR_NODEVICE;
+    }
+    switch (midiOutDevices[wDevID]->wTechnology) {
+    case MOD_FMSYNTH:
+	/* FIXME:
+	 *	- chorus depth controller is not used
+	 */
+	{
+	    sFMextra*	extra   = (sFMextra*)MidiOutDev[wDevID].lpExtra;
+	    sVoice* 	voice   = extra->voice;
+	    sChannel*	channel = extra->channel;
+	    int		chn = (evt & 0x0F);
+	    int		i, nv;
+	    
+	    switch (evt & 0xF0) {
+	    case MIDI_NOTEOFF:
+		for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+				/* 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);
+		    }
+		}
+		break;	
+	    case MIDI_NOTEON:
+		if (d2 == 0) { /* note off if velocity == 0 */
+		    for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+			/* 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)
+		 */
+		for (i = nv = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+		    if (voice[i].status == sVS_UNUSED || 
+			(voice[i].note == d1 && voice[i].channel == chn)) {
+			nv = i;
+			break;
+		    }
+		    if (voice[i].cntMark < voice[0].cntMark) {
+			nv = i;
+		    }
+		}
+		TRACE(midi, 
+		      "playing on voice=%d, pgm=%d, pan=0x%02X, vol=0x%02X, "
+		      "bender=0x%02X, note=0x%02X, vel=0x%02X\n", 
+		      nv, channel[chn].program, 
+		      channel[chn].balance, 
+		      channel[chn].volume, 
+		      channel[chn].bender, d1, d2);
+		
+		SEQ_SET_PATCH(wDevID, nv, IS_DRUM_CHANNEL(extra, chn) ? 
+			      (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);
+#if 0	
+		/* 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);
+#endif	
+		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:
+		for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+		    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) {
+			for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+			    if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {
+				voice[i].status = sVS_SUSTAINED;
+			    }
+			}
+		    } else {
+			for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+			    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;
+		case CTL_REGIST_PARM_NUM_MSB:	channel[chn].regPmtMSB = d2;	break;
+		    
+		case CTL_DATA_ENTRY:
+		    switch ((channel[chn].regPmtMSB << 8) | channel[chn].regPmtLSB) {
+		    case 0x0000: 
+			if (channel[chn].benderRange != d2) {
+			    channel[chn].benderRange = d2;
+			    for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+				if (voice[i].channel == chn) {
+				    SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);
+				}
+			    }
+			}
+			break;
+			
+		    case 0x7F7F:
+			channel[chn].benderRange = 2;
+			for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+			    if (voice[i].channel == chn) {
+				SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);
+			    }
+			}
+			break;
+		    default:
+			TRACE(midi, "Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n",
+			      channel[chn].regPmtMSB, channel[chn].regPmtLSB,
+			      channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB,
+			      d2);
+			break;
+		    }
+		    break;
+		    
+		case 0x78: /* all sounds off */
+		    for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+			if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) {
+			    voice[i].status = sVS_UNUSED;
+			    SEQ_STOP_NOTE(wDevID, i, voice[i].note, 0);
+			}
+		    }
+		    break;
+		case 0x7B: /* all notes off */
+		    for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+			if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {
+			    voice[i].status = sVS_UNUSED;
+			    SEQ_STOP_NOTE(wDevID, i, voice[i].note, 0);
+			}
+		    }
+		    break;	
+		default:
+		    TRACE(midi, "Dropping MIDI control event 0x%02x(%02x) on channel %d\n", 
+			  d1, d2, chn);
+		    break;
+		}
+		break;
+	    case MIDI_PGM_CHANGE:
+		channel[chn].program = d1;
+		break;
+	    case MIDI_CHN_PRESSURE:
+		for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+		    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;
+		for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
+		    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);
+		    break; 
+		default:
+		    WARN(midi, 
+			 "Unsupported (yet) system event %02x\n", 
+			 evt & 0x0F);
+		}
+		break;
+	    default:	
+		WARN(midi, "Internal error, shouldn't happen\n");
+		return MMSYSERR_NOTENABLED;
+	    }
+	}
+	break;
+    case MOD_MIDIPORT:
+	{
+	    int	dev = wDevID - MODM_NUMFMSYNTHDEVS;
+	    if (dev < 0) {
+		WARN(midi, "Internal error on devID (%u) !\n", wDevID);
 		return MIDIERR_NODEVICE;
+	    }
+	    
+	    switch (evt & 0xF0) {
+	    case MIDI_NOTEOFF:
+	    case MIDI_NOTEON:
+	    case MIDI_KEY_PRESSURE:
+	    case MIDI_CTL_CHANGE:
+	    case MIDI_PITCH_BEND:
+		SEQ_MIDIOUT(dev, evt);	
+		SEQ_MIDIOUT(dev, d1);	
+		SEQ_MIDIOUT(dev, d2); 	
+		break;
+	    case MIDI_PGM_CHANGE:
+	    case MIDI_CHN_PRESSURE:
+		SEQ_MIDIOUT(dev, evt);	
+		SEQ_MIDIOUT(dev, d1);										
+		break;	
+	    case MIDI_SYSTEM_PREFIX:
+		switch (evt & 0x0F) {
+		case 0x00:	/* System Exclusive, don't do it on modData, 
+				 * 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. */
+		    SEQ_MIDIOUT(dev, evt);	
+		    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. */
+		    SEQ_MIDIOUT(dev, evt);	
+		    SEQ_MIDIOUT(dev, d1);	  									
+		case 0x02:	/* Song Position Pointer. */
+		    SEQ_MIDIOUT(dev, evt);	
+		    SEQ_MIDIOUT(dev, d1);
+		    SEQ_MIDIOUT(dev, d2);
+		}
+		break;
+	    }
 	}
-	event = LOWORD(dwParam);
-	if (write (MidiOutDev[wDevID].unixdev, 
-		&event, sizeof(WORD)) != sizeof(WORD)) {
-		WARN(midi, "error writting unixdev !\n");
-	}
+	break;
+    default:
+	WARN(midi, "Technology not supported (yet) %d !\n", 
+	     midiOutDevices[wDevID]->wTechnology);
 	return MMSYSERR_NOTENABLED;
+    }
+    
+    SEQ_DUMPBUF();
+    TRACE(midi, "done\n");
+#else
+    if (MidiOutDev[wDevID].unixdev == 0) {
+	WARN(midi,"can't play !\n");
+	return MIDIERR_NODEVICE;
+    }
+    {
+	WORD	event = LOWORD(dwParam);
+	if (write (MidiOutDev[wDevID].unixdev, 
+		   &event, sizeof(event)) != sizeof(WORD)) {
+	    WARN(midi, "error writting unixdev !\n");
+	}
+    }
+#endif /* HAVE_OSS */
+    return MMSYSERR_NOERROR;
 }
 
 /**************************************************************************
@@ -1055,51 +1943,96 @@
  */
 static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
 {
-	int		count;
-	LPWORD	ptr;
-	int     en;
-
-	TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
-	if (MidiOutDev[wDevID].unixdev == 0) {
-        WARN(midi,"can't play !\n");
-		return MIDIERR_NODEVICE;
-		}
-	if (lpMidiHdr->lpData == NULL) return MIDIERR_UNPREPARED;
-	if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
-	if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
-	lpMidiHdr->dwFlags &= ~MHDR_DONE;
-	lpMidiHdr->dwFlags |= MHDR_INQUEUE;
-	TRACE(midi, "dwBytesRecorded %lu !\n", lpMidiHdr->dwBytesRecorded);
-	TRACE(midi, "                 %02X %02X %02X %02X\n",
-		     lpMidiHdr->lpData[0], lpMidiHdr->lpData[1],
-		     lpMidiHdr->lpData[2], lpMidiHdr->lpData[3]);
-/*
-	count = write (MidiOutDev[wDevID].unixdev, 
-		lpMidiHdr->lpData, lpMidiHdr->dwBytesRecorded);
-*/
-	ptr = (LPWORD)lpMidiHdr->lpData;
-	for (count = 0; count < lpMidiHdr->dwBytesRecorded; count++) {
-		if (write (MidiOutDev[wDevID].unixdev, ptr, 
-			sizeof(WORD)) != sizeof(WORD)) break;
-		ptr++;
+    int		count;
+    
+    TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
+    
+#ifdef HAVE_OSS
+    if (midiSeqFD == -1) {
+	WARN(midi,"can't play !\n");
+	return MIDIERR_NODEVICE;
+    }
+#else /* HAVE_OSS */
+    if (MidiOutDev[wDevID].unixdev == 0) {
+	WARN(midi,"can't play !\n");
+	return MIDIERR_NODEVICE;
+    }
+#endif /* HAVE_OSS */
+    
+    if (lpMidiHdr->lpData == NULL) 
+	return MIDIERR_UNPREPARED;
+    if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) 
+	return MIDIERR_UNPREPARED;
+    if (lpMidiHdr->dwFlags & MHDR_INQUEUE) 
+	return MIDIERR_STILLPLAYING;
+    lpMidiHdr->dwFlags &= ~MHDR_DONE;
+    lpMidiHdr->dwFlags |= MHDR_INQUEUE;
+    TRACE(midi, "dwBytesRecorded %lu !\n", lpMidiHdr->dwBytesRecorded);
+    TRACE(midi, "                 %02X %02X %02X %02X\n",
+	  ((LPBYTE)(lpMidiHdr->reserved))[0],
+	  ((LPBYTE)(lpMidiHdr->reserved))[1],
+	  ((LPBYTE)(lpMidiHdr->reserved))[2],
+	  ((LPBYTE)(lpMidiHdr->reserved))[3]);
+#ifdef HAVE_OSS
+    switch (midiOutDevices[wDevID]->wTechnology) {
+    case MOD_FMSYNTH:
+	/* FIXME: I don't think there is much to do here */
+	break;
+    case MOD_MIDIPORT:
+	if (((LPBYTE)lpMidiHdr->reserved)[0] != 0xF0) {
+	    /* Send end of System Exclusive */
+	    SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 0xF0);
+	    TRACE(midi, "Adding missing 0xF0 marker at the begining of "
+		  "system exclusive byte stream\n");
 	}
-
+	for (count = 0; count < lpMidiHdr->dwBytesRecorded; count++) {
+	    SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 
+			((LPBYTE)lpMidiHdr->reserved)[count]);	
+	}
+	if (((LPBYTE)lpMidiHdr->reserved)[count - 1] != 0xF7) {
+	    /* Send end of System Exclusive */
+	    SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 0xF7);
+	    TRACE(midi, "Adding missing 0xF7 marker at the end of "
+		  "system exclusive byte stream\n");
+	}
+	SEQ_DUMPBUF();
+	break;
+    default:
+	WARN(midi, "Technology not supported (yet) %d !\n", 
+	     midiOutDevices[wDevID]->wTechnology);
+	return MMSYSERR_NOTENABLED;
+    }
+#else /* HAVE_OSS */
+    {
+	LPWORD	ptr = (LPWORD)lpMidiHdr->reserved;
+	int		en;
+	
+	for (count = 0; count < lpMidiHdr->dwBytesRecorded; count++) {
+	    if (write(MidiOutDev[wDevID].unixdev, 
+		      ptr, sizeof(WORD)) != sizeof(WORD)) 
+		break;
+	    ptr++;
+	}
+	
 	en = errno;
 	TRACE(midi, "after write count = %d\n",count);
 	if (count != lpMidiHdr->dwBytesRecorded) {
-		WARN(midi, "error writting unixdev #%d ! (%d != %ld)\n",
-			     MidiOutDev[wDevID].unixdev, count, 
-			     lpMidiHdr->dwBytesRecorded);
-		TRACE(midi, "\terrno = %d error = %s\n",en,strerror(en));
-		return MMSYSERR_NOTENABLED;
+	    WARN(midi, "error writting unixdev #%d ! (%d != %ld)\n",
+		 MidiOutDev[wDevID].unixdev, count, 
+		 lpMidiHdr->dwBytesRecorded);
+	    TRACE(midi, "\terrno = %d error = %s\n",en,strerror(en));
+	    return MMSYSERR_NOTENABLED;
 	}
-	lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
-	lpMidiHdr->dwFlags |= MHDR_DONE;
-	if (MIDI_NotifyClient(wDevID, MOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
-		WARN(midi,"can't notify client !\n");
-		return MMSYSERR_INVALPARAM;
-	}
-	return MMSYSERR_NOERROR;
+    }
+#endif /* HAVE_OSS */
+    
+    lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
+    lpMidiHdr->dwFlags |= MHDR_DONE;
+    if (MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD)lpMidiHdr, 0L) != MMSYSERR_NOERROR) {
+	WARN(midi,"can't notify client !\n");
+	return MMSYSERR_INVALPARAM;
+    }
+    return MMSYSERR_NOERROR;
 }
 
 /**************************************************************************
@@ -1107,21 +2040,28 @@
  */
 static DWORD modPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
 {
-	TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
-	if (MidiOutDev[wDevID].unixdev == 0) {
-		WARN(midi,"can't prepare !\n");
-		return MMSYSERR_NOTENABLED;
-	}
-	if (MidiOutDev[wDevID].lpQueueHdr != NULL) {
-		TRACE(midi,"already prepare !\n");
-		return MMSYSERR_NOTENABLED;
-	}
-	MidiOutDev[wDevID].dwTotalPlayed = 0;
-	MidiOutDev[wDevID].lpQueueHdr = PTR_SEG_TO_LIN(lpMidiHdr);
-	if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
-	lpMidiHdr->dwFlags |= MHDR_PREPARED;
-	lpMidiHdr->dwFlags &= ~MHDR_DONE;
-	return MMSYSERR_NOERROR;
+    TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
+    
+#ifdef HAVE_OSS
+    if (midiSeqFD == -1) {
+	WARN(midi,"can't prepare !\n");
+	return MMSYSERR_NOTENABLED;
+    }
+#else /* HAVE_OSS */
+    if (MidiOutDev[wDevID].unixdev == 0) {
+	WARN(midi,"can't prepare !\n");
+	return MMSYSERR_NOTENABLED;
+    }
+#endif /* HAVE_OSS */
+    if (dwSize != sizeof(MIDIHDR) || lpMidiHdr == 0 || 
+	lpMidiHdr->lpData == 0 || lpMidiHdr->dwFlags != 0 || 
+	lpMidiHdr->dwBufferLength >= 0x10000ul)
+	return MMSYSERR_INVALPARAM;
+    
+    lpMidiHdr->lpNext = 0;
+    lpMidiHdr->dwFlags |= MHDR_PREPARED;
+    lpMidiHdr->dwFlags &= ~MHDR_DONE;
+    return MMSYSERR_NOERROR;
 }
 
 /**************************************************************************
@@ -1129,12 +2069,24 @@
  */
 static DWORD modUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
 {
-	TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
-	if (MidiOutDev[wDevID].unixdev == 0) {
-		WARN(midi,"can't unprepare !\n");
-		return MMSYSERR_NOTENABLED;
-	}
-	return MMSYSERR_NOERROR;
+    TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
+#ifdef HAVE_OSS
+    if (midiSeqFD == -1) {
+	WARN(midi,"can't unprepare !\n");
+	return MMSYSERR_NOTENABLED;
+    }
+#else /* HAVE_OSS */
+    if (MidiOutDev[wDevID].unixdev == 0) {
+	WARN(midi,"can't unprepare !\n");
+	return MMSYSERR_NOTENABLED;
+    }
+#endif /* HAVE_OSS */
+    if (dwSize != sizeof(MIDIHDR) || lpMidiHdr == 0)
+	return MMSYSERR_INVALPARAM;
+    if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
+	return MIDIERR_STILLPLAYING;
+    lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
+    return MMSYSERR_NOERROR;
 }
 
 /**************************************************************************
@@ -1142,102 +2094,106 @@
  */
 static DWORD modReset(WORD wDevID)
 {
-	TRACE(midi, "(%04X);\n", wDevID);
-	return MMSYSERR_NOTENABLED;
+    TRACE(midi, "(%04X);\n", wDevID);
+    /* FIXME: this function should :
+     *	turn off every note, remove sustain on all channels
+     *	remove any pending buffers
+     */
+    return MMSYSERR_NOTENABLED;
 }
 
-
 /**************************************************************************
  * 				modMessage			[sample driver]
  */
 DWORD WINAPI modMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
-					DWORD dwParam1, DWORD dwParam2)
+			DWORD dwParam1, DWORD dwParam2)
 {
-	TRACE(midi, "(%04X, %04X, %08lX, %08lX, %08lX);\n", 
-			wDevID, wMsg, dwUser, dwParam1, dwParam2);
-	switch(wMsg) {
-	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:
-		return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
-	case MODM_PREPARE:
-		return modPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
-	case MODM_UNPREPARE:
-		return modUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
-	case MODM_GETDEVCAPS:
-		return modGetDevCaps(wDevID,(LPMIDIOUTCAPS16)dwParam1,dwParam2);
-	case MODM_GETNUMDEVS:
-		return MODM_NUMDEVS;
-	case MODM_GETVOLUME:
-		return 0;
-	case MODM_SETVOLUME:
-		return 0;
-	case MODM_RESET:
-		return modReset(wDevID);
-	}
-	return MMSYSERR_NOTSUPPORTED;
+    TRACE(midi, "(%04X, %04X, %08lX, %08lX, %08lX);\n", 
+	  wDevID, wMsg, dwUser, dwParam1, dwParam2);
+    switch(wMsg) {
+    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:
+	return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
+    case MODM_PREPARE:
+	return modPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
+    case MODM_UNPREPARE:
+	return modUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
+    case MODM_GETDEVCAPS:
+	return modGetDevCaps(wDevID,(LPMIDIOUTCAPS16)dwParam1,dwParam2);
+    case MODM_GETNUMDEVS:
+	return MODM_NUMDEVS;
+    case MODM_GETVOLUME:
+	return 0;
+    case MODM_SETVOLUME:
+	return 0;
+    case MODM_RESET:
+	return modReset(wDevID);
+    default:
+	TRACE(midi, "Unsupported message\n");
+    }
+    return MMSYSERR_NOTSUPPORTED;
 }
 
-
 /**************************************************************************
  * 				MIDI_DriverProc		[sample driver]
  */
 LONG MIDI_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg, 
 		     DWORD dwParam1, DWORD dwParam2)
 {
-	switch(wMsg) {
-	case DRV_LOAD:
-		return 1;
-	case DRV_FREE:
-		return 1;
-	case DRV_OPEN:
-		return 1;
-	case DRV_CLOSE:
-		return 1;
-	case DRV_ENABLE:
-		return 1;
-	case DRV_DISABLE:
-		return 1;
-	case DRV_QUERYCONFIGURE:
-		return 1;
-	case DRV_CONFIGURE:
-		MessageBox16(0, "Sample Midi Linux Driver !", 
-			     "MMLinux Driver", MB_OK);
-		return 1;
-	case DRV_INSTALL:
-		return DRVCNF_RESTART;
-	case DRV_REMOVE:
-		return DRVCNF_RESTART;
-	case MCI_OPEN_DRIVER:
-	case MCI_OPEN:
-		return MIDI_mciOpen(dwDevID, dwParam1, (LPMCI_OPEN_PARMS16)PTR_SEG_TO_LIN(dwParam2));
-	case MCI_CLOSE_DRIVER:
-	case MCI_CLOSE:
-		return MIDI_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
-	case MCI_PLAY:
-		return MIDI_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
-	case MCI_RECORD:
-		return MIDI_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2));
-	case MCI_STOP:
-		return MIDI_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
-	case MCI_SET:
-		return MIDI_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
-	case MCI_PAUSE:
-		return MIDI_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
-	case MCI_RESUME:
-		return MIDI_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
-	case MCI_STATUS:
-		return MIDI_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2));
-	case MCI_GETDEVCAPS:
-		return MIDI_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2));
-	case MCI_INFO:
-		return MIDI_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(dwParam2));
-	default:
-		return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
-	}
+    switch(wMsg) {
+    case DRV_LOAD:
+	return 1;
+    case DRV_FREE:
+	return 1;
+    case DRV_OPEN:
+	return 1;
+    case DRV_CLOSE:
+	return 1;
+    case DRV_ENABLE:
+	return 1;
+    case DRV_DISABLE:
+	return 1;
+    case DRV_QUERYCONFIGURE:
+	return 1;
+    case DRV_CONFIGURE:
+	MessageBox16(0, "Sample Midi Linux Driver !", 
+		     "MMLinux Driver", MB_OK);
+	return 1;
+    case DRV_INSTALL:
+	return DRVCNF_RESTART;
+    case DRV_REMOVE:
+	return DRVCNF_RESTART;
+    case MCI_OPEN_DRIVER:
+    case MCI_OPEN:
+	return MIDI_mciOpen(dwDevID, dwParam1, (LPMCI_OPEN_PARMS16)PTR_SEG_TO_LIN(dwParam2));
+    case MCI_CLOSE_DRIVER:
+    case MCI_CLOSE:
+	return MIDI_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
+    case MCI_PLAY:
+	return MIDI_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
+    case MCI_RECORD:
+	return MIDI_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2));
+    case MCI_STOP:
+	return MIDI_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
+    case MCI_SET:
+	return MIDI_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
+    case MCI_PAUSE:
+	return MIDI_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
+    case MCI_RESUME:
+	return MIDI_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
+    case MCI_STATUS:
+	return MIDI_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2));
+    case MCI_GETDEVCAPS:
+	return MIDI_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2));
+    case MCI_INFO:
+	return MIDI_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(dwParam2));
+    default:
+	return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
+    }
 }
 /*-----------------------------------------------------------------------*/