How does the sort function work?

Hi all,

I’ve tried to sort an integer array with the sort function.

Var modeOffsets, notesInKey : integer array

Initialization
modeOffsets = [0, 2, 4, 5, 7, 9, 11]
notesInKey = Sort(modeOffsets, true)
End

I expect the array notesInKey to be equal to the array modeOffsets, however, I get an error message:
“Semantic error: Line 26, Col 5: Types are not compatible”

The Sort function does not return a value — (GPScript ain’t C :slight_smile: )

Cheers !

So when I compare to Pascal;
Sort is not a function but a procedure?

Absolutely. GP Script was very much inspired by the Pascal/Algol world. I even thought about using the term procedure when the “function” didn’t return anything. I still could allow it

On the same subject, how do you prefer the use of global versus local variables?
I see myself resorting to both: why return a value from a function if you can also change the global variable (which you would be returning it to) inside the function, directly?

But you can write your own real function

Var modeOffsets, notesInKey : integer array

function csort(a : Integer Array) returns integer array
 var at : Integer Array
 
 at = a
 Sort(at, true)
 
 result = at
end

Initialization
modeOffsets = [0, 2, 4, 5, 7, 9, 11]
notesInKey = csort(modeOffsets)
End

Functions should generally not modify global variables unless there’s no choice. Unfortunately, GPScript does not yet have scoping rules as local as I would like.

Or you could leave out that local variable and just write

function csort(a : Integer Array) returns integer array
   result = a
   Sort(result, true)
end

and save a copy assignmnet

1 Like

Now I think of it, how do you define that the input to the function is to be modified?
Would you write something like this?

Function removeIndex(someArray : Integer Array, index : Integer) returns Integer Array
// Removes data at any index from array
var i : Integer
    For i = index; i < Size(someArray) - 1; i = i + 1 Do
        someArray[i] = someArray[i+1] // Move remainder data 1 index lower
    End
    result = RemoveLast(someArray)
End

This is one of those cases where I’m cautious to simply try.

I think that is not possible as the parameter is only a value and not the object itself.
GP script is not C where you can give a pointer to the original object as a parameter.

But isn’t that exactly what the Sort function does?

Yes, but the sort function is not a user defined function but predefined.
But to be honest, I do not really know.

I left the body of the function commented out and only left the function definition (and its End) in place and the function call later in the code removeIndex(a, b).
The error message was

Semantic error: Line 164, Col 9: No assignment found for function that returns a value

After trying to return the original array it became

Semantic error: Line 165, Col 9: No assignment found for function that returns a value

So now I got it as

Function removeIndex(someArray : Integer Array, index : Integer)
// Removes data at any index from array
var i : Integer
    For i = index; i < Size(someArray) - 1; i = i + 1 Do
        someArray[i] = someArray[i+1] // Move remainder data 1 index lower
    End
    // result = RemoveLast(someArray)
    RemoveLast(someArray)
End

Mind you, still commented out the meat and potatoes. But now I can debug the rest of my code without worrying about this part.

Do you recommend to define it as a function that returns an array and assign it to the same variable with which it was called?

Currently, arrays (and other non-primitive types) are passed as “call by ref” so parameter arguments of these types can be directly modified in a function.

If you don’t want the array itself modified in a function, assign it to a local variable inside the function and do the work there.

At some point it may make sense to have some more built-in functions (like sort) for operations such removing elements. What is the use case for this kind of function, i.e, what are you trying to accomplish that you need to be able to remove parts of an array

Also, I would note that removeIndex is a very misleading function name since, from looking at what you wrote, this should be called removeElementAtIndex

1 Like

Thanks @dhj,

You are correct about the name, it is misleading. I like your suggestion better.

The script keeps track of the notes I’ve enabled, i.e. triads in a programmable inversion, based on a single root note. So when I modify the inversion between the root note’s NoteOn and NoteOff, I disable the wrong chord notes (except for the root) and the original third and fifth remain on.
Also, if I enable a C major triad and subsequently an E minor triad (before releasing the C) I get a Cmaj7, where the E and G are enabled again. If I then release the C, all notes of its triad are released (C-E-G) and only the B remains on. I’d prefer, that in that case only the C is released and the Em (E-G-B) remains on.

For bookkeeping, the note numbers of each NoteOn event and the (then valid) inversion are stored in two arrays (noteOnEvents and inversionEvents). When a key is released, its note is necessarily in the noteOnEvents array (as far as I know it is not possible to receive a NoteOff message without having received the corresponding NoteOn message, first).

I find its index with IndexOf() and use it to recover the corresponding inversion, such that the correct chord notes are released. This happens conditionally, see the C and Em example above. Next, the event must be deleted from the noteOnEvents and inversionEvents arrays, otherwise the arrays would overflow after 128 NoteOn events, and what’s worse the same NoteOn may occur multiple times with different inversions.

I realize that what I’m doing is probably already supported in some way by the NoteTracker, but I couldn’t find information about it.