Se connecter
Se connecter

ou
Créer un compte

ou

Récupérer le sysex du message envoyer de mon clavier

  • 2 réponses
  • 2 participants
  • 879 vues
  • 2 followers
Sujet de la discussion Récupérer le sysex du message envoyer de mon clavier
Bonjour ,

je fait un soft pour afficher les partititions et je sait recevoir les données mais
le reste ne vient pas , je n'arrive pas a récupérer le sysex.

Avec vous une idée ?

Je suis en vb6 pour la programmation

Merci d'avance
2
Waow ! La question est simple, mais la réponse risque d'être très technique.

Je vais tenter de donner ma solution.
Elle n'est pas complètement satisfaisante car elle est issue d'expérimentations et se heurte à mes lacunes en programmation avancée : la réception ne semble fonctionner qu'une fois.
Il serait souhaitable que des pros de la programmation améliorent le système que je vais proposer, même si VB6 n'est certainement pas leur outil favori.
Je crois pouvoir dire que ma solution est une exclusivité mondiale compte tenu de l'absence d'exemple sur le net. Elle a le mérite d'être un premier jet sur lequel d'autres pourront apporter des améliorations.
Je vais devoir la rédiger en plusieurs fois.

Tu as déjà sûrement créé une classe qui contient les structures et les fonctions de winmm.dll :
____________________________________________________________________________________
Option Explicit On
Imports System
Imports System.Runtime.InteropServices

'MIDIHR structure for MidiStream functions
Public Structure MIDIHDR
Dim DataPtr As IntPtr
Dim BufferLength As Integer ' size of buffer
Dim BytesRecorded As Integer ' actual amount of data in buffer
Dim MhdrID As Integer 'custom user data
Dim Flags As Integer 'flags giving information about the buffer
Dim Reserved1 As Integer
Dim Reserved2 As Integer
Dim CallbackOffset As Integer ' offset into buffer when callback is performed
Dim Reserved3a As Integer
Dim Reserved3b As Integer
Dim Reserved3c As Integer
Dim Reserved3d As Integer
End Structure

' MIDIINCAPS structure for midiInGetDevCaps function
Public Structure MIDIINCAPS
Dim ManufacturerID As Short
Dim ProductID As Short
Dim DriverVersion As Integer
Dim Label As String
Dim Support As Integer
End Structure

' MIDIOUTCAPS structure for midiOutGetDevCaps function
Public Structure MIDIOUTCAPS
Dim ManufacturerID As Short
Dim ProductID As Short
Dim DriverVersion As Integer
Dim Label As String
Dim Technology As Short
Dim Voices As Short
Dim Notes As Short
Dim ChannelMask As Short
Dim Support As Integer
End Structure

Public Class MIDI

'Constants
Public Const CALLBACK_NULL As ULong = &H0
Public Const CALLBACK_WINDOW As ULong = &H10000
Public Const CALLBACK_THREAD As ULong = &H20000
Public Const CALLBACK_FUNCTION As ULong = &H30000
Public Const MEVT_SHORTMSG As ULong = &H0
Public Const MEVT_TEMPO As ULong = &H1
Public Const MEVT_NOP As ULong = &H2
Public Const MOM_OPEN As ULong = &H3C7
Public Const MOM_CLOSE As ULong = &H3C8
Public Const MOM_DONE As ULong = &H3C9
Public Const MHDR_DONE As ULong = &H1
Public Const MHDR_PREPARED As ULong = &H2
Public Const MHDR_INQUEUE As ULong = &H4
Public Const MHDR_ISSTRM As ULong = &H8

