What do you want to see in a scripting language?

While development started on GPScript quite some time ago, many of the features were based on the kinds of things that I want to be able to do.

However, I’ve never needed to do such things as chord analysis, something that Lukas suggested, and I realized that some extra mechanism will be required to do such things, or at least to do them more easily.

So this is probably a good time to collect a list of the kinds of things one might imagine being able to do with a built-in programming language.

So post your thoughts about the kinds of things you’d like to be able to accomplish so we can discuss.

I would like to get the current song position in bars and Beats and Show it in a widget.

1 Like

And trigger Audio Player at specific bar/beat

1 Like

I had a electro pop project some years ago that needed lots of arpeggiator stuff going on while playing pad sounds and melodies at the same time (of course with one single keyboard player). I didn’t want to just have the arpeggio play the same chord tones I play with my left hand over 4 octaves. I wanted to decide which notes the arpeggio should contain if I play a maj7, m7b5/m6 or a diminished chord in my left hand. That’s one of the use cases for my “chord analysis” idea. I got this to work by writing a script for MainStage that kept the chord qualities and the melody structures in an array containing JSON objects (or - shame on me - associative array… I don’t remember if the MainStage/Logic understands this object notation):

arpNotes.push({ chordType: ‘dim7’, notes: ‘c f d# g# f# b a d2’});
arpNotes.push({ chordType: ‘sus4’, notes: ‘c d f e a g’});
[…]
chordTypes.push({ chordType: ‘major’, notes: ‘c e g’ });
chordTypes.push({ chordType: ‘dim7’, notes: ‘c d# f# a’ });
chordTypes.push({ chordType: ‘aug’, notes: ‘c e g#’ });
[…]

Everything written in C major and the script transposed it appropriately. Very nerdy, I know, and again more quick than elegant :wink:

Of course I can’t say if many people will need this, but I think it would be useful if we could somehow recognise the currently playing chord with GPScript and make decision out of that. Or if the current chord contains some specific notes…

I have normally managed chord recognition by keeping intervals rather than explicit notes. In GPScript you can write something like

var
major : integer array
minor : integer array
majorSeventh : integer array

initialization
major = [1, 5, 8]
minor = [1, 4, 8]
majorSeventh = [1,4,8,12]
end

You could then use a FOR loop and the SendLater function inside a NoteEvent callback to generate arpeggios.

However, it seems to me that the kind of thing you’re trying to do can better be done with MIDI plugins that can do arpeggios, something like Sugar Bytes Thesys or BlueARP (BlueARP – arpeggiator / pattern sequencer – Developer's homepage. Get the latest version here.). I’m not saying that it couldn’t be done by writing scripts but writing scripts just seems like a very hard way to do something that might easily be accomplished with plugins.

So far, (and this could certainly change), I’ve been aiming to use GPScript to do things that are NOT really feasible with plugins, for example to control widgets which then control parameters. So for example, in a normal synth, you can generally only apply keyboard follow to the filter cutoff. But if you use a note value to control a widget position or a specific plugin parameter, then you could use keyboard follow to control anything.

Similarly, there is a notion of a function generator, which includes an ADSR function. So you can use that to apply ADSR to ANY parameter of a plugin, e.g.

Here’s a little movie I just put together to demonstrate this.

Note - this is an unlisted video, please do not share.

And here’s the script I used

var
   env : ADSR;    // An LFO function generator - yeah just a single period :-)
   Detune : Widget // A widget with the script name Detune which I have associated
                   // with the Detune parameter in FM8

Initialization
   

   env.SetADSRAttackLevel(0.5)  // Half way
   env.SetADSRAttackTime(500)   // 500 milliseconds
   env.EnableLFO(true)
   StartTimers();

End

on Activate
   StartTimers();
End

On Deactivate
   StopTimers()
End

var
   SL88 : MidiInBlock   // This is my keyboard

On NoteOnEvent(m : NoteMessage) from SL88
var
   n : integer

   n = m.GetNoteNumber()

   // Set the value of the Detune widget by scaling the keyboard range into a desired range
   Detune.SetWidgetValue(Scale(n, 0, 127, 0.3, 0.7))

   SL88.SendNow(m)  // If we don't include this, the note won't get sent

   env.StartAttackPhase()  // Trigger the ADSR
end

On NoteOffEvent(m : NoteMessage) from SL88
   env.StartReleasePhase()  // Switch to the release phase of the ADSR
   SL88.SendNow(m)  // If you don't include this you will get stuck notes
end

var
   EnvFollow : Widget  // We'll control this widget with the ADSR

// Called by ADSR as time passes. Y is the current value of the ADSR
On TimePassing(millisecondsPassed : int, y : double) from env
   EnvFollow.SetWidgetValue(y)

End

Cool, very nice idea! Thanks for the script.

One more thing I can think of is automated filter sweeps: Set an rough song tempo for the current Rackspace, play one chord and let the filter cutoff (widget value) open automatically within 2 or 4 bars. I guess that could be done pretty easily using timers?

Sure – although as well as the ADSR, there is a RAMP and SQUARE generator already available – I’ll be adding others over time.

There is also a general timer callback and, as @pianoman already mentioned, there will soon be a callback for beats

Hi David,how may I be able to convert scripts from MainStage 3 to compile correctly in GP? I think those scripts are Java based.
Thank you for your kind assistance.

I have not looked at Mainstage scripting but that image looks like they’re Javascript (which is completely different than Java, despite the name).

What you’re trying to do in the script should be pretty trivial with GP Script. I refer you to the online draft language manual (http://gigperformer.com/downloads/GPScript/LanguageManual.pdf) and the current list of system functions (http://gigperformer.com/downloads/GPScript/SystemFunctionList.html). The script editor itself has some some templates for the various callbacks. Once you have a sense for the syntax, you will probably want to look at the SendNow, SendLater and Transpose functions.

For example, if you have a MIDI In block with a GP Script name of Keyboard, then

Var
   Keyboard : MidiInBlock

On NoteEvent(m : NoteMessage) from Keyboard
    SendNow(Keyboard, m)
    SendLater(Keyboard, Transpose(m, 12), 100)
End

will do exactly what your Mainstage script is doing. Note that there’s no need to check that the message is a note because for the OnNoteEvent callback, it will ALWAYS be a note.

I regret however that we cannot provide hands-on training or support for GP scripting

Hi David, Community,
Possibility to define an array of references, e.g. to note events,
or to other arrays, or structures, would help.

Then it could be possible to route the input of the stream
of notes to different Midi channels, think Autodivisi, Chords to Different Monophonic instruments, dependant of the timing
of the note’s arrival, the note numbers (Voice Number of chord) , in Combination with CC or pitch Messages Messages,
sent by Breath controller ect…

Maybe referencing, sorting, note events,…, is already possible with help of The NoteTracker object?
Unfortunately I could not find enough information about it yet. :slight_smile:

Arrays of note events are causing unexpected errors,…, that would help a lot!
Could you give some tips, or links,… please ?

Thanks in advance,
Peter

Hi David, Nebojsa,
thank you for this script language!
It is really fun to program. My experience with MainStage was, I hated Java script.

I got around problem not to be able to use Note-event-Arrays,

  • although it would be helpful sometimes, also add more elements to the structure of an element of an array.

  • It would be nice to have the possibility to use something like Macros to enable/disable
    debug( True/false) related Commands (prints ect…) instead of using “if then…” or “select” which still uses the processor when debug related code is deactivated.

  • Constant definitions without the need to use variables, set to a constant value in the
    “On activate” or “initialization” Routine would be nice.

  • A function call to close the LogWindow, and a Function to close the editor window, would be nice, Some shortcuts for the editor, maybe also search-function/shortcut could make coding easier.

  • Shortcuts for saving Scripter Code, or Code in active Editor Tab.

  • Activate the code in an different TAB often caused loss of code in the beginning.

  • To be Sure often save of code would be nicer with some Intelligent Shortcuts, undo or whatever…

But the scripting it really already very Nice to use :slight_smile: (still learning)
Unfortunately I didn’t find out how to edit my last post,…

Peter

Thanks for your feedback. GP Script is still a work in progress and we’re still exploring what can be done with it. There will be a GP Script V2 at some point which will address some of the drawbacks of the initial version. The array stuff will certainly get addressed.

To answer some of your other points:

  1. There will never be macros. As a friend of mine who also did research on programming languages/compilers said one, “Macros are a sign of a badly designed language”. At some point however, we will probably add a compiler option that will cause it to ignore the “print” statement (or perhaps a separate “Log” statement) during compilation but the amount of “processor” time being used for an if…then test is hardly impacting the code and worrying about that probably comes under the guise of “premature optimization”
  2. Constant definitions are on the list already
  3. CloseLogWindow will be in the next update (just added it now - that was an easy one)
  4. I’m not convinced a function to close the script editor window is a good idea.
  5. Yes, more editing (find/replace) would be nice — but since one can just copy/paste the text into a “real” editor and back, it’s kinda low priority
  6. “Shortcuts for saving Scripter Code” — not sure what you mean by this - the script code gets saved with the rackspace when you save the gigfile

Keep those suggestions coming.

Thank you,
< 6) “Shortcuts for saving Scripter Code” — not sure what you mean by this – the script code gets saved with the rackspace when you save the gigfile
Keep those suggestions coming.

When working in the script editor, there were some commands,
you often have to use, to prevent code loss after possible crash.
(fortunately crash did not happen to me yet)
could be partly automated or made easier:

  • saving the script file to a file (shortcut or automatically when starting compilation)
  • eventually even a shortcut for the compile command.

I know, these would be just luxury, not necessary. :slight_smile:

Peter

In general I would like to use scripting to enhance my live performances, particularly where I have not yet found a plug-in to do what I need. Examples:

  1. Tap Tempo for Live Performance. Every Tap Tempo that I have tried is hyper sensitive and not useful for live performance because I can tap a tempo for two measures and if my last tap came a bit too soon or too late, then the tempo changes dramatically. For live performances I want a tap tempo that averages my last 8 (or so) taps. I am OK if it slowly adapts to tempo changes because in a live band that is not playing to a click the tempo tends to drift but not make drastic jumps. If I miss a tap it would recognize that my next tap was still in synch and it would not immediately halve the tempo. If a plug-in exists I’d buy it, but if not maybe I can script it? (Or Gig Performer can offer that!) This would finally allow me to use an arp or other pulsing sounds.

  2. I would like to implement several LFOs and multi-step envelopes to control many parameters of my plug-ins to create movement. These could be tied to widgets so the widgets move according to timing that I set up.

  3. A simple keyboard latch. Press a note or chord and it holds, press a different chord and it releases the old and holds the new, press the same chord and it releases it. Others have done this but I don’t have a good plug-in for this. Omnisphere’s latch is buggy for me.

  4. I use a chord trigger a lot to play one part and trigger other keyboard parts as I go. Suppose I play a C2, that triggers a C4 and G4 on MIDI Channel 1 and a C3 and C4 on MIDI Channel 2. One note can trigger multiple different chords on different instruments. I am currently using midiChords by Insert Piz Here and I can strongly recommend it. What I cannot do today is to trigger a part that moves at a different speed as what I am playing. I would be interested to experiment with being able to trigger parts that move with the beat (quarters or eights, etc.) even if I am playing a different rhythm. I can see experimenting with scripts to create more interesting parts that I can trigger to pull off sounds that normally come from multiple keyboard players.

  1. Have you tried our tap tempo? I use it myself in performances. There’s a Tap() function in GPScript as well
  2. Yeah, we’ve got this concept of function generators in GPScript but they’re harder to use than I would like. Having said that, I recently discovered MidiShaper from cableguys.com and you can set up all this stuff with that plugin, so I put the function generator stuff at lower priority
  3. I actually have code to do AutoSustain, what you describe is something I’ve been using for years, I originally implemented this with MaxMSP but I have some GP Script code that does it as well. I’ve been meaning to turn that code into a GPScript object though, but haven’t had time yet. I’ll publish the code I have (will require modification) but I should make an AutoSustain Object available
  4. Yeah, that’s an interesting one… watch this space :slight_smile:
  1. Yes, I have tried the GP tap tempo and I see it vary by plus or minus 7 bpm even when I am focused on hitting the trigger in time with a different metronome that I have. That is too wide a swing to pull off an arp or a pulse. To improve I would humbly request that you look at the last 8 (or so) taps – while any one tap might be slightly off, the average of my last 8 taps will be very close to the correct bpm. I would be happy if the tempo did not change until I had hit at least 4 taps, but keep track of the last 8 and use them to improve the accuracy.
  • Also, when tapping during a live performance, stuff happens and occasionally I will miss a tap. I humbly request that your timing logic anticipate such a miss, and if the next tap falls in the expected timeframe then don’t assume the tempo dropped in half, assume instead that I missed a tap!
  1. Thank you for the tip – I now own MidiShaper – a great use of $29!

  2. Back in the dark MainStage days I implemented that using their JavaScript tool. Seems generally useful for keyboard players and so possibly something that you want to make available as an object.

  3. Intrigued!

I always have to end with a big Thank You for creating Gig Performer - it is THE best tool for performances. It’s hard work but I especially appreciate your focus on stability – the single most important measure for a live performance tool. I also appreciate that it is CPU-friendly. I can pull off significantly more layers of virtual instruments in Gig Performer relative to Ableton Live. That makes it possible for me to do what I do!

Sincerely,
Rob

Hmm, I have not experienced that problem with tap tempo. We are using a pretty decent auto-correlation algorithm that should do a decent job with slight variations (although not if you miss a beat). I’ll have to revisit the algorithm to see if we can expose parameters such as number of beats.

Thanks for the MidiShaper tip! Will check out this one tomorrow. Very interesting.

  1. I did the same in my Main Stage days. And I recently did the same in GPScript using the NoteTracker object. Here is a example rackspace with chord hold functionality. Just one Midi In Block and one instrument. I extended the whole thing so that you can touch the pitch bend wheel to stop the currently sustained chord. Alternatively you can define a single key or a key range that will do the same thing. The modulation wheel decides if Chord Hold is active (values <= 64 -> on, values > 64 -> off). Very useful if you don’t need the Chord Hold function all the time.

http://jazzundso.de/Chord-Hold-Advanced.gig

If you need the pitch bend or mod wheel for different things, just change it to your needs. Have fun :wink:

  1. I need quite similar things and I also use Piz / midiChords for that. Sending different chords on different MIDI CHs to different instruments is pretty easy. But what you describe at the end is way more interesting. What I always wanted to implement is a MIDI player that recognizes the tempo you play and triggers a phrase synchronously that matches to the part you play. One idea to make this work is to have two tracks in the MIDI file: One guide track that is what you play (could be a melody or some chord repetitions) and one more track that will be played by the plugin / script. In the best case this would also work if you play rubato. And also if you make some mistakes while playing like playing different notes than those in the MIDI file… :smiley:

I’m not sure if it will work in practice but it is definitely an interesting topic.

Thank you – I look forward to testing / tweaking your script!!

I really like your idea to provide a guide track and a trigger track. The tempo could automatically be deduced from the playing of the guide track. And notes that are not anticipated by the guide track could be assumed to be errors and therefore ignored when tracking the tempo and the position during playback.