and a short setup program.
It works fine here on XP (32bit) SP3 can you test it on your XP(64) VISTA or WIN 7 please ?
Download: TestSetup.zip
The Setup.exe will create one registry key:
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Drivers32\midi4=MIDICable.drv]
and moves MIDICable.drv to the windows system folder.
on end of the setup it will start test01.exe
on my XP i get this output:
The driver creates 6 extra MIDI ports 2 x outputs and 4 x inputsMIDIOut[0] Microsoft GS Wavetable SW Synth
MIDIOut[1] MIDI Out Cable ® 2010
MIDIOut[2] MIDI Out Cable ® 2010
MIDIIn [0] MIDI In Cable ® 2010
MIDIIn [1] MIDI In Cable ® 2010
MIDIIn [2] MIDI In Cable ® 2010
MIDIIn [3] MIDI In Cable ® 2010
Don't worry if it won't work on your box it's only a first test.
Do you need Admin rights to install an driver on your OS ?
You can use uninstall to remove the driver and the registry key.
Thank you for testing
Joshy
You can trust me "i don't install any spam or virus on your box".
MIDICable.bas
Code: Select all
' fbc -dll -s gui MIDICable.bas -X MIDICable.drv
#define UNICODE
#include "windows.bi"
#include "win\mmsystem.bi"
#include "mmddk.bi"
' mmreg.bi are missed in \inc\win
#ifndef MM_MIDI_MAPPER
' MM_MICROSOFT product IDs
#define MM_MIDI_MAPPER 1 ' Midi Mapper
#define MM_WAVE_MAPPER 2 ' Wave Mapper
#define MM_SNDBLST_MIDIOUT 3 ' Sound Blaster MIDI output port
#define MM_SNDBLST_MIDIIN 4 ' Sound Blaster MIDI input port
#define MM_SNDBLST_SYNTH 5 ' Sound Blaster internal synth
#define MM_SNDBLST_WAVEOUT 6 ' Sound Blaster waveform output
#define MM_SNDBLST_WAVEIN 7 ' Sound Blaster waveform input
#define MM_ADLIB 9 ' Ad Lib Compatible synth
#define MM_MPU401_MIDIOUT 10 ' MPU 401 compatible MIDI output port
#define MM_MPU401_MIDIIN 11 ' MPU 401 compatible MIDI input port
#define MM_PC_JOYSTICK 12 ' Joystick adapter
#endif
#ifdef UNICODE
# define STRING_T WSTRING
# define MKSTRING(s) wstr(s)
#else
# define STRING_T ZSTRING
# define MKSTRING(s) (s)
#endif
'#define DEBUG
#ifdef DEBUG
dim shared as STRING_T * 1024 Buffer
dim shared as STRING_T ptr pBuffer=@Buffer
dim shared as STRING_T * 1024 Fmt
' DbgPrint a messages
#macro DMSG(msg)
fmt = MKSTRING("%s")
wsprintf(pBuffer,@fmt,@MKSTRING(msg))
OutputDebugString(pBuffer)
#endmacro
' DbgPrint driver messages
#macro DDRVMSG(msg)
fmt = MKSTRING("%s ID %d hDrv %d p1 %X p2 %X")
wsprintf(pBuffer,@fmt,@MKSTRING(msg),dwDriverId,hDrv,lParam1,lParam2)
OutputDebugString(pBuffer)
#endmacro
' DbgPrint midi In/Out messages
#macro DMXMSG(msg)
fmt = MKSTRING("%s ID %d dwUser %X dwP1 %X dwP2 %X")
wsprintf(pBuffer,@fmt,@MKSTRING(msg),uDeviceId,dwUser,dwParam1,dwParam2)
OutputDebugString(pBuffer)
#endmacro
' DBgPrint MIDIOUTCAPS
#macro DMOCAPS(pCaps)
fmt=MKSTRING(!"MOCAPS\n.wMid %hu\n.wPid %hu\n.Ver %hu\n.szPname %hs\n.wTechnology %hu\n.wVoices %hu\n.wNotes %hu\n.wChannelMask %hu\n")
wsprintf(pBuffer,@fmt, _
pCaps->wMid, _
pCaps->wPid, _
pCaps->vDriverVersion, _
pCaps->szPname, _
pCaps->wTechnology, _
pCaps->wVoices, _
pCaps->wNotes, _
pCaps->wChannelMask)
OutputDebugString(pBuffer)
#endmacro
#else
# define DDRVMSG(msg)
# define DMXMSG(msg)
#endif
#define HAS_MIDI_IN
#define HAS_MIDI_OUT
extern "windows-ms"
function DriverProc (dwDriverId as DWORD, _
hDrv as HDRVR, _
uMsg as UINT, _
lParam1 as LONG, _
lParam2 as LONG) as long export
static as integer id=1
dim as DWORD dwRes = 0
select case uMsg
case DRV_LOAD
DDRVMSG("DRV_LOAD")
' Sent when the driver is loaded.
' This is always the first message received by a driver.
dwRes = 1 ' returns 0 to fail
case DRV_FREE
DDRVMSG("DRV_FREE")
' Sent when the driver is about to be discarded.
' This is the last message a driver receives before it is freed.
dwRes = 1 ' return value ignored
case DRV_OPEN
' Directs the driver to open an new instance.
' dwDriverId Identifier of the installable driver.
'`hdrvr Handle of the installable driver instance.
' lParam1 Address of a null-terminated, wide-character string that specifies configuration information used to open the instance. If no configuration information is available, either this string is empty or the parameter is NULL.
' lParam2 32-bit driver-specific data. (given as the lParam parameter in a call to the OpenDriver function.)
DDRVMSG("DRV_OPEN")
' Sent when the driver is opened.
' Return a nonzero value if successful or zero otherwise.
' If the driver returns a nonzero value, the system uses that value as the driver identifier (the dwDriverId parameter)
' The driver can return "any" type of value as the identifier. For example, some drivers return memory addresses that point
' to instance-specific information. Using this method of specifying identifiers for a driver instance gives the drivers ready access
' to the information while they are processing messages.
dwRes=id
id+=1
return dwRes
case DRV_CLOSE
' dwDriverId Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.
' hdrvr Handle of the installable driver instance.
' lParam1 32-bit value specified as the lParam1 parameter in a call to the DriverClose function.
' lParam2 32-bit value specified as the lParam2 parameter in a call to the DriverClose function.
DDRVMSG("DRV_CLOSE")
' Sent when the driver is closed.
' Drivers are unloaded when the open count reaches zero.
dwRes = 1 ' returns 0 to fail
case DRV_ENABLE
' The driver should initialize any variables and locate devices with the input and output (I/O) interface.
' Drivers are considered enabled from the time they receive this message until they are disabled by using the DRV_DISABLE message.
' hdrvr Handle of the installable driver instance
DDRVMSG("DRV_ENABLE")
' Sent when the driver is loaded or reloaded and when Windows is enabled.
' Install interrupt handlers and initialize hardware.
dwRes = 1 ' return value ignored
case DRV_DISABLE
' Disables the driver.
' The driver should place the corresponding device, if any, in an inactive state and terminate any callback functions or threads.
' hdrvr Handle of the installable driver instance.
DDRVMSG("DRV_DISABLE")
' Sent before the driver is freed or when Windows is disabled.
' Remove interrupt handlers and place hardware in an inactive state.
dwRes = 1' return value ignored
case DRV_INSTALL
' The driver should create and initialize any needed registry keys and values and verify that the supporting drivers and hardware are installed and properly configured.
' dwDriverId Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.
' hdrvr Handle of the installable driver instance.
' lParam2 Address of a DRVCONFIGINFO structure or NULL. If a structure is given, it contains the names of the registry key and value associated with the driver.
DDRVMSG("DRV_INSTALL")
' Sent when the driver is installed.
' Returns one of these values:
' DRVCNF_OK The installation is successful; no further action is required.
' DRVCNF_CANCEL The installation failed..
' DRVCNF_RESTART The installation is successful, but it does not take effect until the system is restarted.
dwRes = DRVCNF_RESTART 'DRVCNF_OK
case DRV_REMOVE
DDRVMSG("DRV_REMOVE")
' Sent when the driver is removed.
dwRes = DRVCNF_RESTART ' DRVCNF_RESTART ' !!! return value ignored !!!
case DRV_QUERYCONFIGURE
DDRVMSG("DRV_QUERYCONFIGURE")
' Sent to determine if the driver can be configured.
return 0 ' Zero indicates configuration NOT supported
case DRV_CONFIGURE
' dwDriverId Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.
' hdrvr Handle of the installable driver instance.
' lParam1 Handle of the parent window. This window is used as the parent window for the configuration dialog box.
' lParam2 Address of a DRVCONFIGINFO structure or NULL. If the structure is given, it contains the names of the registry key and value associated with the driver.
DDRVMSG("DRV_CONFIGURE")
' Sent to display the configuration dialog box for the driver.
dim as PDRVCONFIGINFO pDCI = cast(PDRVCONFIGINFO,lParam1)
return 0'DRVCNF_OK ' Can also return DRVCNF_CANCEL and DRVCNF_RESTART
case DRV_POWER
' Notifies the driver that power to the device is being turned on or off.
' dwDriverId Identifier of the installable driver. This is the same value previously returned by the driver from the DRV_OPEN message.
' hdrvr Handle of the installable driver instance.
DDRVMSG("DRV_POWER")
dwRes = 1
select case lParam1
case PWR_SUSPENDREQUEST:
' If we decided we wanted to try to cause the machine to not suspend,
' we would return PWR_FAIL. However, the machine may still be suspended
' (the APM BIOS may override the driver's wishes).
case PWR_SUSPENDRESUME:
' This notification is just for information.
' PWR_OK should be returned regardless of what the driver does
' to resume normal hardware operations.
case PWR_CRITICALRESUME:
' This notification is just for information.
' This message indicates that the APM BIOS suspended the system without prior notice.
' PWR_OK should be returned regardless of what the driver does to resume
' normal hardware operations.
end select
return PWR_OK
case else ' Process any other messages.
DDRVMSG("DRV_???")
return DefDriverProc (dwDriverId, hDrv, uMsg, lParam1, lParam2)
end select
return dwRes
end function
#ifdef HAS_MIDI_OUT
function modMessage alias "modMessage" (uDeviceID as UINT, _
uMsg as UINT, _
dwUser as DWORD_PTR, _
dwParam1 as DWORD_PTR, _
dwParam2 as DWORD_PTR) as DWORD export
select case uMsg
case MODM_GETNUMDEVS
' uDeviceID Specifies the ID of the target device. Device IDs are sequential and have an initial value of zero and a final value that is equal to one less than the number of devices that the driver supports.
' uMsg WINMM sets this parameter to MODM_GETNUMDEVS when it calls modMessage to process this message.
' dwUser Use this parameter to return instance data to the driver. Drivers that support multiple clients can use this instance data to keep track of the client that is associated with the message.
' dwParam1 Not used.
' dwParam2 Not used.
DMXMSG("MODM_GETNUMDEVS")
return 2 ' return the number of MIDI output devices that the driver supports.
case MODM_GETDEVCAPS
' uDeviceID Specifies the ID of the target device. Device IDs are sequential and have an initial value of zero and a final value that is equal to one less than the number of devices that the driver supports.
' uMsg WINMM sets this parameter to MODM_GETDEVCAPS when it calls modMessage to process this message.
' dwUser Use this parameter to return instance data to the driver. Drivers that support multiple clients can use this instance data to track the client that is associated with the message.
' dwParam1 For Plug and Play drivers, this parameter specifies a pointer to an MDEVICECAPSEX structure. The driver fills this structure with the capabilities of the device.
' For drivers that are not Plug and Play, this parameter specifies a far pointer to a MIDIOUTCAPS data structure. The driver fills this structure with the capabilities of the device.
' dwParam2 For Plug and Play drivers, this parameter specifies a device node.
' For drivers that are not Plug and Play, this parameter specifies the size of the MIDIOUTCAPS structure in bytes.
' NOTE: For drivers that are not Plug and Play, the driver must only write dwParam2 or less bytes to the location pointed to by dwParam1.
' return MMSYSERR_NOERROR ' return MMSYSERR_NOERROR otherwise MMSYSERR_NOTENABLED
if (dwParam1<>NULL) then
DMXMSG("MODM_GETDEVCAPS")
dim as MIDIOUTCAPS ptr pMOCaps = cptr(PMIDIOUTCAPS,dwParam1)
with *pMOCaps
.wMid = 1 ' manufacture ID (ID's = 0 are for user defined i don't know)
.wPid = MM_MPU401_MIDIOUT ' MM_MIDI_MAPPER MM_MPU401_MIDIOUT
.vDriverVersion = &H0010 ' 0.10
.szPname = MKSTRING("MIDI Out Cable © 2010")
.wTechnology = MOD_MIDIPORT
.wVoices = 0 ' If the device is a port, this member is not meaningful and is set to 0.
.wNotes = 0 ' dito
.wChannelMask = &HFFFF ' a port supports all 16 MIDI Channels
.dwSupport = 0 ' no support for optional volume control, MIDI stream or patch caching.
end with
dwParam2=SizeOf(MIDIOUTCAPS)
return MMSYSERR_NOERROR
else
DMXMSG("MODM_GETDEVCAPS !!!")
dwParam2 = 0
return 1
end if
case MODM_OPEN :DMXMSG("MODM_OPEN")
' uDeviceID Specifies the ID of the target device. Device IDs are sequential and have an initial value of zero and a final value equal that is to one less than the number of devices that the driver supports.
' uMsg WINMM sets this parameter to MODM_OPEN when it calls modMessage to process this message.
' dwUser The MIDI output driver must fill this location with its instance data, but only in response to the MODM_OPEN.
' dwParam1 This parameter specifies a far pointer to a MIDIOPENDESC structure. This structure contains additional information for the driver such as instance data from the client and a callback function for the client.
' dwParam2 CALLBACK_EVENT,CALLBACK_FUNCTION,CALLBACK_THREAD,CALLBACK_WINDOW,MIDI_IO_COOKED
dim as PMIDIOPENDESC pMOD = cptr(PMIDIOPENDESC,dwParam1)
' pMOD->dwCallback
' pMOD->dwInstance
' pMOD->hMidi
' If the open operation is successful, the driver uses the DriverCallback function
' to send the client a MOM_OPEN message.
return MMSYSERR_NOERROR
case MODM_CLOSE
DMXMSG("MODM_CLOSE")
return MMSYSERR_NOERROR
case MODM_PREPARE
DMXMSG("MODM_PREPARE")
return MMSYSERR_NOERROR
case MODM_UNPREPARE
DMXMSG("MODM_UNPREPARE")
return MMSYSERR_NOERROR
case MODM_DATA
' uDeviceID Specifies the ID of the target device. Device IDs are sequential and have an initial value of zero and a final value that is equal to one less than the number of devices that the driver supports.
' uMSG WINMM sets this parameter to MODM_DATA when it calls modMessage to process this message.
' dwUser Use this parameter to return instance data to the driver. Drivers that support multiple clients can use this instance data to track the client that is associated with the message.
' dwParam1 Specifies the MIDI event that will be available at the output. The low-order byte is the first byte of the event.
' dwParam2 Not used.
DMXMSG("MODM_DATA")
'return MMSYSERR_NOERROR ' return MMSYSERR_NOERROR otherwise, MMSYSERR_NOTENABLED,MIDIERR_NOTREADY
return MMSYSERR_NOERROR
case MODM_LONGDATA
' uDeviceID Specifies the ID of the target device. Device IDs are sequential and have an initial value of zero and a final value that is equal to one less than the number of devices that the driver supports.
' uMsg WINMM sets this parameter to MODM_LONGDATA when it calls modMessage to process this message.
' dwUser Use this parameter to return instance data to the driver. Drivers that support multiple clients can use this instance data to track the client that is associated with the message.
' dwParam1 This parameter specifies a far pointer to MIDIHDR data structure that identifies the data block.
' dwParam2 This parameter specifies the size of the MIDIHDR structure.
DMXMSG("MODM_LONGDATA")
'return MMSYSERR_NOERROR ' Otherwise, MMSYSERR_NOTENABLED or MIDIERR_UNPREPARED or MIDIERR_NOTREADY
return MMSYSERR_NOTSUPPORTED
case MODM_RESET
DMXMSG("MODM_RESET")
return MMSYSERR_NOTSUPPORTED
case MODM_GETVOLUME
DMXMSG("MODM_GETVOLUME")
return MMSYSERR_NOTSUPPORTED
case MODM_SETVOLUME
DMXMSG("MODM_SETVOLUME")
return MMSYSERR_NOTSUPPORTED
case MODM_CACHEPATCHES
DMXMSG("MODM_CACHEPATCHES")
return MMSYSERR_NOTSUPPORTED
case MODM_CACHEDRUMPATCHES
DMXMSG("MODM_CACHEDRUMPATCHES")
return MMSYSERR_NOTSUPPORTED
case MODM_STRMDATA
DMXMSG("MODM_STRMDATA")
return MMSYSERR_NOTSUPPORTED
case MODM_GETPOS
DMXMSG("MODM_GETPOS")
return MMSYSERR_NOTSUPPORTED
case MODM_PAUSE
DMXMSG("MODM_PAUSE")
return MMSYSERR_NOTSUPPORTED
case MODM_RESTART
DMXMSG("MODM_RESTART")
return MMSYSERR_NOTSUPPORTED
case MODM_STOP
DMXMSG("MODM_STOP")
return MMSYSERR_NOTSUPPORTED
case MODM_PROPERTIES
DMXMSG("MODM_PROPERTIES")
return MMSYSERR_NOTSUPPORTED
case MODM_PREFERRED
DMXMSG("MODM_PREFERRED")
return MMSYSERR_NOTSUPPORTED
case MODM_RECONFIGURE
DMXMSG("MODM_RECONFIGURE") ' (MODM_USER+&H0768)
return MMSYSERR_NOTSUPPORTED
case else
DMXMSG("MODM_???")
return MMSYSERR_NOTSUPPORTED
end select
end function
#endif
#ifdef HAS_MIDI_IN
function midMessage (uDeviceID as UINT, _
uMsg as UINT, _
dwUser as DWORD_PTR, _
dwParam1 as DWORD_PTR, _
dwParam2 as DWORD_PTR) as DWORD export
select case uMsg
case MIDM_GETNUMDEVS
DMXMSG("MIDM_GETNUMDEVS")
return 4
case MIDM_GETDEVCAPS
if (dwParam1<>NULL) then
DMXMSG("MIDM_GETDEVCAPS")
dim as MIDIINCAPS ptr pMICaps = cptr(PMIDIINCAPS,dwParam1)
with *pMICaps
.wMid = 1 ' manufacture ID (ID's = 0 are for user defined i don't know)
.wPid = MM_MPU401_MIDIIN ' MM_MIDI_MAPPER MM_MPU401_MIDIIN
.vDriverVersion = &H0010 ' 0.10
.szPname = MKSTRING("MIDI In Cable © 2010")
.dwSupport = 0 ' no support for optional volume control, MIDI stream or patch caching.
end with
dwParam2=SizeOf(MIDIINCAPS)
return MMSYSERR_NOERROR
else
DMXMSG("MIDM_GETDEVCAPS !!!")
dwParam2 = 0
return 1
end if
case MIDM_OPEN
DMXMSG("MIDM_OPEN")
case MIDM_CLOSE
DMXMSG("MIDM_CLOSE")
case MIDM_PREPARE
DMXMSG("MIDM_PREPARE")
case MIDM_UNPREPARE
DMXMSG("MIDM_UNPREPARE")
case MIDM_ADDBUFFER
DMXMSG("MIDM_ADDBUFFER")
case MIDM_START
DMXMSG("MIDM_START")
case MIDM_STOP
DMXMSG("MIDM_STOP")
case MIDM_RESET
DMXMSG("MIDM_RESET")
case else
DMXMSG("MIDM_???")
return MMSYSERR_NOTSUPPORTED
end select
return 0
end function
#endif
#ifdef HAS_CALLBACK
BOOL DriverCallback alias "DriverCallback" (dwCallback as DWORD_PTR, _
dwFlags as DWORD, _
hDevice as HDRVR, _
dwMsg as DWORD, _
dwUser as DWORD_PTR, _
dwParam1 as DWORD_PTR, _
dwParam2 as DWORD_PTR) as BOOL export
end function
#endif
end extern
Code: Select all
#include "windows.bi"
#include "win\mmsystem.bi"
dim as integer nI = midiInGetNumDevs()
dim as integer nO = midiOutGetNumDevs()
if ni>0 then
dim as MIDIINCAPS iCaps
for i as integer=0 to nI-1
midiInGetDevCaps(i,@iCaps,sizeof(MIDIINCAPS))
print "MIDIIn [" & i & "] " & iCaps.szPname
next
print
end if
if nO>0 then
dim as MIDIOUTCAPS oCaps
for i as integer=0 to nO-1
midiOutGetDevCaps(i,@oCaps,sizeof(MIDIOUTCAPS))
print "MIDIOut[" & i & "] " & oCaps.szPname
next
end if
sleep