Converting Program Changes to Prev/Next song

Description
I use an M-Audio Oxygen 61 as controller for going up/down in songs. However, the issue is that it sends out Program Change (PC) messages. It starts with 0, pressing the > button increases the value (so it sends PC 1, etc. When it goes beyond the number of songs in a Gig Performer set list, it keeps increasing, as it doesn’t know about the set list.

To make things worse, when you manually select a song, the current song changes, and pressing the < or > button on the Oxygen continues from where it sends it last program change.

Solution

So what is needed, is that the < and > buttons should not use direct program changes, but be converted into a Prev Song / Next Song action.

Thanks to @dhj I got the right points to implement this and this is shown in the remainder of this post.

The procedure is:

  • The Oxygen sends a PC message.

  • In the Gig script, the PC message is converted into a CC message and sent to the Oxygen61MidiIn residing in the global rackspace

  • The global rackspace receives this CC message and sets the Prev Song widget or Next Song widget.

  • These widgets are coupled to the system action, carrying out the actual Prev or Next Song system action.

  • The

Implementation

First in the wiring diagram of the global rackspace the following items need to be added:

In the global panel, two buttons need to be added: Prev Song and Next Song, connected to the system action and using parameter ‘Prev Song’ and ‘Next Song’.

In the GIG Script, the following code is placed:


var 
 Oxygen61 : MidiInDevice
 PrevPc : int = -1
 
On ProgramChangeEvent(m : ProgramChangeMessage) from Oxygen61
    var 
     current_pc : int = GetProgramChangeNumber(m)
     ccMessage : ControlChangeMessage
     up : boolean
    
    Print("On PC")
    Print("Prev PC  c = " + IntToString(PrevPc))
    Print("current_pc = " + IntToString(current_pc))

    if PrevPc != -1 then
        up = (PrevPc == 127 and current_pc == 0) or (PrevPc < current_pc and not (PrevPc == 0 and current_pc == 127))
        Print("Up = " + BoolToString(up))
            
        if up then
            Print("UP")
            ccMessage = MakeControlChangeMessage(111, 127)
        else
            Print("DOWN")
            ccMessage = MakeControlChangeMessage(110, 127)
        end
    end
    PrevPc = current_pc
    Print("Injecting")
    InjectMidiEvent("Oxygen 61", ccMessage)    
    Print("Injected. -----------------------")
End

The name of the MidiInDevice can be found in the Rig Manager:

(see last line). Note that no spaces are allowed, but you can rename it and all references are automatically changed (well done development team).

In the global rackspace script the following code is placed:

var 
 Oxygen61MidiIn : MidiInBlock
 PrevSongButton, NextSongButton : Widget
 
On ControlChangeEvent(m : ControlChangeMessage) from Oxygen61MidiIn
    var 
     current_cc : int = GetCCNumber(m)
     current_value : int = GetCCValue(m)

    Print("On CC")
    Print("Current cc = " + IntToString(current_cc))
    Print("Current value = " + IntToString(current_value))

    if current_cc == 110 and current_value == 127 then
        Print("Prev song")
        SetWidgetValue(PrevSongButton, 1.0)
    elsif current_cc == 111 and current_value == 127 then
        Print("Next song")
        SetWidgetValue(NextSongButton, 1.0)
    end
    Print("------------------------------------")
End

In the diagnostics window you can see what happens:

** Improvement **

When removing the print statements, also code can be compacted more resulting in the following scripts:

*** Gig Script***


var 
 Oxygen61 : MidiInDevice
 PrevPc : int = -1
 
On ProgramChangeEvent(m : ProgramChangeMessage) from Oxygen61
    var 
     current_pc : int = GetProgramChangeNumber(m)
     ccMessage : ControlChangeMessage
     up : boolean
    
    if PrevPc != -1 then
        up = (PrevPc == 127 and current_pc == 0) or (PrevPc < current_pc and not (PrevPc == 0 and current_pc == 127))
        ccMessage = MakeControlChangeMessage(if up then 111 else 110 end, 127)
    end
    PrevPc = current_pc
    InjectMidiEvent("Oxygen 61", ccMessage)    
End

Global Rackspace Script

var 
 Oxygen61MidiIn : MidiInBlock
 PrevSongButton, NextSongButton : Widget
 
On ControlChangeEvent(m : ControlChangeMessage) from Oxygen61MidiIn
    if GetCCValue(m) == 127 then
        SetWidgetValue(if GetCCNumber(m) == 110 then PrevSongButton else NextSongButton end, 1.0)
    end
End

Gig File
Below the gig file can be downloaded.
Do not forget to use your own controller for the MIDI In device.

ConvertPcToNextPrevSong.gig (245.4 KB)

Also see the related post Simple Song Selector

2 Likes