Michel Keijzers - Template Rackspace

(PART TWO, continuation of the main post, as there is a body limit of 32000 characters)

Template script

Below is the entire template script, chopped up in pieces for more explanation.

Feel free to use my script as you like. Also, if you have improvements or questions, feel free to ask.

/*
   Created by Michel Keijzers
	v1.0
*/

Below are all ‘global variables’ which I use, the first part constants (in capitals as by convention), the others normal global variables. I also used as many constants as possible, to make it easier for you to adapt the script to your needs.

Due to the spaces/tabs, the alignment is sometimes a big awkward.

Var
   SLIDER_CC_START : integer = 81 // CC of first slider on the Oxygen 61,
											 // consecutive
   NR_OF_SLIDERS   : integer =  9 // Number of physical sliders on the 
											 // Oxygen 61
   NR_OF_AUDIO_MIXER_CHANNELS : integer = 8   // Number of audio mixer channels
   PANEL_TOGGLE_ON_VALUE      : double  = 0.6 // On value for hammond/audio 
															 // mixer toggle

Use here the CC values from your Hammond plugin.

   HAMMOND_PLUGIN_UPPER_DRAWBARS_PARAMETER_START : integer = 20 // 16' Upper,
	                                           // 5 1/3' Upper, 8' Upper etc.

These are the parameter numbers from the GigPerformer Audio Mixer plugin. I wish there was also a parameter for the label strip of each channel.

   AUDIO_MIXER_PARAMETERS        : integer = 7
   AUDIO_MIXER_VOLUME_PARAMETER  : integer = 0
   AUDIO_MIXER_BALANCE_PARAMETER : integer = 1
   AUDIO_MIXER_SOLO_PARAMETER    : integer = 2
   AUDIO_MIXER_MUTE_PARAMETER    : integer = 3
   AUDIO_MIXER_OUTPUT_PARAMETER  : integer = 4	

Various plugins I use which are affected by my script.

   MidiInOxygen61 : MidiInBlock
	MidiInFcb1010 : MidiInBlock
	
   HammondPlugin : PluginBlock
   AudioMixerFadersPlugin: PluginBlock
   AudioMixerExprPedalsPlugin: PluginBlock
   GainAndBalanceTotalPlugin: PluginBlock

All Hammond widgets I use.

   HammondBox: widget
   RotatorSpeedLed, RotatorSpeedSustainPedal, DriveKnob: widget
   Drawbar1, Drawbar2, Drawbar3, Drawbar4, Drawbar5, Drawbar6, Drawbar7,
 	 Drawbar8, Drawbar9: widget

These are the widgets for the sliders part of the audio mixer.

   Keyboard61MixerBox, Keyboard88MixerBox, MainMixerBox: widget
   Slider1, Slider2, Slider3, Slider4, Slider5, Slider6, Slider7, Slider8, 
	 Slider9: widget

And here the array for the Hammond widgets.

   HammondArray : widget array = 
	[
      Drawbar1, Drawbar2, Drawbar3, Drawbar4, Drawbar5, Drawbar6, Drawbar7, 
		Drawbar8, Drawbar9,
      HammondBox, RotatorSpeedLed, RotatorSpeedSustainPedal, DriveKnob
   ]

And the widgets and array for the expression pedals.

	ExpressionPedal1, ExpressionPedal2, ExpressionPedal3, ExpressionPedal4,
	 ExpressionPedal5, ExpressionPedal6, ExpressionPedal7, ExpressionPedal8,
	 ExpressionPedalUpperBox, ExpressionPedalLowerBox: widget

   ExpressionPedalArray : widget array = 
	[
	   ExpressionPedal1, ExpressionPedal2, ExpressionPedal3, ExpressionPedal4,
	   ExpressionPedal5, ExpressionPedal6, ExpressionPedal7, ExpressionPedal8
	]
  
  	VolumeKnob1,  VolumeKnob2, VolumeKnob3, VolumeKnob4,
	 VolumeKnob5, VolumeKnob6, VolumeKnob7, VolumeKnob8 : widget

