Lao_Xiong

I want a simple program when click button "SysEx" it send out MIDI SysEx message 'F0 7D 12 34 10 02 11 00 F7',

but the follow routine send out '00 7D 12 34 10 02 11 00 00'.

Then I downloaded Mabry's MIDIIO32.OCX and test its demo project "SYSEX", it also couldn't send out the 'F0' and 'F7', but with a wrong '00'.

I'm sure the receiver is correct. (MIDI Yoke + MIDI OX etc., and MIDI hardware device)

What's wrong about it

Private Sub cmdSysEx_Click()

Dim SysEx As String
Dim MyHdr As MIDIHDR

SysEx = Chr(&HF0) & Chr(&H7D) & Chr(&H12) & Chr(&H34) & Chr(&H10) & Chr(&H2) & Chr(&H11) & Chr(&H0) & Chr(&HF7)

MyHdr.dwBufferLength = Len(SysEx)
MyHdr.dwBytesRecorded = Len(SysEx)
MyHdr.lpData = SysEx
MyHdr.dwFlags = 0

midiOutPrepareHeader hmidi, MyHdr, Len(MyHdr)
midiOutLongMsg hmidi, MyHdr, Len(MyHdr)
midiOutUnprepareHeader hmidi, MyHdr, Len(MyHdr)

End Sub



Re: Visual Basic General midiOutLongMsg Send Wrong SysEx ?

nobugz

The .NET String type doesn't store bytes, it stores Unicode characters. They will get translated when you P/Invoke the midiOutLongMsg() function. Start using byte arrays instead of strings.





Re: Visual Basic General midiOutLongMsg Send Wrong SysEx ?

Lao_Xiong

nobugz wrote:
The .NET String type doesn't store bytes, it stores Unicode characters. They will get translated when you P/Invoke the midiOutLongMsg() function. Start using byte arrays instead of strings.

Thanks for your suggestion!

I modified the code :

Dim SysEx(10) As Byte

SysEx(0) = &HF0
SysEx(1) = &H7D
SysEx(2) = &H12
SysEx(3) = &H34
SysEx(4) = &H10
SysEx(5) = &H2
SysEx(6) = &H11
SysEx(7) = &H0
SysEx(8) = &HF7

But it send out many strange bytes, none is correct.





Re: Visual Basic General midiOutLongMsg Send Wrong SysEx ?

nobugz

Show us your P/Invoke declaration for mdiOutLongMsg().





Re: Visual Basic General midiOutLongMsg Send Wrong SysEx ?

Lao_Xiong

nobugz wrote:
Show us your P/Invoke declaration for mdiOutLongMsg().

Type MIDIHDR

lpData As String

dwBufferLength As Long

dwBytesRecorded As Long

dwUser As Long

dwFlags As Long

lpNext As Long
Reserved As Long

End Type

Declare Function midiOutPrepareHeader Lib "winmm.dll" (ByVal hMidiOut As Long, lpMidiOutHdr As MIDIHDR, ByVal uSize As Long) As Long





Re: Visual Basic General midiOutLongMsg Send Wrong SysEx ?

nobugz

This cannot work properly unless you are using VB6. Are you using VB.NET





Re: Visual Basic General midiOutLongMsg Send Wrong SysEx ?

Lao_Xiong

I use VB6.

But the system installed .NET Framework.

Is it the reason How to modify my code





Re: Visual Basic General midiOutLongMsg Send Wrong SysEx ?

nobugz






Re: Visual Basic General midiOutLongMsg Send Wrong SysEx ?

Lao_Xiong

nobugz wrote:

I'll searching them and report here if found the answer.

Thank you so much.





Re: Visual Basic General midiOutLongMsg Send Wrong SysEx ?

obiwanjacobi

These are my p/Invoke declarations which work fine (although in C#):

[DllImport("winmm.dll")]

public static extern int midiOutLongMsg(MidiSafeHandle handle,

IntPtr header, int sizeOfmidiHeader);

I use SafeHandles to wrap the midi handle. If you don't have/want this use an IntPtr instead. The header itself is allocated as an unmanaged memory block.

[StructLayout(LayoutKind.Sequential)]

internal struct MidiHeader

{

public IntPtr data;

public int bufferLength;

public int bytesRecorded;

public int user;

public int flags;

public IntPtr next;

public int reserved;

public int offset;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]

public int[] reservedArray;

}

The MidiHeader.data is an IntPtr and I assign an allocated buffer of unmanaged memory to it containing the SysEx message (F0....F7).

