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?
 

Luca1967

Active Member
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

Luca1967

Active Member
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

stevel05

Expert
Licensed User
Longtime User
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

Luca1967

Active Member
Ok. Function. :)

Change volume:
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

Luca1967

Active Member
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: 141
  • 2009.zip
    35.3 KB · Views: 150
Upvote 0

Luca1967

Active Member
I found the solution. It's correct?

B4J volume solution:
    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

stevel05

Expert
Licensed User
Longtime User
Without testing it, It looks OK to me.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
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:
'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

Luca1967

Active Member
It just calls the getController method in the JavaxSound library.

B4X:
'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

  • StevelTest.zip
    2.8 KB · Views: 155
  • temp.zip
    29.7 KB · Views: 151
Upvote 0

stevel05

Expert
Licensed User
Longtime User
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

Luca1967

Active Member
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
Top