B4J Question [B4j] Javax Midi Lib

Luca1967

Active Member
Hi Stevel.

I want to change the volume in the track.
First I delete the "Channel Volume" events in the track.
To write the new volume again, what can I do?
 
It's Correct?

Dim mm As MidiShortMessage
mm.Initialize
mm.Create1Byte(Bit.Or(MidiStatus.CONTROL_CHANGE,3),10)

Dim PCEvt As MidiEvent
PCEvt.Initialize
PCEvt.CreateShort(mm,SalvaTick)
T.Add(PCEvt)
 
Upvote 0
If I do this it changes me by putting "4" also in the channel when the channel of track 4 is number 3.

Dim mm As MidiShortMessage
mm.Initialize

mm.Create2Bytes(Bit.Or(MidiStatus.CONTROL_CHANGE,4),7,10)

Dim PCEvt As MidiEvent
PCEvt.Initialize
PCEvt.CreateShort(mm,SalvaTick)
T.Add(PCEvt)
 
Upvote 0
There are several possible ways to change the volume dependant on which the synth responds to. See the list here: https://www.songstuff.com/recording/article/midi_message_format/

CC1 is the Mod wheel (that is on most keyboards) and can change the volume if the synth responds to it.
CC7 the channel volume
CC11 Expression as a percentage of CC7

If you are changing CC7 and CC11 is 0 you may not hear anything if the synth responds to it.

It requires a 2byte message with the volume (byte 3) being 0 - 127 as in your second post. Channels should be referenced 0 - 15

You can also change the note on velocity for each note. This may be the only way if the synth does not respond to cc messages.
 
Upvote 0
Ok. Function. :-)

Code: Copy
Dim NuovoVolume As Double = Value
Dim T As MidiTrack = Main.Seq.GetTracks(oo)
Dim canale As Int
Canale = GetTrackChannel(t)
Dim mm As MidiShortMessage
mm.Initialize
mm.Create4(MidiStatus.CONTROL_CHANGE,canale,7,127)
Dim PCEvt As MidiEvent
PCEvt.Initialize
PCEvt.CreateShort(mm,SalvaTick)
T.Add(PCEvt)
 
Upvote 0
I noticed that when I go to fetch the volume value via midichannel - (Chnls (3) .GetController (7) - most of the time it returns the value 100 instead of the correct value.
I also checked controller 39 but it is at 0.

Do you have an idea?
 

Attachments

  • gh.png
    gh.png
    134.3 KB · Views: 524
  • 2009.zip
    2009.zip
    35.3 KB · Views: 438
Upvote 0
I found the solution. It's correct?

Code: Copy
    If LblTrack0.Text ="" Then
        Return
    End If
    canale = canale -1
    Dim tx As MidiTrack = Main.Seq.GetTracks(LblTrack0.text)
    For o = 0 To tx.Size - 1
        Dim Mevt As MidiEvent = tx.Get(o)
        If Mevt.GetMessage.IsShortMessage Then
            If canale = Mevt.GetMessage.AsShortMessage.GetChannel Then
                Dim sm As MidiShortMessage = Mevt.GetMessage.AsShortMessage
                If sm.GetCommand = MidiStatus.CONTROL_CHANGE Then
                    If sm.GetData1 = 7 Then
                        LblVol0.Text = sm.GetData2
                        SliderCh0.Value = sm.GetData2
                    End If
                End If
            End If
        End If
    Next
 
Upvote 0
But your library's GetController function returns an incorrect value. Can you please check it?
It just calls the getController method in the JavaxSound library.

B4X: Copy
'Obtains the current value of the specified controller.
Public Sub GetController(Controller As Int) As Int
    Return TJO.RunMethod("getController",Array As Object(Controller))
End Sub
'Obtains

I don't have a an app set up that I can test it on. If you have one I'll look at it.
 
Upvote 0
It just calls the getController method in the JavaxSound library.

B4X: Copy
'Obtains the current value of the specified controller.
Public Sub GetController(Controller As Int) As Int
    Return TJO.RunMethod("getController",Array As Object(Controller))
End Sub
'Obtains

I don't have a an app set up that I can test it on. If you have one I'll look at it.
I made a quick program and put you a foundation to test it. This base must be placed in c: \
 

Attachments

Upvote 0
OK, that is the expected result. Channel.getController method is a realtime method, which means that it will only return a meaningful value when the track is being played with a sequencer. It gets the current value of the controller at the current time in the track.

Controllers are continuous, there could be many thousands of messages for a given controller in a midi track. Consider a crescendo in the music. The controller will start at a small value, and rise, maybe every 50th of a second until the highest value is achieved.

To monitor this correctly you would normally use the event listener, but Channel.GetController gets a snapshot of the value when it is called.
 
Last edited:
Upvote 0
OK, that is the expected result. Channel.getController method is a realtime method, which means that it will only return a meaningful value when the track is being played with a sequencer. It gets the current value of the controller at the current time in the track.

Controllers are continuous, there could be many thousands of messages for a given controller in a midi track. Consider a crescendo in the music. The controller will start a small value, and rise, maybe every 50th of a second until the highest value is achieved.

To monitor this correctly you would normally use the event llistener, but Channel.GetController gets a snapshot of the value when it is called.
Thanks.
 
Upvote 0
Back
Top