I think you have to either pin managed objects or allocate unmanaged memory to pass to the midi-API in order to prohibit the GC from taking it while the midi driver is working with it.

My 2 cents.






Re: Visual Basic General midiOutLongMsg Send Wrong SysEx ?

Lao_Xiong

Thank you, Marc Jacobi!

Unfortunately, I'm a beginner, still couldn't find the way to modify my code (in VB6) after your suggestion :-(

Somebody please help me to modify the code

___________________________________________________________

module.bas

Option Explicit

Public Const MAXPNAMELEN = 32

Type MIDIOUTCAPS
wMid As Integer
wPid As Integer
vDriverVersion As Long
szPname As String * MAXPNAMELEN
wTechnology As Integer
wVoices As Integer
wNotes As Integer
wChannelMask As Integer
dwSupport As Long
End Type

Declare Function midiOutGetNumDevs Lib "winmm" () As Integer
Declare Function midiOutGetDevCaps Lib "winmm.dll" Alias "midiOutGetDevCapsA" (ByVal uDeviceID As Long, lpCaps As MIDIOUTCAPS, ByVal uSize As Long) As Long

Declare Function midiOutClose Lib "winmm.dll" (ByVal hMidiOut As Long) As Long
Declare Function midiOutOpen Lib "winmm.dll" (lphMidiOut As Long, ByVal uDeviceID As Long, ByVal dwCallback As Long, ByVal dwInstance As Long, ByVal dwFlags As Long) As Long

Type MIDIHDR
lpData As String
dwBufferLength As Long
dwBytesRecorded As Long
dwUser As Long
dwFlags As Long
lpNext As Long
Reserved As Long
End Type

Declare Function midiOutLongMsg Lib "winmm.dll" (ByVal hMidiOut As Long, lpMidiOutHdr As MIDIHDR, ByVal uSize As Long) As Long
Declare Function midiOutPrepareHeader Lib "winmm.dll" (ByVal hMidiOut As Long, lpMidiOutHdr As MIDIHDR, ByVal uSize As Long) As Long
Declare Function midiOutUnprepareHeader Lib "winmm.dll" (ByVal hMidiOut As Long, lpMidiOutHdr As MIDIHDR, ByVal uSize As Long) As Long

____________________________________________________________

Dim NumberOutDevice As Long
Dim curDevice As Long
Dim hmidi As Long
Dim rc As Long

Private Sub cmdSysEx_Click()

Dim SysEx As String
Dim MyHdr As MIDIHDR

SysEx = Chr(&HF0) & Chr(&H7D) & Chr(&H12) & Chr(&H34) & Chr(&H10) & Chr(&H2) & Chr(&H11) & Chr(&H0) & Chr(&HF7)

MyHdr.dwBufferLength = Len(SysEx)
MyHdr.dwBytesRecorded = Len(SysEx)
MyHdr.lpData = SysEx
MyHdr.dwFlags = 0

midiOutPrepareHeader hmidi, MyHdr, Len(MyHdr)
midiOutLongMsg hmidi, MyHdr, Len(MyHdr)
midiOutUnprepareHeader hmidi, MyHdr, Len(MyHdr)

End Sub

Private Sub Form_Load()

Dim i As Long
Dim caps As MIDIOUTCAPS

' set the first MIDI OUT device as MIDI Mapper
out_device(0).Caption = "MIDI Mapper"
out_device(0).Enabled = True
out_device(0).Visible = True

' get number of MIDI OUT device
NumberOutDevice = midiOutGetNumDevs()

' get MIDI OUT device name
For i = 0 To (NumberOutDevice - 1)

midiOutGetDevCaps i, caps, Len(caps)

out_device(i + 1).Caption = caps.szPname
out_device(i + 1).Visible = True
out_device(i + 1).Enabled = True

Next

' init variable
curDevice = 0

' Select the MIDI Mapper as the default device
out_device_Click (0)

End Sub

Private Sub Form_Unload(Cancel As Integer)

' Close current midi device
rc = midiOutClose(hmidi)

End Sub

Private Sub out_device_Click(Index As Integer)

out_device(curDevice + 1).Checked = False
out_device(Index).Checked = True

curDevice = Index - 1

rc = midiOutClose(hmidi)
rc = midiOutOpen(hmidi, curDevice, 0, 0, 0)

If (rc <> 0) Then
MsgBox "Couldn't open midi out, rc = " & rc
End If

End Sub