'MIDI Input functions
Declare Auto Function midiInGetNumDevs Lib "winmm.dll" () As Integer
Declare Auto Function midiInGetDevCaps Lib "winmm.dll" (ByVal DeviceID As Integer, ByRef DevCaps As MIDIINCAPS, ByVal Size As Integer) As Integer
Declare Auto Function midiInOpen Lib "winmm.dll" (ByRef DeviceHandle As Integer, ByVal DeviceID As Integer, ByVal CallbackFunction As [delegate], ByVal Instance As Integer, ByVal CallbackFlags As Integer) As Boolean
Declare Auto Function midiInClose Lib "winmm.dll" (ByVal DeviceHandle As Integer) As Integer
Declare Auto Function midiInStart Lib "winmm.dll" (ByVal DeviceHandle As Integer) As Integer
Declare Auto Function midiInStop Lib "winmm.dll" (ByVal DeviceHandle As Integer) As Integer
Declare Auto Function midiInReset Lib "winmm.dll" (ByVal DeviceHandle As Integer) As Integer
Declare Auto Function midiInPrepareHeader Lib "winmm.dll" (ByVal Handle As Integer, ByRef Hdr As MIDIHDR, ByVal Size As Integer) As Integer
Declare Auto Function midiInUnprepareHeader Lib "winmm.dll" (ByVal Handle As Integer, ByRef Hdr As MIDIHDR, ByVal Size As Integer) As Integer
Declare Auto Function midiInAddBuffer Lib "winmm.dll" (ByVal Handle As Integer, ByRef Hdr As MIDIHDR, ByVal Size As Integer) As Integer

'MIDI Output functions
Declare Auto Function midiOutGetNumDevs Lib "winmm.dll" () As Integer
Declare Auto Function midiOutGetDevCaps Lib "winmm.dll" (ByVal DeviceID As Integer, ByRef DevCaps As MIDIOUTCAPS, ByVal Size As Integer) As Integer
Declare Auto Function midiOutOpen Lib "winmm.dll" (ByRef DeviceHandle As Integer, ByVal DeviceID As Integer, ByVal CallbackFunction As Integer, ByVal Instance As Integer, ByVal CallbackFlags As Integer) As Integer
Declare Auto Function midiOutClose Lib "winmm.dll" (ByVal DeviceHandle As Integer) As Integer
Declare Auto Function midiOutShortMsg Lib "winmm.dll" (ByVal DeviceHandle As Integer, ByVal msg As Integer) As Integer
Declare Auto Function midiOutPrepareHeader Lib "winmm.dll" (ByVal Handle As Integer, ByRef Hdr As MIDIHDR, ByVal Size As Integer) As Integer
Declare Auto Function midiOutUnprepareHeader Lib "winmm.dll" (ByVal Handle As Integer, ByRef Hdr As MIDIHDR, ByVal Size As Integer) As Integer
Declare Auto Function midiOutLongMsg Lib "winmm.dll" (ByVal Handle As Integer, ByRef Hdr As MIDIHDR, ByVal Size As Integer) As Integer

End Class
___________________________________________________________________________________
Les fonctions les plus importantes sont
1/ Declare Auto Function midiInPrepareHeader Lib "winmm.dll" (ByVal Handle As Integer, ByRef Hdr As MIDIHDR, ByVal Size As Integer) As Integer
pour préparer le buffer qui va recevoir les sysex.
2/ Declare Auto Function midiInUnprepareHeader Lib "winmm.dll" (ByVal Handle As Integer, ByRef Hdr As MIDIHDR, ByVal Size As Integer) As Integer
pour libérer la mémoire après la réception et le traitement des sysex.
3/ Declare Auto Function midiInAddBuffer Lib "winmm.dll" (ByVal Handle As Integer, ByRef Hdr As MIDIHDR, ByVal Size As Integer) As Integer
pour remplir le(s) buffer(s) des données sysex reçues.

Leur point commun est une variable "Hdr" qui a une structure MIDIHDR, c'est à dire une simple suite d'octets stockés à partir de l'adresse Hdr.DataPtr pour une longueur de Hdr.BytesRecorded.

Je vais prendre un cachet d'aspirine et préparer la suite.

[ Dernière édition du message le 25/07/2011 à 16:17:08 ]

3
Une fois la classe MIDI précédente rajoutée dans l'application principale, ajouter le code suivant de cette application principale que j'ai appelée "MonApplicationMidiQuiReçoitDesSysex", commenté en français :

