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 .
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.
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
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?
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
@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
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?
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
@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.
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.
Not to say that you should play sloppy 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