Michel Keijzers - Template Rackspace

(PART ONE)

Introduction

This article is about a template rackspace I’m intending to use for all songs (rackspaces) I will create with Gig Performer. Mainly, it is a script to be included in all rackspace, taking care of a panel with mixer volumes, hammond drawbars (when applicable), expression pedal functionality and later more.

This post mentions who I am and the bands I play in, and all background and information what the script does, the second post (first reply) explain the (initial) version of the script and the third post (second reply) is a copy of the script itself).

Who am I?

I am Michel Keijzers, 51 years old (young?) from the Netherlands, and playing keyboards in bands for more than 30 years, non professionally. I have played in around 5 or 6 bands in my lifetime, mostly rock cover bands, one was more a party band, the others mainly rock.

I think I have a quite broad music style, although it is mostly within rock (ranging from ballads to symphonic/progressive rock).

My profession is software engineer (at Cap Gemini, working for ASML the last decades mostly), and in my free time I developed a Windows application for managing sounds file for Korg workstations. This is called PCG Tools, see http://pcgtools.mkspace.nl if you are interested (probably most are not, as we use GigPerformer and typically less hardware synthesizers).

Bands

I play in two rock cover bands, called Co-Incidental and Hoax. Both bands are hobby rock-cover bands, and we play locally in bars and small festivals.

The funny thing is that half of the band members between the bands are the same (drummer, bass guitarist, one guitarist, and the keyboardist which is myself).The reason was that not all band members in one band liked certain songs, so those songs we converted to the second band.

We don’t really have any good demo (as the best way to get gigs is just visit bars), so it will be a phone recorded video , and some audio fragments from Hoax. Note that in these recordings I do not use GigPerformer as they were before I changed. Also, since there are no upcoming gigs this year, I cannot post any GigPerformer demo, but I will post some pictures of my current setup in the rehearsal room.

In both bands we try not to play only the obvious songs. Also, we sometimes play covers from cover bands, and when there are no obvious keyboard parts, or when I don’t like the original ones, I have the freedom to play whatever I feel sounds ok.

Below are some screenshots from the songs we play in each band.

Hoax:

image

Co-Incidental:

And here are some direct mixer outputs from the last gig of Hoax (with the singer of Co-Incidental joined):

https://soundcloud.com/user-870312333/bounce1?in=user-870312333/sets/gig_direct_mixer_output/
https://soundcloud.com/user-870312333/bounce2?in=user-870312333/sets/gig_direct_mixer_output/
https://soundcloud.com/user-870312333/bounce3?in=user-870312333/sets/gig_direct_mixer_output/

And an unfinished demo of phone recordings of Hoax:

The above all were made before I used GigPerformer, but below is a picture of my current GigPerformer setup (Laptop, M-Audio Oxygen 61 MK5, StudioLogic Acuna 88, Ipad, Behringer FCB1010 MIDI foot pedal, IPad).

The nice blue light is from a DMX light we use in the rehearsal room (static light, but colored).

Facebook pages:

Co-Incidental: https://www.facebook.com/search/top?q=co-incidental
Hoax: Redirecting...

Previous Rig

During the last years (except the first 5) I always have used Korg synthesizers/workstations (Korg X5, N264, Triton Extreme, M50,Kronos). Typically I used two keyboards at the same time, the last two versions.

During the last 5 years I started using a StudioLogic Acuna 88 master keyboard which I used together with my Kronos.

Also, for around 10 years or more, I use a Behringer FCB1010 MIDI foot pedal board, with 10 switches (typically I use 4 or 5), and two expression pedals.

Current Rig

As the Korg Kronos is discontinued, the only alternative when my Kronos would break down (it’s more than 10 years old but still working, but for how long?), is a second hand Kronos which price is very expensive due to the discontinuation, or the Nautilus, which is a stripped down version of Korg they call now the ‘flagship’.