The volume knobs are used for the same function as the expression pedals.

   VolumeKnobArray : widget array = 
	[
	  	VolumeKnob1, VolumeKnob2, VolumeKnob3, VolumeKnob4,
		VolumeKnob5, VolumeKnob6, VolumeKnob7, VolumeKnob8
	]
	
   MixerArray : widget array = 
	[
      Slider1, Slider2, Slider3, Slider4, Slider5, Slider6, Slider7, Slider8, 
		Slider9,
      Keyboard61MixerBox, Keyboard88MixerBox, MainMixerBox
   ]
  
   PanelToggle  : widget // Toggles between Hammond widgets and volume sliders
	                      // widgets
   ChordsWidget : widget // Shows Chords in the Chords panel (unrelated to the
	                      // mixer)

This function shows or hides a group of widgets, which is typically the Hammond widgets array or the Audio mixer widgets array to be toggled.

function ShowWidgets(group : widget array, show : boolean)
   var index : integer
   
   for index = 0; index < Size(group); index = index + 1 do
      SetWidgetHideOnPresentation(group[index], !show)
   end
end

This function returns the enabled channels concatenated, in my example for this song and defined in the rackspace script for the song, e.g. in this case “1” for the upper keyboard and “567” for the lower keyboard, resulting in “1567”.

function GetEnabledChannels() returns string
		result = TrimString(GetEnabledUpperAudioMixerChannels()) +
               TrimString(GetEnabledLowerAudioMixerChannels())
end

This functions shows or hides the audio mixer faders, based on which channels are enabled in the user script. The second part is for the gain slider and the three boxes.

function ShowUsedMixerChannels()
   var 
		enabledChannels : string = GetEnabledChannels()
		enabledChannel : integer
		index : integer
   
   for index = 0; index < Length(enabledChannels); index = index + 1 do
      enabledChannel = StringToInt(CopySubstring(enabledChannels, index, 1))
     	if enabledChannel >= 1 and 
		   enabledChannel <= NR_OF_AUDIO_MIXER_CHANNELS then
	      SetWidgetHideOnPresentation(MixerArray[enabledChannel - 1], false)
      end  
   end
   
   for index = NR_OF_AUDIO_MIXER_CHANNELS; index < Size(MixerArray);
	 index = index + 1 do
	   SetWidgetHideOnPresentation(MixerArray[index], false)
   end
end

This function toggles between the Hammond and audio mixer widgets.

function PanelToggleValueChanged(panelToggleValue : double)
   if panelToggleValue > PANEL_TOGGLE_ON_VALUE then
      ShowWidgets(HammondArray, true)
	   ShowWidgets(MixerArray, false)
   else
      ShowWidgets(HammondArray, false)
	   ShowWidgets(MixerArray, false)
	   ShowUsedMixerChannels()
   end
end

This function moves the Hammond or audio mixer fader depending on which one is active.

function MoveFader(
 index : integer, ccNumber_unused : integer, ccValue : integer)
   if IsHammondPresent() and
	   GetWidgetValue(PanelToggle) > PANEL_TOGGLE_ON_VALUE then
      SetWidgetValue(HammondArray[index], MidiToParam(ccValue))
   else
      SetWidgetValue(MixerArray[index], MidiToParam(ccValue))
   end
end

Returns the lowest channel number, which typically is the first character of the string, but to not make this assumption, the string is iterated. Typically, the argument is the lower keyboard string, in the song defined as “567”, resulting in the 4th channel.

function GetLowestChannel(enabledChannels: string) returns integer
   var 
		lowestChannel : integer = NR_OF_AUDIO_MIXER_CHANNELS + 1
		enabledChannel : integer
		index : integer

	for index = 0; index < Length(enabledChannels); index = index + 1 do
	   enabledChannel = StringToInt(CopySubstring(enabledChannels, index, 1))
      lowestChannel = Round(Min(lowestChannel, enabledChannel))
   end
	
   result = lowestChannel
end