Option Strict Off
Option Explicit On

Imports System
Imports System.Runtime.InteropServices

Public Class MonApplicationMidiQuiReçoitDesSysex

'Constantes
Public Const BufferInSize As Integer = 270 'taille arbitraire d un sysex en octets
Public Const NumSysexBuffers As Integer = 300 'nombre arbitraire maximum de sysex à recevoir

'Structures
Dim MidiInCaps As New MIDIINCAPS
Dim MidiInHdr(NumSysexBuffers) As MIDIHDR 'sysex buffers à recevoir

'Variables
Dim hMidiIn As Integer
Dim MiNum As Integer
Dim wParam2 As Integer

'pour stocker les octets des sysex :
Dim InSysex(BufferInSize - 1), InSysexData(NumSysexBuffers, BufferInSize - 1) As Byte
Dim buffer As Integer = 0 'index courant du buffer recevant le sysex entrant
Dim CurrentSysex As Integer = 0 'sysex index à exploiter

'Définir la forme générale d une fonction de délégation MidiInDelegate() :
Private Delegate Sub MidiInDelegate(ByVal MidiHandle As Integer, ByVal wMsg As Integer, ByVal Instance As Integer, ByVal wParam As Integer, ByVal lParam As Integer)
'Créer une fonction MidiInCallback de type MidiInDelegate() correspondant à l'adresse de MidiInProc() utilisée par le driver midi
Private MidiInCallback As New MidiInDelegate(AddressOf MidiInProc)

'Définir la forme générale d une fonction déléguée de retour CallBack() :
Private Delegate Sub CallBack(ByVal midiMsg() As Byte, ByVal MidiHandle As Integer, ByVal wMsg As Integer, ByVal Instance As Integer, ByVal wParam As Integer, ByVal lParam As Integer)
'Créer une fonction DelgMidiIn() de type CallBack() correspondant à l'adresse de MidiInMessage() utilisée par Me.Invoke() dans MidiInProc()
Private DelgMidiIn As New CallBack(AddressOf MidiInMessage)

'LES FONCTIONS COMMENCENT ICI :
Private Sub Midi1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
'faire un grand nettoyage avant de fermer l application :
For i = 0 To NumSysexBuffers
Marshal.FreeHGlobal(MidiInHdr(i).DataPtr)
MIDI.midiInUnprepareHeader(hMidiIn, MidiInHdr(i), Marshal.SizeOf(MidiInHdr(i)))
Next
MIDI.midiInStop(hMidiIn)
MIDI.midiInClose(hMidiIn)
End Sub

Private Sub Midi1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'au chargement de l application :
MiNum = MIDI.midiInGetNumDevs
For i = 0 To MiNum - 1
MIDI.midiInGetDevCaps(i, MidiInCaps, Marshal.SizeOf(MidiInCaps))
'les noms des ports midi-in sont stockés dans une liste Indevices :
InDevices.Items.Add(MidiInCaps.Label)
Next
End Sub

' M I D I I N P U T
'lorsque l on choisit un port midi-in dans la liste InDevices :
Private Sub InDevices_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles InDevices.SelectedIndexChanged
'on ferme tout ce qui serait déjà ouvert
For i = 0 To NumSysexBuffers
Marshal.FreeHGlobal(MidiInHdr(i).DataPtr)
MIDI.midiInUnprepareHeader(hMidiIn, MidiInHdr(i), Marshal.SizeOf(MidiInHdr(0)))
Next
MIDI.midiInStop(hMidiIn)
MIDI.midiInClose(hMidiIn)
MIDI.midiOutClose(hMidiOut)
'et on ouvre le port midi-in choisi :
MIDI.midiInOpen(hMidiIn, InDevices.SelectedIndex, MidiInCallback, 0, MIDI.CALLBACK_FUNCTION)
'puis on prépare les buffers qui recevront les sysex entrant
For i = 0 To NumSysexBuffers
'adresse mémoire du premier octet qui sera stocké :
MidiInHdr(i).DataPtr = Marshal.AllocHGlobal(BufferInSize)
'taille attendue d un sysex :
MidiInHdr(i).BufferLength = BufferInSize
MidiInHdr(i).Flags = 0
MIDI.midiInPrepareHeader(hMidiIn, MidiInHdr(i), Marshal.SizeOf(MidiInHdr(i)))
MIDI.midiInAddBuffer(hMidiIn, MidiInHdr(i), Marshal.SizeOf(MidiInHdr(i)))
Next
'buffers prêts ; on peut commencer à recevoir :
MIDI.midiInStart(hMidiIn)
End Sub