I also use an IPad for my inear monitoring application (Visi Listen for the Soundcraft Expressoin SI 2).

This is the main reason I moved from Korg to a VST/Plugin setup with GigPerformer.

I decided to keep using my StudioLogic Acuna 88 and my Behringer FCB1010, but I like to have faders/knobs and pads, and I bought an M-Audio Oxygen 61. Not the best keybed, but for piano parts I use the Acuna 88, and the Oxygen 61 so far works fine. Actually, I bought two, so I have one at home and one at the rehearsal room.

Also, I needed an audio interface. As I had a Behringer UMC404HD interface which worked great when I used it mostly as a ‘mixer’, I bought a smaller one (2 inputs) to be used for my new laptop, and one extra for the rehearsal room. However, it turned out, pops and crackles were unavoidable when the CPU reached over 50%, so after trying a FocusRite I bought two of them (2i4, as I needed a MIDI input for my Behringer FCB1010).

As a laptop, I bought a second hand (like the audio interfaces and M-Audio keybed controllers) Windows 10, Core I7 laptop which I first blamed for the pops/crackles, but ‘luckily’ it was my audio interface. Since GigPerformer uses quite some memory, I upgraded it to 32 GB and now it works fine. Also, I bought an external 1 TB SSD as the internal SSD was only 256 GB.

Regarding software plugins, I decided to buy NI Komplete 13, which I don’t regret so far. It has a lot of sounds, although I also checked out some free VST plugins, where some also are very usable, so I will use a combination of NI Komplete and free VST’s. Maybe at a later point, I will buy others, but as I’m new, I didn’t want to spend too much.

Below is a bare schematic of my setup:

1 TB SSD
   |
   v 
Windows
 Laptop  ->  USB hub <- M-Audio Oxygen 61
  I7             |
    |            +-------  StudioLogic Acuna 88
    v
 Audio Interface
 FocusRite 2i4
      ^
Behringer FCB1010
MIDI Foot Pedal board

Challange

The first two months, I tried to get to know a lot about GigPerformer, but also about learning NI Komplete, VSTs in general, finding solutions for my pops/clicks etc.

Now I have a setup that works, and have done several rehearsals (some were a bit annoying as I reprogrammed my FCB1010 and due to a mistake I had some problems with not able to use the volume controls).

Since I come from Korg/hardware synthesizers, I still like to keep some features I used in my new rig, which are:

  1. Being able to use the expression pedals for volume, the left one for the volume of the upper keyboard, and the right for the lower keyboard
  2. Using two foot switches for the modulation (this is still some kind of work to do) of the upper and lower keyboard. I prefer not having to keep my hands from the keyboards at some cases.
  3. Using two foot switches for sustain and/or changing the Hammond leslie speed.
    4.Using the faders for the Hammond drawbars
  4. Using the faders for volume control (I had 16 channels on the Korg, but since I have 9 faders now, I think 8 for each channel and one for the total volume seems logical).
  5. Using two knobs on the Oxygen to change the volume as well for the upper and lower keyboard (these tend to be a bit more precise and in some cases I cannot use the volume as I have two feet only, when having to press a foot pedal AND an expression pedal I probably fall over/down/left/right).
  6. Instead of the volume, I sometimes like to use Cutoff as volume as it nicely makes the volume softer.
  7. I want the Hammond drawbars to be invisible when there is no Hammond needed, and also I don’t want to see volume sliders of channels I don’t use.
  8. I like to have a more smart Audio Mixer plugin, which automatically mutes the unused channels. Preferably also to have the label automatically update, and not able to move the volume (keep it at 0).
  9. I want to have the above features in all of my patches as ‘template’.

The reason I want the sliders for volume, is to be able to change the balance in the rehearsal room, typically at home it sounds good, but at the rehearsal room I want to make changes on the fly (unless it takes too much time too program per son).

Initial idea