Draws the widgets for the Hammond drawbars. As the other Hammond related widgets do not change, I decided not to ‘redraw’ them.

function DrawDrawbars()
   var index : integer
	
   for index = 0; index < NR_OF_SLIDERS; index = index + 1 do
      SetWidgetBounds(HammondArray[index], [5 + 43 * index, 5, 50, 370])
   end
	
	SetWidgetBounds(HammondBox, [0, 0, 480, 380])
	// RotatorSpeedLed, RotatorSpeedSustainPedal, DriveKnob
end

Draws the faders.

function DrawSliders(lowestLowerChannel: integer)
   var
		index : integer
		width : integer = 53
   
	for index = 0; index < NR_OF_SLIDERS; index = index + 1 do
      SetWidgetBounds(MixerArray[index], [width * index, 10, width, 370])
   end
	
	SetWidgetBounds(Keyboard61MixerBox, 
	 [ 0, 0, width * (lowestLowerChannel - 1), 380 ])
	SetWidgetBounds(Keyboard88MixerBox, 
	 [ width * (lowestLowerChannel - 1), 0, 
	   width * (9 - lowestLowerChannel), 380])
   SetWidgetBounds(MainMixerBox, [ width * 8, 0, width, 380 ])
end

This function formats the audio mixer widgets.

function FormatAudioMixerWidgets(lowestLowerChannel : integer)
	DrawDrawbars()
	DrawSliders(lowestLowerChannel)
end

This parameter enables an audio mixer channel, by unmuting it, or disabling by muting it, setting the volume to 0, resetting the balance knob and the solo button.
I wish, I also could change the channel strip label, but there is no parameter for this.

function EnableChannel(plugin: PluginBlock, index : integer, enable : boolean)		
	var parameterOffset : integer
	
	parameterOffset = AUDIO_MIXER_PARAMETERS * (index - 1)
	
	if (enable) then
   	SetParameter(plugin, parameterOffset + AUDIO_MIXER_MUTE_PARAMETER, 0)
	else
   	SetParameter(plugin, parameterOffset + AUDIO_MIXER_VOLUME_PARAMETER, 0)
		SetParameter(plugin, parameterOffset + AUDIO_MIXER_BALANCE_PARAMETER, 
		 0.5)
		SetParameter(plugin, parameterOffset + AUDIO_MIXER_MUTE_PARAMETER, 1)
		SetParameter(plugin, parameterOffset + AUDIO_MIXER_SOLO_PARAMETER, 0)
		// There is no parameter for the label of each channel
	end
end

This function disables the unused audio mixer channels.

function DisableUnusedMixerChannels()
   var
   	enabledChannels : string = GetEnabledChannels()
		enabledChannel  : integer
		enable          : boolean
		index           : integer   

   for index = 1; index <= NR_OF_AUDIO_MIXER_CHANNELS; index = index + 1 do
	   enable = IndexOfSubstring(
		 enabledChannels, IntToString(index), false) >= 0
		EnableChannel(AudioMixerFadersPlugin    , index, enable)
		EnableChannel(AudioMixerExprPedalsPlugin, index, enable)
   end
end

This function formats the expresson pedal and knobs widgets for the volume.
The expression pedals/knobs are assigned to each of the audio mixer sliders.
Only two expression pedals are shown, the first for the upper keyboard, and the first for the lower keyboard (depending which is the first active audio mixer channel).
The other expression pedal widgets are drawn in small on the right margin, and the knobs are drawn in small left of the corresponding expression pedals.

