Advanced Note Assignment (may require scripting)

I’m in the process of decomposing and programming the Manfred Mann version of “Blinded by the Light”. If you watch them play it live, the keys are significantly simpler than in the studio recording, but hey… that’s not good enough for me :slight_smile:.

I’ve been through this process with multiple incarnations of my rig over the last 15 years, but I’ve never had the power of GP at my fingertips. The one big difference I want to make is being able to play the organ and choir at the beginning of the transition into the first verse with a single hand. In the past, I’ve ‘cheated’ by simply doubling all the notes in the chords with organ and choir patches, but I’d really like to have the appropriate single note in the middle of each inverted chord play mono-phonically on the choir patch like it sounds on the original recording. Yes, I know this was two tracks in the studio, but hey, they didn’t have GP.

The red notes are the ones I want to play. I’ll be using Arturia B-3 V2 for the hammond and the stock ‘boys choir’ from Kontakt 5 for the sound engines. I’ve already though about just setting the Kontakt 5 sound to monophonic, however it doesn’t allow me to set priority to high note, nor would that work for the g minor second inversion or the f major second inversion as it would simply replay the Bb and the A instead of the G and the F notes.

If anyone can think of a way to do this (including a good script suggestion) I’m totally open to suggestions. I need my other hand free to mange all the other parts, or I’d simply use both hands.

Just so you know what I have available, I do have two expression pedals and two ‘hold/sustain’ pedals set up as widgets in my standard default rackspace template. It would be better to NOT have to use them, but they could be available if necessary.

thanks!

X

1 Like

I used to play that song live with a band — one of my favorites.

If you’re willing to play those chords with one finger rather than one hand, then you could use a GP Script to generate the actual notes and you could send the middle note to a different plugin :slight_smile:

I have not really done any scripting yet as I’ve been trying to see if I could do whatever I was wanting without scripting. That being said, would I create two midi inputs for the controller, then script just the one that was going to the organ to add the extra notes? How would you approach the scripting from an object-model perspective?

thanks!

X

Unfortunately, I’m not in a position to actually write user scripts, sorry. But conceptually you would use callbacks to detect the single note you’re playing and then the callback would send out the three notes, two of them to a MidiIn plugin associated with your hammond and the other one to a MidiIn plugin associated with your choir.

Having said that, if I was doing this live, I wouldn’t use scripting at all. Instead I’d play the chords and the two MidiIn blocks would have velocity ranges set so that if the velocity was under some value, then the Organ MidiIn block would pass it through, otherwise the ChoirMidiIn block would pass it through.

You could try this script, just give your MidiInBlock the Handle MIN
(just quick and dirty)

var MIN : MidiInBlock

on NoteEvent(m : NoteMessage) matching A#2 from MIN
    SendNow(MIN, m)
    SendNow(MIN, m.Transpose(4))
    SendNow(MIN, m.Transpose(-5))
end

on NoteEvent(m : NoteMessage) matching A2 from MIN
    SendNow(MIN, m)
    SendNow(MIN, m.Transpose(3))
    SendNow(MIN, m.Transpose(-5))
end

on NoteEvent(m : NoteMessage) matching G2 from MIN
    SendNow(MIN, m)
    SendNow(MIN, m.Transpose(4))
    SendNow(MIN, m.Transpose(-5))
end

on NoteEvent(m : NoteMessage) matching F2 from MIN
    SendNow(MIN, m)
    SendNow(MIN, m.Transpose(4))
    SendNow(MIN, m.Transpose(-5))
end
1 Like

@pianopaul, thanks for the hints here. I really wasn’t expecting anyone to actually write the script, but rather just point me in the right direction :smile:

Question though: Being as this is just note events VS some type of note on events, this will handle both the note on and note off so I don’t end up with any dangling sustained notes, correct?

thanks!

X

Testing it is the simplest way to find out :wink:

The theory why this works is:
The NoteEvent callback is called on NoteOn as well as NoteOff events. So the three MIDI messages are sent out as keys are pressed as well as let go. And because nothing but the pitch is changed, the appropriate NoteOn/NoteOff messages are passed, so you shouldn’t get any stuck notes :smiley:

Note that if you use scripting, you’ll need TWO MidiIn Blocks, one for the Organ, the other for the Choir.

@dhj
You are right, for this use case the script should be like this:

    var MIN : MidiInBlock
        MCHOIR : MidiInBlock

    on NoteEvent(m : NoteMessage) matching A#2 from MIN
        SendNow(MIN, m)
        SendNow(MCHOIR, m)
        SendNow(MCHOIR, m.Transpose(4))
        SendNow(MCHOIR, m.Transpose(-5))
    end

    on NoteEvent(m : NoteMessage) matching A2 from MIN
        SendNow(MIN, m)
        SendNow(MCHOIR, m)
        SendNow(MCHOIR, m.Transpose(3))
        SendNow(MCHOIR, m.Transpose(-5))
    end

    on NoteEvent(m : NoteMessage) matching G2 from MIN
        SendNow(MIN, m)
        SendNow(MCHOIR, m)
        SendNow(MCHOIR, m.Transpose(4))
        SendNow(MCHOIR, m.Transpose(-5))
    end

    on NoteEvent(m : NoteMessage) matching F2 from MIN
        SendNow(MIN, m)
        SendNow(MCHOIR, m)
        SendNow(MCHOIR, m.Transpose(4))
        SendNow(MCHOIR, m.Transpose(-5))
    end