Initially, I only wanted just to have the drawbars and some basic controls necessary for a song. I thought the volume mixer would be too much work as it is only used during programming mainly and once the song is balanced, I don’t need the volume mixer. However, I think even after that it could be useful to be able to move the volumes separately.

Idea 2

Since I have a Korg nanoKONTROL2 MIDI fader controller, I thought I would use that for the volume mixer, but since Korg has its own drivers which do not automatically reconnect after an accidental ‘plugout’, the using the Korg nanoKONTROL2 is kind too dangerous to use. Buying another device would add to the cost obviously.

Idea 3

So I asked a question here at the Community about switching faders and got almost instantly a result (see: Switching widget functionality - General discussion about Gig Performer - Gig Performer Community).

So the remainder of this post is about how I used that as basis for my Audio Mixer/Hammond setup and related items.

Earlier Wiring

When I first started using GigPerformer, I thought it would be nice to make the routing in a hierarchical way, see below for an example

I use a lot of keyboard splitting and stacking, and the convention I use is to place stacked sound below each other (see e.g. the 2 green String Ensemble and Session String plugins), and from left to right the upper and lower keyboard, and splits from left to right.

There are mixers for balancing the stacked sounds, the upper and lower keyboard and the total. Inside the global rackspace is another audio mixer for the expression pedals (as this should not affect the balancing of the sounds, it’s only used for fade in/out etc).

However, the above idea would be hard to be programmed into a mixer, as there will be too many plugins involved, so I decided to go for a single mixer approach.

Example Single Mixer Approach

I have only used it for a few songs yet to try out, and below is one example, Walk from the Foo Fighters.

In the remainder of this article, this song/rackspace will be used.

Wiring Diagram

In this song, I use on the upper keyboard a Hammond sound, and on the lower left a piano sound, and on the right a synth sound, which is a stack of two separate sounds.

As you can see I like to rename the plugin (green blocks) with the actual names of the presets (sometimes I add also the plugin type, e.g. Kontrol or MassiveX, but for the time being I use not too many different/exotic sounds, that will come later, maybe).

When there is a rackspace, not using a Hammond, still it needs to be added, otherwise the script cannot find the Hammond plugin, for this an unused unconnected Hammond plugin is used:

image

Audio Mixers

As you can see, I use two audio mixers, 16 channels, 2 x 8 stereo, one mixer for the actual balance (Faders) and one for the expression pedal. My Behringer FCB1010 has 2 pedals, I use one for the upper keyboard and one for the lower keyboard.

Audio Mixer Faders

Below is the inside of the Audio Mixer Faders. It controls the balances between the used plugins, and I typically the 4 left faders for the upper keyboard and the 4 right faders for the lower keyboard. I also like to name them like the plugins, and set unused faders to 0 and mute them. In the panel later, I want these 8 faders to be controlled by the first 8 faders of my upper keyboard, an M-Audio Oxygen 61.

Note that I only connect further the ports of used channels and set each channel to its corresponding output (i.e. fader 1 to output 1/2, fader 8 to output 15/16).

Audio Mixer Expression Pedals

See below a picture. This is used for the expression pedals of my Behringer, controlling the volume, such as fade in/outs. I also have programmed a button to take a snapshot, but for that, I need to manually make sure to put the expression pedals both up when making a snapshot otherwise the balance would be affected (and stored). I want these always stored as 127 for used plugins and 0 for unused plugins. Maybe later, I will try to automatically set these to 127 when saving.

In the panel I will make sure the expression pedals will connect to the right faders.
Also, there I like to use two knobs on my upper keyboard (M-Audio Oxygen 61) which serve the same purpose.

This is looking very much like the previous audio mixer, except that all outputs will go to output 1/2.

Panels

Below are the panels, the first containing of a label strip with some comments (empty in this example), and a chords box where a small script is putting text on it in a hardcoded way.

The second panel is the fader/mixer panel plus some expression pedal functionality.

When pressing a button on my M-Audio Oxygen (button 2), the panel toggles to show the volume mixer.