function FormatExpressionPedalWidgets(lowestLowerChannel : integer)
   var
	 	EDGE_MARGIN 							 : integer =    5
	
   	LEFT_MARGIN_MAIN_EXPRESSION_PEDAL : integer =  980
		LEFT_MARGIN_MAIN_VOLUME_KNOB 		 : integer =  
		                                    LEFT_MARGIN_MAIN_EXPRESSION_PEDAL -
														20
		WIDTH_MAIN 								 : integer =  120
		HEIGHT_BOX  							 : integer =  190
		HEIGHT_MAIN 							 : integer =  
		                                    HEIGHT_BOX - 2 * EDGE_MARGIN
		
		LEFT_MARGIN_EXPRESSION_PEDAL 		 : integer = 1050
		LEFT_MARGIN_VOLUME_KNOB 			 : integer = 
		                                    LEFT_MARGIN_EXPRESSION_PEDAL - 30
		WIDTH_OTHERS  							 : integer =   30
		HEIGHT_OTHERS  					    : integer = WIDTH_OTHERS
		
	
		index : integer
	
   for index = 0; index < NR_OF_SLIDERS - 1; index = index + 1 do
	   if index == 0 then
         SetWidgetBounds(ExpressionPedalArray[index], 
			 [ LEFT_MARGIN_MAIN_EXPRESSION_PEDAL, EDGE_MARGIN, 
			   WIDTH_MAIN, HEIGHT_MAIN ])
			SetWidgetBounds(VolumeKnobArray[index], 
			 [ LEFT_MARGIN_MAIN_VOLUME_KNOB, EDGE_MARGIN, 
			   WIDTH_OTHERS, HEIGHT_OTHERS ])
			SetWidgetHideOnPresentation(ExpressionPedalArray[index], false)  
  		elsif index == lowestLowerChannel - 1 then
		   SetWidgetBounds(ExpressionPedalArray[index], 
			 [ LEFT_MARGIN_MAIN_EXPRESSION_PEDAL, HEIGHT_BOX + EDGE_MARGIN, 
			   WIDTH_MAIN, HEIGHT_MAIN ])
			SetWidgetBounds(VolumeKnobArray[index], 
		    [ LEFT_MARGIN_MAIN_VOLUME_KNOB, HEIGHT_BOX, 
			   WIDTH_OTHERS, HEIGHT_OTHERS ])
			SetWidgetHideOnPresentation(ExpressionPedalArray[index], false)
		elsif index < lowestLowerChannel then
         SetWidgetBounds(ExpressionPedalArray[index], 
		    [ LEFT_MARGIN_EXPRESSION_PEDAL, 
			   HEIGHT_BOX / lowestLowerChannel * (index - 1),
 			   WIDTH_OTHERS, HEIGHT_OTHERS ])
			SetWidgetBounds(VolumeKnobArray[index],
			 [ LEFT_MARGIN_VOLUME_KNOB,
  			   HEIGHT_BOX / lowestLowerChannel * (index - 1), 
			   WIDTH_OTHERS, HEIGHT_OTHERS ])
			SetWidgetHideOnPresentation(ExpressionPedalArray[index], true)
		else
		   SetWidgetBounds(ExpressionPedalArray[index], 
		    [ LEFT_MARGIN_EXPRESSION_PEDAL,
 			   HEIGHT_BOX + (HEIGHT_BOX - EDGE_MARGIN) / 
				 (NR_OF_AUDIO_MIXER_CHANNELS - lowestLowerChannel + 1) * 
				 (index - lowestLowerChannel), 
			   WIDTH_OTHERS, HEIGHT_OTHERS ])
		   SetWidgetBounds(VolumeKnobArray[index], 
		    [ LEFT_MARGIN_VOLUME_KNOB, 
			   HEIGHT_BOX + (HEIGHT_BOX - EDGE_MARGIN) / 
				 (NR_OF_AUDIO_MIXER_CHANNELS - lowestLowerChannel + 1) * 
				 (index - lowestLowerChannel), 
				WIDTH_OTHERS, HEIGHT_OTHERS ])
		   SetWidgetHideOnPresentation(ExpressionPedalArray[index], true)
		end
		
    	SetWidgetHideOnPresentation(VolumeKnobArray[index], true)
   end

   SetWidgetBounds(ExpressionPedalUpperBox, 
	 [ LEFT_MARGIN_MAIN_VOLUME_KNOB, 0, WIDTH_MAIN, HEIGHT_BOX ])
   SetWidgetBounds(ExpressionPedalLowerBox, 
	 [ LEFT_MARGIN_MAIN_VOLUME_KNOB, HEIGHT_BOX, WIDTH_MAIN, HEIGHT_BOX ])
