AutoSustainer and Chord Recognition with GP Script

Here’s a YouTube video I just uploaded showing how GPScript can be used to implement an AutoSustainer to sustain notes automatically until you release all keys AND then start playing a new chord. It’s an approach that I’ve depended on for years with several bands and had previously implemented it using the ‘borax’ objects in MaxMSP. Now it can be done natively.

There’s also an example of a chord recognizer and you can see chord names being displayed as I play the chords on a keyboard.

The script in this video also shows the syntax for writing functions. This stuff is all implemented and will be available in the next beta.

Happy new year to you all.

Since the version 2.4 we have the object “AutoSustainer”. Please can someone post an example code with this new object?

Pretty easy :slight_smile:

var MasterKeyboard : MidiInBlock
    AutoSustain    : AutoSustainer

Initialization
    AutoSustain.AutoSustainer_SetTarget(MasterKeyboard)
End

On NoteEvent(m : NoteMessage) from MasterKeyboard
    AutoSustain.AutoSustainer_Play(m)
End

On PitchBendEvent(m : PitchBendMessage) from MasterKeyboard
    AutoSustain.AutoSustainer_Stop()
End

Requires a MidiInBlock with the script name ‘MasterKeyboard’. Routing is just as if there were no scripting involved at all. Touching the PitchBend wheel stops all pending chord. Remove this callback if you don’t need it.

The only problem I see is when using a different MIDI channel than 1. What happens is that NoteOn events will be on channel (say) 5, but the NoteOff events are sent on channel 1. I guess that the AutoSustainer makes use of the NoteTracker internally which does not save the MIDI channel of incoming NoteOn events.

I’m looking at the best way to address that MIDI channel stuff for AutoSustainer.

Perfect! Thank you for your quick anwser. I tried to find a way that it works also with all the settings (velocity, key- and velocitysplit) from the MidiInBlock.

Here is my result:

var MasterKeyboard : MidiInBlock
	AutoSustain    : AutoSustainer
	AUTOSUSTAIN_ON_OFF : Widget
Initialization
	AutoSustain.AutoSustainer_SetTarget(MasterKeyboard)
End

On NoteEvent (m : NoteMessage) from MasterKeyboard
	var blockfilter : boolean
	var velo : integer
	velo = m.GetVelocity()
	blockfilter = false
	if (m.IsNoteOn()) then
		// Block all notes lower than MIN note from the MidiBlock settings
		if (GetNoteNumber(m) < MasterKeyboard.GetMinNoteFromMidiInBlock()) then blockfilter = true end
		// Block all notes higher than MAN note from the MidiBlock settings
		if (GetNoteNumber(m) > MasterKeyboard.GetMaxNoteFromMidiInBlock()) then blockfilter = true end
		// Block all notes lower than Min Velocity from the MidiBlock settings
		if (velo < ParamToMidi(MasterKeyboard.GetParameter(150)) && velo > 0) then blockfilter = true end
		// Block all notes higher than Man Velocity from the MidiBlock settings
		if (velo > ParamToMidi(MasterKeyboard.GetParameter(151))) then blockfilter = true end
	end
	if (blockfilter == false) then
		if (m.IsNoteOn()) then
			if (MasterKeyboard.GetParameter(154)==1) then
				// Calculate the new veloctiy when the MidiBlock setting is Constrain
				if (velo < ParamToMidi(MasterKeyboard.GetParameter(152))) then velo = ParamToMidi(MasterKeyboard.GetParameter(152)) end
				if (velo > ParamToMidi(MasterKeyboard.GetParameter(153))) then velo = ParamToMidi(MasterKeyboard.GetParameter(153)) end
			else
				// Calculate the new veloctiy when the MidiBlock setting is Scale
				velo = (Round(Scale (velo, 0, 127, ParamToMidi(MasterKeyboard.GetParameter(152)), ParamToMidi(MasterKeyboard.GetParameter(153)))))
			end
		end
		if (GetWidgetValue(AUTOSUSTAIN_ON_OFF) > 0) then
			// Sending out the notes with the new veloctiy and transpose setting from MidiBlock over AutoSustain
			AutoSustain.AutoSustainer_Play(Transpose(WithVelocity(m,velo),MasterKeyboard.GetTransposeFromMidiInBlock()))
		else
			// Sending out the notes with the new veloctiy and transpose setting from MidiBlock without AutoSustain
			MasterKeyboard.SendNow(Transpose(WithVelocity(m,velo),MasterKeyboard.GetTransposeFromMidiInBlock()))
		end
	end
End

AutoSustainer works beautifully! It’s now part of my standard rackspace, merged with my metronome volume script. I can turn the sustain on and off using a button on my Livid DS-1 controller.

Using the Autosustain Script from LeeHarvey which is absolutly great and works very well.
However, in my case when using this script the overall GP tranpose does not work any more, which I would still need.
Another (minor) thing is that after approx 3min holding the key, the sound starts to get deteriorated.
Any idea, especially for the overall transpose?

Hi @MojoBass and welcome around GP “world”

Well, not much info from you to elaborate some advice (what plugin are you using, what computer, audio interface, it´s settings (sample rate/buffer size)

I’ll have a play with AutoSustainer to remember things…

Hello @keyman,
Thank you for your feedback!
Here the infos on my setup:
Plugins: Chordz, CollaB3
Keys: Studiologic MP-113
Interface: Steinberg UR22C
Dell Inspiron 7580 i7 32GB RAM, Win10
ASIO 44,1kHz, 512 Samples

Thanks for your effort in advance!!

That’s either a plugin issue or your system has a wordclock sync issue. The only thing autosuststain does is hold up NoteOff messages

OK, thank you very much for your feedback. I will try to circle the problem by stepwise changing my setup.
Any idea for the overall GP transpose function?

Global Transpose: Try this

var MIN : MidiInBlock
    AutoSustain    : AutoSustainer
    tr : Integer

on NoteEvent(m:NoteMessage) from MIN

 if IsNoteOn(m) then
  tr = GetGlobalTranspose()  
  AutoSustain.AutoSustainer_Play(Transpose(m, tr))
 end
end 

initialization
 AutoSustainer_SetTarget(AutoSustain, MIN)
end

Hello @pianopaul,
thanks for the feedack and the script. My understanding was to use it instead of the original script from @LeeHarvey. However, the new script seems not to stop any tones, which was a feature of LeeHarveys script and which is mandatory for me.
But maybe there is a misunderstanding: is your script ment only as starting point for my own programming to include the features of LeeHaeveys script? Or should I add your scripting to the orignal script somehow?
Sorry for still being new to GP scripting…

This script should only show how the global transpose can be used.

OK I will try to include that into my setup.

Thanks @pianopaul for ideas…

Sorry @MojoBass, a bit too much on my “plate” right now; I like scripts added functionalities, but I’m not that “fluent” so to speak.

Keep asking its a growing and vibrant GP community :wink:

2 Likes