Pressing the button again toggles between the two screens, but only when there is a Hammond sound in the rackspace.

Only faders shown from channels being used are shown.

I use a convention of three colors:

  • Red: upper keyboard
  • Blue: Lower keyboard
  • Green: Total Volume

Typically, the first four sliders are used for the upper keyboard, and four for the lower keyboard. However, when there are more sounds used for the upper or lower keyboard, semi-automatically the red/blue screens will grow/shrink.

Chords panel

This shows chords or other notes. I use the following script for that (which is mixed with the audio mixer script, but below I just paste the portion used for this panel:

var
   ChordsWidget : Widget
   ChordsText : String = <<<
   Intro:  A   A   A   A
  VERSE:   A   E   F#m     D   Dm
  Verse   Chorus    A  ... E ... F#m   F#m   D   Dm   
  Verse   Chorus 3x
  >>>

initialization
   SetWidgetLabel(ChordsWidget, ChordsText)
end

Depending on the size, I then resize the chords widget so it is as big as possible, without clipping text.

Fader/Mixer Panel

This is the most complicated part, and I used mostly the helpful information from other members, see Switching widget functionality - General discussion about Gig Performer - Gig Performer Community

The left part contains of the sliders and faders for the audio mixer and drawbars for the hammond, see the edit part below

I use 4 layers:

  • Faders for the audio mixer
  • Three boxes for the audio mixer, red for the upper keyboard, blue for the lower keyboard and green for the main volume (connected to the Gain of the Gain/Balance Total widget).
  • Sliders for the drawbars, I also added some basic functions for the hammond, like a led showing the rotor speed, a speed switch, and a drive (overdrive) knob.
  • One box which is red or blue, mostly red, as the upper keyboard is typically used for Hammond

However, the problem with these layers, is that it is very hard to select the correct item on the panel, for this I also probably will make some feature requests (like selecting an item from a list or something). I tried using the ‘send back’ or ‘send to back’ but the boxes need to be behind the sliders/faders otherwise the result looks bad, and only items on the top can be selected for editing. So, I decided to automatically format/rearrange the widgets.

For these items, the MIDI connection is not made, as instead the CC values will be used. In a script the CC numbers from the 9 faders of my M-Audio Oxygen are connected. The same applies for the Hammond drawbars.

The mapping to plugins will be for the Hammond very easy: just the upper drawbars. The only downside is that I have to do this for every copy of this panel. It would be nice if it would be automatically coupled to the Hammond plugin (maybe when a panel is copy/pasted it should remember the connections and when pasted in a rackspace with a plugin with the same name, the connections should be made automatically. This would be a huge help). However, I managed to automatically connect the CC values and send them to the Hammond plugin using the script.

For the audio volume sliders, I mostly connect them to the audio mixer Faders, but for some sounds it’s better to connect it to the cutoff or I could cheat and place an equality with a high gain (maybe I should find for some cutoff filter, as a plugin somehow). In my script, I can override the volume faders.

The 9th fader is used for the Gain/Balance Total (see wiring diagram), to set the main volume of the rackspace, to be able to balance volumes between songs easier.

** Expression Pedals part**

This part defines expression pedals, which are mapped to all used sliders to set the volume of the upper/lower keyboard.

I made it in such a way, that when the expression pedal is down, besides changing the overridden functionality, the volume also is brought to 0 (and put up to 127 when the expression pedal is not down). This way a sound will be always silent when the expression pedal is down.

The same applies for the two buttons also serving as volume (knobs 4 and 8 on my M-Audio Oxygen 61).

Scripts

I use two scripts, one is the template script, which is placed in the Documents folder, and should be included in every song. Then, there is a script per rackspace/song, which contains overrides and some settings which I could not gather automatically with GScript functions.

Steps to copy the panel to another rackspace

To copy a panel from one rackspace to another in the same gig file, and make it work, take the following steps:

  • Copy the rackspace specific rackspace script and adjust the variable items (e.g. chords, used channels for upper/lower keyboard, hammond presence) and adjust the values if needed.
  • Make various plugins gscript accessible:
    • Hammond plugin with name ‘HammondPlugin’ , if there is no hammond, still make this plugin, but set it into bypass
    • Keyboard controller (with the sliders/knobs) with name ‘MidiInOxygen61’
    • Audio mixer used for balancing with name ‘AudioMixerFadersPlugin’
    • Audio mixer used for the expression pedals with name AudioMixerExprPedalsPlugin’

Rackscript example

Below is the script for the song ‘Walk’. I will place comments above each fragment.

When a volume slider needs to override the default volume slider from the audio mixer, e.g. to change the Cutoff frequency instead, below the plugin blocks are added.

var
   PolyPad2Plugin     : PluginBlock
   DirtySawLeadPlugin : PluginBlock

This function returns the text to be placed on the Chords widget. When finished, manually adapt the font size.

function GetChordsText() returns string
  result =
    <<<
    Intro:  A   A   A   A
    VERSE:   A   E   F#m     D   Dm  !1
    Verse   Chorus    A  ... E ... F#m   F#m   D   Dm   
    Verse   Chorus 3x 
    >>>  
end

This function is very easy: when a Hammond sound is used in the song, return true, otherwise return false. This function will be called in the template script, as other functions below.

function IsHammondPresent() returns boolean
   result = true
end

This function returns the channels which are used for the upper keyboard, in our case only 1: channel 1.

function GetEnabledUpperAudioMixerChannels() returns string
   result = "1"   
end

This function returns the channels which are used for the lower keyboard, which are channels 5, 6 and 7.

function GetEnabledLowerAudioMixerChannels() returns string
   result = "567"
end

For two sounds (channels 6 and 7), the synth sounds will use the cutoff frequence to be brought down instead of a harsh volume control, so here is shown how they can be overridden. Find the parameter by counting it inside GigPerformer using a temporary widget to find the index.

function OverrideSlider(sliderNumber : integer, sliderValue : integer) 
 returns boolean
   var
      NI_RETRO_MACHINES_MK2_CUTOFF_PARAMETER_INDEX : integer = 0

      overridden : boolean = false
      
   select sliderNumber == 6 do 
      SetParameter(DirtySawLeadPlugin, 
       NI_RETRO_MACHINES_MK2_CUTOFF_PARAMETER_INDEX, MidiToParam(sliderValue))
      overridden = true
   end
   
   select sliderNumber == 7 do 
      SetParameter(PolyPad2Plugin, 
       NI_RETRO_MACHINES_MK2_CUTOFF_PARAMETER_INDEX, MidiToParam(sliderValue))
      overridden = true
   end
   
   result = overridden
end

This include statement reads the script that uses the function above and makes sure all items mentioned in the challenges are addressed.

Include "rackspace_template.gpscript"

(as there is a limit of characters, the second part is in the reply).

5 Likes

(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

(reserved for future updates).

1 Like

Wow, when we first talked about this I didn’t know that this will end up this good :beers:

2 Likes

Some preview for the next update already: A ‘SLOW’/‘FAST’ rotator speed text instead of the LED and sustain pedal:

image

image

1 Like

Good stuff! And very nice to see a ‘normal life’ colleague in this forum :slight_smile:

3 Likes

Thank you for the compliment.

A small update, I’m converting this rackspace to a global rackspace, so I don’t have anything into the local rackspace, except for plugins that are really specific for that song (using rackspace to songs 1:1).

For this I found a way to store the widget values/settings from the global rackspace for each song, and a way to setup the non changeable values per (global) rackspace. Like a default value per rackspace but for the global rackspace.

It will still take some time to have something completely working, but the proof of concept works :slight_smile:

In a few weeks I hope to come with a bigger update.

2 Likes

Wow! Thx!