end

This is the initialization function of the script, which handles the toggle value, mapping the hammond widgets to the Hammond plugin, mapping the audio mixer sliders to the audio mixer plugin, setting the Chords widget, and formatting the layout of most of the widgets.

initialization
   var 
		initialPanelToggleValue : double = 0.0
		index : integer
		lowestLowerChannel : integer
	
	for index = 0; index < NR_OF_SLIDERS; index = index + 1 do
      MapWidgetToPlugin(HammondArray[index], HammondPlugin, 
       HAMMOND_PLUGIN_UPPER_DRAWBARS_PARAMETER_START + index)
   end
   
   for index = 0; index < NR_OF_SLIDERS - 1; index = index + 1 do
      MapWidgetToPlugin(MixerArray[index], 
		 AudioMixerFadersPlugin, 
       AUDIO_MIXER_PARAMETERS * index + AUDIO_MIXER_VOLUME_PARAMETER)
		MapWidgetToPlugin(ExpressionPedalArray[index],
 		 AudioMixerExprPedalsPlugin,
		 AUDIO_MIXER_PARAMETERS * index + AUDIO_MIXER_VOLUME_PARAMETER)
   end
 
   MapWidgetToPlugin(Slider9, GainAndBalanceTotalPlugin, 0)
  
   if IsHammondPresent() then
      initialPanelToggleValue = 1.0
   end
	
   PanelToggleValueChanged(initialPanelToggleValue)
   SetWidgetValue(PanelToggle, initialPanelToggleValue)
   SetWidgetLabel(ChordsWidget, GetChordsText())
	
	lowestLowerChannel = GetLowestChannel(GetEnabledLowerAudioMixerChannels())
   FormatAudioMixerWidgets(lowestLowerChannel)
	DisableUnusedMixerChannels()
	
	FormatExpressionPedalWidgets(lowestLowerChannel)
end

This function sets the audio mixer slider when an incoming CC event is received. In case the functionality is overridden, it is calling the user script function, otherwise the volume control will be used. To make sure when the expression pedal of the FCB1010 is down, that the volume is off, it is automatically set to 0 when under a certain threshold value, and set to max volume when the expression is not down, so the overridden functionality is active.

function SetAudioMixerSlider(
 firstSlider : integer, lastSlider : integer, ccValue: integer)
   var
	   FCB1010_FULL_DOWN_RANGE   : integer = 10 // FCB1010 expression pedal is 
		                                         // not so exact
		MIDI_VALUE_NO_VOLUME      : integer = 0
		MIDI_VALUE_MAX_VALUE      : integer = 127
		AUDIO_CHANNEL_NOT_MUTED   : integer = 0
		
		index                     : integer
	   parameterOffset           : integer
		isOverridden              : boolean
		
	for index = firstSlider; index < lastSlider; index = index + 1 do
		parameterOffset = AUDIO_MIXER_PARAMETERS * index
		if GetParameter(AudioMixerFadersPlugin, 
		 parameterOffset + AUDIO_MIXER_MUTE_PARAMETER) == 
		 AUDIO_CHANNEL_NOT_MUTED then
			isOverridden = OverrideSlider(index + 1, ccValue)				
			if isOverridden == true then
				if ccValue <= FCB1010_FULL_DOWN_RANGE then
					SetWidgetValue(ExpressionPedalArray[ index ], 
					 MidiToParam(MIDI_VALUE_NO_VOLUME))
				else
					SetWidgetValue(ExpressionPedalArray[ index ], 
					 MidiToParam(MIDI_VALUE_MAX_VALUE))
				end
			else
				SetWidgetValue(ExpressionPedalArray[ index ], 
				 MidiToParam(ccValue))
			end
		end
	end
end

