Scale Constrainer Script

Hi all,

I was looking the other day for a plugin that could constrain the midi notes to a key.
I didn’t find something that was useable.

So today I decided to write a script to do it.

The idea is that for a selected key only notes in that key should be playable.
I realise that this is quite limiting as not even dominant 7th chords are then possible.
However in the context that I play (in church) this is often not needed.
Being a bit clumsy I can sometimes accidentally catch an adjacent key or if I am playing a bit more spontaneously and it’s not one the easier keys, I might play a note out of scale and this is quite disturbing in a worship environment.

Therefore by having a facility where I can select the key to restrict the available notes works quite well.

I know some will say that I should just practise more and get better but nevertheless…

I used the ‘lanes’ from my previous post on Drone Player but I hope you get the idea…I have a button
for each key and when the scale button is pressed then the midi notes are filtered.

Here’s the script:

On NoteEvent (m : NoteMessage) From MidiInOMNI
var
  note: Integer
  LanePlaying: Integer
  
  
  //Print("LanePlaying=" + LanePlaying + "note=" + note + "C0=" + C0)
  
  if GetWidgetValue(ScaleBtn) == 1.0 then
    note = GetNoteNumber(m) % 12 + 24
    LanePlaying = GetLanePlaying()
    
    if LanePlaying == -1
      or 
      (
         (LanePlaying == 0 and // Key of C
          (note == C0 
        or note == D0 
        or note == E0 
        or note == F0 
        or note == G0 
        or note == A0 
        or note == B0))
      or (LanePlaying == 1 and // Key of C#
          (note == C#0
        or note == D#0 
        or note == F0 
        or note == F#0 
        or note == G#0
        or note == A#0 
        or note == C0))
      or (LanePlaying == 2 and // Key of D
          (note == D0 
        or note == E0 
        or note == F#0 
        or note == G0
        or note == A0 
        or note == B0 
        or note == C#0))
      or (LanePlaying == 3 and // Key of D#
          (note == D#0 
        or note == F0 
        or note == G0
        or note == G#0 
        or note == A#0 
        or note == C0 
        or note == D0))
      or (LanePlaying == 4 and // Key of E
          (note == E0 
        or note == F#0 
        or note == G#0 
        or note == A0 
        or note == B0 
        or note == C#0
        or note == D#0))
      or (LanePlaying == 5 and // Key of F
          (note == F0 
        or note == G0
        or note == A0 
        or note == A#0 
        or note == C0
        or note == D0 
        or note == E0))
      or (LanePlaying == 6 and // Key of F#
          (note == F#0 
        or note == G#0
        or note == A#0 
        or note == B0 
        or note == C#0
        or note == D#0 
        or note == F0))
      or (LanePlaying == 7 and // Key of G
          (note == G0
        or note == A0 
        or note == B0 
        or note == C0
        or note == D0 
        or note == E0 
        or note == F#0))
      or (LanePlaying == 8 and // Key of G#
          (note == G#0
        or note == A#0 
        or note == C0
        or note == C#0 
        or note == D#0 
        or note == F0 
        or note == G0))
      or (LanePlaying == 9 and // Key of A
          (note == A0 
        or note == B0
        or note == C#0
        or note == D0 
        or note == E0 
        or note == F#0 
        or note == G#0))
      or (LanePlaying == 10 and // Key of A#
          (note == A#0 
        or note == C0
        or note == D0 
        or note == D#0
        or note == F0 
        or note == G0
        or note == A0))
      or (LanePlaying == 11 and // Key of B
          (note == B0 
        or note == C#0
        or note == D#0 
        or note == E0
        or note == F#0 
        or note == G#0
        or note == A#0)))
      then  
        SendNow(MidiInOMNI, m)
    end
  else
    SendNow(MidiInOMNI, m)
  end
End
1 Like

Very nice…one suggestion. Instead of writing all those out as individual tests, consider writing something like this

if (LanePlaying == 0 and IndexOf([C0,D0,E0, F0,G0,A0,B0], n) > -1) or
     (LanePlaying == 1 and IndexOf([C#0,D#0,F0, F#0,G#0,A#0,C0], n) > -1)
     // more tests as needed
  then
      // Play the note
end 

where n is the note you’re looking for

Once more thanks for sharing :wink:

Im sure there are others VSTs, I do use this
https://frozenplain.com/product/obelisk/ (sometimes for creative ways with all my controllers…)

There’s also https://www.codefn42.com/cales/

Seems like your script is doing what you want, but may be worth looking at plugins for ideas if it’s something you’re going to use with any regularity.

I have a keyboard that does variations of this. (Novation SL MK3). I’ve never actually tried it, but I’ve heard people that love it. You can tell it to ignore “wrong” notes or automatically shift wrong notes to “right” notes. And you can set key, mode, whether you want the dominant 7ths available, blue notes available, etc.

I could see using it if I were doing real gigs. I could convince myself it’s the same as using safety equipment.

There is also a VST in the free PizMIDI plugin collection that does essentially the same thing.

I use this particular VST for the flute solo in Toto’s “Africa” to add a second part harmony in the key of B major. There is a small UI with the ability to turn on or off the notes you want/don’t want played.

You can download the PizMIDI VST zip files for Mac, Win32 and Win64 here: https://code.google.com/archive/p/pizmidi/downloads

Ooops, that is a foul :wink:

The “magic” of technology… :grinning:

I know, and tell you what - I do the same :wink:

This is the right way to do it :wink::

The stages we play are not that big …

I’m also playing the CS-80 brass part with my left hand while soloing with my right, so I’d have to grow another arm/hand… :stuck_out_tongue_winking_eye:

Who knows If you play like Greg Philinganes :stuck_out_tongue_winking_eye:

Look at the beginning of the video, this guy not only plays, he makes the show by the way it plays.

David Paich, Steve Porcaro and even Greg Philinganes in one single keyboardist, now I understand :+1: :stuck_out_tongue_winking_eye:

Impressive!

I thought I recognised him…it was from this keyscape demo:

1 Like

Yes, it is a really serious keyboardist and he’s got a fantastic career too.

Thanks!
I was thinking there must be a more elegant way.
I was thinking to use “in” like in pascal e.g. in [C0, D0, E0] etc. but I saw that in only worked with ranges.
This is much better.

One more thing…I was applying this to a MidiInBlock that has a transpose of +12 (I have two midi in blocks and when this one is active it adds an octave above) but the note that I get on the On NoteEvent for this block seems to be the note BEFORE its transposed and when I do SendNow I am sending the untransposed note.

I realised that I needed to get the transpose setting for the MidiInBlock and Transpose the note before using SendNow.

I was wrapping the previous code into a function and it ended up like this with the transpose handled:

Function SendIfInKey(MidiIn: MidiInBlock, m: NoteMessage, Key: Integer)
var
  note: Integer
  Steps: Integer
  NoteMsg: NoteMessage
  
  Steps = GetTransposeFromMidiInBlock(MidiIn)
  NoteMsg = Transpose(m, Steps)
  
  note = GetNoteNumber(NoteMsg) % 12 + 24
  
  If Key == -1 or InKey(Key, note) then
    SendNow(MidiIn, NoteMsg)
  end
end

Take a look at the

SendNowRespectingParameters

system function

That’s great thanks…just what I needed and respects other parameters also like key ranges.

Also, I realised while playing live with this that I should only be Filtering Note On messages :slight_smile:
I changed the key before releasing the notes and they were stuck. I had to bypass the plugin to stop them. I didn’t realise during the performance what the issue was but it soon dawned on me later.
So now I changed the script to use OnNoteOnEvent rather than OnNoteEvent.