B4J Question How to select a MIDI receiver

peter01

Member
Licensed User
Longtime User
Hi,

I have infos of all my connected MIDI devices using parts of Steve05 AudioSystem example. :
Dim MidiRecs() As Object = MidiSystem.RunMethod("getMidiDeviceInfo",Null)

All infos are in a list:
For Each MInfo As JavaObject In MidiRecs
Result.Add(MInfo)
Next

By comparing the list items with the description name of my wanted receiver I get his object index.
But I failed in connecting this receiver with :
Receiver = MidiSystem.RunMethod("getReceiver",Null)
because I don't know how to replace "Null" correctly.

Has somebody an idea??

 

peter01

Member
Licensed User
Longtime User
I took the example from steve05 AudioSystem example and transferred the logic .https://www.b4x.com/android/forum/attachments/audiosystemtest-zip.61040/
form the post https://www.b4x.com/android/forum/threads/play-audio-through-selected-soundcard.85448/#post-541398


I have the Info objects located with :
Dim MidiRecs() As Object = MidiSystem.RunMethod("getMidiDeviceInfo",Null)
Also the port nr. is known by comparing the MidiRecs with the name "Custom MIDI interface" (name of interface I want to connect to)
When I try to connect the device with:
cnt_mid_port = 0
For Each MInfo As JavaObject In MidiRecs
If cnt_mid_port == MyPortNr Then
Log(MInfo)
Receiver = MidiSystem.RunMethod("getMidiDevice",MInfo)
End If
cnt_mid_port = cnt_mid_port + 1
Next
The logged interface is the right one but I get the java exception:
(ClassCastException) java.lang.ClassCastException: com.sun.media.sound.MidiOutDeviceProvider$MidiOutDeviceInfo cannot be cast to [Ljava.lang.Object;
If I select my "Custom MIDI interface" as default interface in windows and use
Receiver = MidiSystem.RunMethod("getReceiver",NULL) everything works fine.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
The line should be :
B4X:
Receiver = MidiSystem.RunMethod("getMidiDevice",Array(MInfo))
 
Upvote 0

peter01

Member
Licensed User
Longtime User
Yes, now the device is recognized. But when I use the "send" Method to transmit e.g. a "note on" message an exception is thrown:
java.lang.RuntimeException: Method: send not found in: com.sun.media.sound.MidiOutDevice

Maybe I have to open the device first, but how? Or is there a special method to invoke the receiver within the device class?
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Can you post your code, please used code tags :

upload_2018-4-18_9-12-41.png
 
Upvote 0

peter01

Member
Licensed User
Longtime User
My code is very long here is the relevant part. If the Sub CtrlChange() is called the exception is thrown,( same with notes). The Sub code is a modification of your example: https://www.b4x.com/android/forum/t...e-guitar-chord-chart-with-midi.62787/#content
The comb.box1 is not used at the moment, I select the interface by name.
Everything works fine if I use" Receiver = MidiSystem.RunMethod("getReceiver",Null)", but with this method I can not select my MIDI Interface, unless it is default. My "Custom MIDI interface" has Receiver and Transmitter in the USB Descriptor, so it shows up 2 times, last time is the Receiver. The Transmitter is not used.


B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private MidiSystem,Receiver,MyDevice,MyReceiver As JavaObject
   ........
End Sub

Private Sub MidiStart
    Try
        'Get the MidiSysten Object
        MidiSystem.InitializeStatic("javax.sound.midi.MidiSystem")
        Dim Result As List
        Result.Initialize
        Dim Class As JavaObject
        Class.InitializeStatic("java.lang.Class")
        Dim MidiRecs() As Object = MidiSystem.RunMethod("getMidiDeviceInfo",Null)
        Dim MyMidiName As String
        MyMidiName = "Custom MIDI interface"
        For Each MInfo As JavaObject In MidiRecs
            Result.Add(MInfo)
        Next
        Dim MyPortNr As Int
        MyPortNr = -1
        For i = 0 To Result.Size-1   
        lbl_status.Text = Result.Get(i)           
        If lbl_status.Text == MyMidiName  Then
            Log("MyMIDI : ---------")
            MyPortNr = i
        End If           
            Log(Result.Get(i))   
        Next
        Log(MyPortNr)
        If MyPortNr == -1 Then
            lbl_status.Text = "Error: Custom MIDI interface not found!"
            Receiver = MidiSystem.RunMethod("getReceiver",Null)
        Else
            lbl_status.Text = "Custom MIDI interface found!"
            lbl_ctrl_name.Text = "Port:"
            lbl_ctrl_val.Text = MyPortNr
            cnt_mid_port = 0
            For Each MInfo As JavaObject In MidiRecs
                If cnt_mid_port == MyPortNr Then
                    '                If cnt_mid_port == 1 Then
                    Log(MInfo)
                    MyDevice = MidiSystem.RunMethod("getMidiDevice",Array(MInfo))
                    Receiver = MyDevice
                End If
                cnt_mid_port = cnt_mid_port + 1
            Next
'            Receiver = MidiSystem.RunMethod("getReceiver",Null)
            Log(Receiver)
        End If
        Log("Midi Device available")
        Log(Receiver)       
    Catch
        'If a midi synth is not available
        Log(LastException)
        Log("Midi System unavailable")
        Return
    End Try
    
    'Create a Short Midi Message
    Dim Message As JavaObject
    Message.InitializeNewInstance("javax.sound.midi.ShortMessage",Null)    
    MidiReady = True
    cmb_box1.Items.AddAll(Result)
End Sub

Private Sub CtrlChange(CtrlNr As Int, CtrlVal As Int)
    If Not(MidiReady) Then
        Log("Midi Device is not ready")
        Return
    End If
    'Create a short midi message
    Dim Message As JavaObject
    Message.InitializeNewInstance("javax.sound.midi.ShortMessage",Null)
    Dim CtrlChg() As Object
    CtrlChg = Array As Object(0xB0,CtrlNr,CtrlVal)
    Message.RunMethod("setMessage",CtrlChg)
    'Send Message
    Receiver.RunMethod("send",Array(Message,TimeStamp))
        
End Sub
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
You got the device ok, but that is not a receiver, you need to change the line:

B4X:
Receiver = MyDevice

To:

B4X:
Receiver = MyDevice.RunMethod("getReceiver",Null)

It should work then.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
OK I guess CtrlChg should be an array of Bytes, not Objects. I can't remember but you may have to mask the values :
B4X:
Bit.And(CtrlNr,0xFF) etc.
 
Upvote 0

peter01

Member
Licensed User
Longtime User
No, CtrlChg ok. The solution is that the device has to be opened with : MyDevice.RunMethod("open",Null) before getting the receiver from the device. Now everything works fine! The documentation of the audio and MIDI implementation of Java is unfortunately not the best.

So thank you very much for your great help!!!
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Yes, the implementation could be better and the documentation doesn't help much.

Still, I'm glad you got it working.
 
Upvote 0
Top