This function process incoming CC events from the Oxygen 61. There are four cases:

  • A slider is changed on the Oxygen 61, this results in a change of a Hammond drawbar or audio mixer

  • Knob 4 is changed, resulting in changing the upper keyboard audio mixer volumes

  • Knob 8 is changed, resulting in changing the lower keyboard audio mixer volumes

  • Else, the CC is forwarded as normal

    on ControlChangeEvent(ccMsg : ControlChangeMessage) from MidiInOxygen61
    var
    OXYGEN61_KNOB_4_CC_NUMBER : integer = 93
    OXYGEN61_KNOB_8_CC_NUMBER : integer = 97

      	ccNumber           : integer = GetCCNumber(ccMsg)
      	ccValue            : integer = GetCCValue(ccMsg)
        lowestLowerChannel : integer = GetLowestChannel(
      	                      GetEnabledLowerAudioMixerChannels())
      
     if ccNumber >= SLIDER_CC_START and 
         ccNumber < SLIDER_CC_START + NR_OF_SLIDERS then
        MoveFader(ccNumber - SLIDER_CC_START, ccNumber, ccValue)
     elsif ccNumber == OXYGEN61_KNOB_4_CC_NUMBER then
         SetAudioMixerSlider(0, lowestLowerChannel - 1, ccValue)
     elsif ccNumber == OXYGEN61_KNOB_8_CC_NUMBER then
         SetAudioMixerSlider(lowestLowerChannel - 1, NR_OF_SLIDERS - 1, ccValue)
     else
        SendNow(MidiInOxygen61, MakeControlChangeMessage(ccNumber, ccValue))
      end
    

    end

This function process the Behringer FCB1010 CC messages. The left pedal is set to CC 94, and the right pedal to CC 95. As with the knobs, the upper audio mixer volumes are changed (in case of CC 94), the lower audio mixer volumes are changed (in case of CC 95), or the CC message is processed normally.

on ControlChangeEvent(ccMessage : ControlChangeMessage) from MidiInFcb1010
	var
	   FCB1010_LEFT_EXPRESSION_PEDAL_CC_NUMBER  : integer = 94
		FCB1010_RIGHT_EXPRESSOIN_PEDAL_CC_NUMBER : integer = 95
		
		ccNumber 			 : integer = GetCCNumber(ccMessage)
		ccValue 			    : integer = GetCCValue(ccMessage)
      lowestLowerChannel : integer = GetLowestChannel(
		                      GetEnabledLowerAudioMixerChannels())
	
   if ccNumber == FCB1010_LEFT_EXPRESSION_PEDAL_CC_NUMBER then
	   SetAudioMixerSlider(0, lowestLowerChannel - 1, ccValue)
   elsif ccNumber == FCB1010_RIGHT_EXPRESSOIN_PEDAL_CC_NUMBER then
	   SetAudioMixerSlider(lowestLowerChannel - 1, NR_OF_SLIDERS - 1, ccValue)
   else
      SendNow(MidiInFcb1010, MakeControlChangeMessage(ccNumber, ccValue))
	end
end

This function is called when Switch 2 of the Oxygen 61 is pressed and results in toggling the Hammond faders and the Audio Mixer faders, depending if there is a Hammond present.

on WidgetValueChanged(panelToggleValue : double) from PanelToggle
   if IsHammondPresent() then
      PanelToggleValueChanged(panelToggleValue)
   end
end

Gig File and Script

See Rackspace Template

Future ideas

  • Also making it possible to switch between the two modes (drawbar/volume faders) with a foot switch on my Behringer.
  • In general: a way to copy this script to ALL rackspaces, with as less possible time to spend on changes.

Script adaptability

In case you want to use the entire script, you probably need to change some things:

  • I’m using the Native Instruments Vintage Organ (Kontakt) library, change the CC numbers for your Hammond plugin
  • I’m using an M-Audio Oxygen 61, where you like want to use your own CCs for the sliders and toggling between the panels
  • I’m using a Behringer FCB1010 midi foot controller, where you want to use your own CCs for the MIDI fool pedals.
  • My laptop has high likely different screen dimensions, so the coordinates also have to be changed.

However, the article is more intended to give ideas and copy parts from which you think are useful.

5 Likes