Why is this extension of the script necessary? Can’t you just use the first script with MIN going to the organ and another independent MIDI In block feeding the monophonic choir?

This is just 1 solution of many possibilities.
The same can be done in use with many MidiIn Plugins and Range and Transpose Transpose.
Or you could use some special plugins like CTHULHU.

1 Like

Of course :smile:

@pianopaul,

Thanks for the script. I was able to use this with only one small modification and get the general desired result. I did go with the approach of two midi in blocks, one for the choir, one for the organ. The ONLY true downside effect is as follows: Since the first chord and the last chord share a note, if you even ‘barely’ overlap the last note and first note, and you release the F after note-on for the Bb, it releases the F note from the Bb chord. I just have to be a little less sloppy than usual to make sure this doesn’t happen.

Thanks again to everyone for their replies!

X

Not to say that you should play sloppy :smiley: But for fun, I implemented a script which does not retrigger notes that are supposed to be held if you play the “trigger” notes legato:

Var ChordTrigger: MidiInBlock
    currentNote, previousNote, NO_NOTE : Integer

// For any single "trigger" note, returns an array of notes which
// should be played when the trigger note is played.
Function GetChord(triggerNote: Integer) Returns Integer array
Var emptyArray : Integer array
    ClearArray(emptyArray)
    
    Select
        triggerNote == NO_NOTE Do
            result = emptyArray
            
        triggerNote == Bb2 Do
            result = [F2, Bb2, D3]
        
        triggerNote == A2 Do
            result = [E2, A2, C3]
            
        triggerNote == G2 Do
            result = [D2, G2, Bb2]
        
        triggerNote == F2 Do
            result = [C2, F2, A2]
        
        // All other notes: Just play the trigger Note
        true Do
            result = [triggerNote]
    End
End

// returns true if element is in container, false otherwise
Function Contains(container: Integer array, element: Integer) Returns Boolean
Var i: Integer
    contained : Boolean
    
    contained = false    
    For i = 0; i < container.Size(); i = i + 1 Do
        If container[i] == element Then
            contained = true
        End
    End
    result = contained
End

// returns an array containing all the elements of a which are not included in b
Function Without(a: Integer array, b: Integer array) Returns Integer array
Var difference: Integer array
    i: Integer

    ClearArray(difference)
    For i = 0; i < a.Size(); i = i + 1 Do
        If !b.Contains(a[i]) Then
            difference.AppendInteger(a[i])
        End
    End
    result = difference
End

// Trigger the notes defined by GetChord() which are not(!) currently active
// and kill all the notes from the previous chord which are not in the current
// one.
// lastNoteOff means "the last (trigger) note was just let go". So if this is
// set to true, all the notes in the previous chord get killed.
Function TriggerNotesLegato(m: NoteMessage, lastNoteOff: Boolean)
Var notesCurrent, notesPrevious: Integer array
    notesOn, notesOff: Integer array
    i: Integer
    
    previousNote = currentNote
    If lastNoteOff Then
        currentNote = NO_NOTE
    Else
        currentNote = m.GetNoteNumber()
    End
    
    notesPrevious = GetChord(previousNote)
    notesCurrent = GetChord(currentNote)
    
    notesOff = notesPrevious.Without(notesCurrent)
    notesOn = notesCurrent.Without(notesPrevious)

    For i = 0; i < notesOff.Size(); i = i + 1 Do
        SendNow(ChordTrigger, WithNoteNumber(m.ReinterpretAsNoteOffMessage(), notesOff[i]))
    End
    
    For i = 0; i < notesOn.Size(); i = i + 1 Do
        SendNow(ChordTrigger, WithNoteNumber(m.ReinterpretAsNoteOnMessage(), notesOn[i]))
    End
    
End
    

Initialization
    NO_NOTE = -1 // quasi a constant
    
    currentNote = NO_NOTE
    previousNote = NO_NOTE
    
End

On NoteOnEvent(m: NoteMessage) From ChordTrigger
    TriggerNotesLegato(m, false)
End

On NoteOffEvent(m: NoteMessage) From ChordTrigger
    If m.GetNoteNumber() == currentNote Then
        TriggerNotesLegato(m, true)
    End
End

1 Like

@xpansion, with @pianopaul and @simon around, don’t tell that your not a happy keyboardist :wink:

1 Like