Private Sub MidiInProc(ByVal MidiHandle As Integer, ByVal wMsg As Integer, ByVal Instance As Integer, ByVal wParam As Integer, ByVal lParam As Integer)
'Pour les messages midi courts on reçoit 3 octets m(0) m(1) et m(2) contenus dans wParam :
Dim m(2) As Byte
wParam2 = wParam 'pour ne pas détruire wParam dans notre processus
For i As Integer = 0 To 2
Dim _b As Byte = CByte(wParam2 And &HFF)
m(i) = _b
wParam2 = wParam2 >> 8
Next
If Me.InvokeRequired Then
'si une fonction windows de notre programme est appelée, alors ...
'... on invoque MidiInMessage() dont l'adresse est connue de DelgMidiIn :
Me.Invoke(DelgMidiIn, New Object() {m, MidiHandle, wMsg, Instance, wParam, lParam})
End If
End Sub

Private Sub MidiInMessage(ByVal m() As Byte, ByVal MidiHandle As Integer, ByVal wMsg As Integer, ByVal Instance As Integer, ByVal wParam As Integer, ByVal lParam As Integer)
If wMsg = 963 Then 'si le message midi est court
'insérer ici le code pour la gestion des messages midi courts
ElseIf wMsg = 964 Then 'sinon, SYSTEM EXCLUSIVE
Label1.Text = "Receiving Sysex:" + Str(buffer)
buffer = buffer + 1
If buffer = 200 Then 'dans cet exemple les données ne seront exploitées que lorsqu on atteindra 200 sysex reçus :
sysexReceived()
End If
End If
End Sub

Private Sub sysexReceived()
'chaque i est un sysex reçu :
For i = 0 To buffer - 1
'copier les données sysex reçues et stockées à partir de l adresse MidiInHdr(i).DataPtr dans une variable exploitable InSysex :
Marshal.Copy(MidiInHdr(i).DataPtr, InSysex, 0, BufferInSize)
'chaque j est un octet de sysex :
For j = 0 To MidiInHdr(i).BytesRecorded - 1
InSysexData(i, j) = InSysex(j)
Next
End If
Next
'Insérer ici le code qui exploite les sysex stockés dans InSysex(i,j)
'InSysex(i,j) est la table qui contient i sysex reçus (en principe 200) avec, pour chacun, j octets reçus (en principe 270)
'exemple d exploitation :
afficheSysex()
End Sub

Private Sub afficheSysex()
Dim t As String
'la variable CurrentSysex doit déjà être définie par ailleurs dans un contrôle VisualBasic
For i = 0 To BufferInSize - 1
't sera la représentation hexadécimale d un octet
t = Hex(InSysexData(CurrentSysex, i))
If Len(t) = 1 Then
t = "0" + t
End If
'afficher le sysex en valeurs hexadécimales
Label1.Text += t + " "
Next
End Sub

End Class
________________________________________________________________________________________
Ce code est à personnaliser au niveau de la taille des sysex, du nombre de sysex/buffers, etc. Il est bien sûr libre de droit.

On doit pouvoir réutiliser les buffers afin de ne pas être limité par le nombre de sysex à recevoir, en principe sans les déprapéparer/repréparer, en les initialisant :
MidiInHdr(i).Flags = 0
MIDI.midiInAddBuffer(hMidiIn, MidiInHdr(i), Marshal.SizeOf(MidiInHdr(i)))
à tester...

Les fonctions déléguées sont des processus windows qui tournent en parallèle de notre application principale.