Jump to content

Trying to understand a bit more when it comes to the Scripter


Recommended Posts

When I have this, for example:

image.png.fb9166045c7682b2528410a6c37fc7ec.png

the event.trace and event.send mean that "if the previous statement isn't true, run the event.trace and event.send" right?

So in this case, if the statement "event instanceof Note && event.pitch == 38" is false, the note goes untouched (this is what event.send means, right?) and also show the result in the console (this is what event.trace means, right?)

I'm trying to merge 4 different scripts into 1 and it seems that I end up with multiple event.trace and event.send and I wonder if I really just need 1?

---

Are these 2 the same thing, but the top one is just omitting the "else" part? If so, is there any advantage to one or the other, apart from having fewer code?

image.png.ad047fd2c559aabcad62f3623d74b270.png

Edited by Tiago Rocha
Link to comment
Share on other sites

39 minutes ago, Tiago Rocha said:

When I have this, for example:

image.png.fb9166045c7682b2528410a6c37fc7ec.png

"event" is an object that represents a MIDI event, which has both properties (bits of data, like for a note, it's pitch and velocity, or for a CC, it's CC number and value etc according to the MIDI spec), and functions defined (like "trace" and "send").

This code is called on every MIDI event, and in pseudocode it means:

If we have a note event with a note number of 38, do some adjustments to it's velocity. (All other MIDI events, including notes with note numbers other than 38, will be unaltered.)

Every event, regardless of whether it's a modified note number 38 or not, will have the trace() function called on it (which outputs a message to the console I believe), and then the send() function (which passes the MIDI event on to it's ultimate destination.)

39 minutes ago, Tiago Rocha said:

Are these 2 the same thing, but the top one is just omitting the "else" part?

No, they behave differently. The second one will basically remove all note number 38 events from the MIDI stream, and they will not be displayed, or passed on to their destination. They will be blocked, and all other MIDI events will pass through.

  • Like 1
Link to comment
Share on other sites

I see. So basically if I have 5 events at the same time (for example a chord), all of them will send their info to the console and all of them will be sent to the instrument. I was testing it with a new project and a simple code and if I just have this

image.png.405df7cee3792ac8a2a8da5e9c3e08a1.png

I get no sound and nothing the console.

Then if I add this:
image.png.0bfe2505b64554672bc48b84004e8728.png

All notes show in the console and are sent to the instrument, but C1 is transposed to A#1

Is there a way to "negate" the event.send()? For example if I want a particular note to not be sent to the instrument? Right now I have this, but I wonder if there's a "don't send" option instead of using velocity 0

image.png.e852789caf36f07946c3b0b55f31c0a4.png

Link to comment
Share on other sites

Ok so one thing I noticed, and maybe that's why when I try to merge 4 scripts, it doesn't work the way it does when it's 4 separate scripts, is because once there's event.send(), everything else gets ignored, like this:

image.png.95fa1630739d4bf5f6edf559319e60fc.png

So the first transposition occurs from 36 to 46, but then the one from 39 to 46 does not.
I thought the event.send() was more like a "continue the script", but it's just "stop reading everything after this and send the notes to the instrument". Interesting...

Link to comment
Share on other sites

21 minutes ago, Tiago Rocha said:

All notes show in the console and are sent to the instrument, but C1 is transposed to A#1

Yes, that is what that code does.

21 minutes ago, Tiago Rocha said:

Is there a way to "negate" the event.send()? For example if I want a particular note to not be sent to the instrument? Right now I have this, but I wonder if there's a "don't send" option

A "don't send" option is particular notes not triggering an event.send() instruction.

ie (in pseudocode):

- If this event is not the note I want to block, call event.send()

Link to comment
Share on other sites

3 minutes ago, Tiago Rocha said:

is because once there's event.send(), everything else gets ignored, like this:

event.send() essentially means "Ok, we're done with this event, send it on it's way." It goes out of the Scripter plugin, to it's destination.

You can't do more stuff with that event - it's gone now, it's left the building. You need to do all the stuff you want to do, then send whatever events you want on at the end of your processing.

  • Like 1
Link to comment
Share on other sites

32 minutes ago, des99 said:

event.send() essentially means "Ok, we're done with this event, send it on it's way." It goes out of the Scripter plugin, to it's destination.

You can't do more stuff with that event - it's gone now, it's left the building. You need to do all the stuff you want to do, then send whatever events you want on at the end of your processing.

Oh I see. So I did another test and now both notes are transposed, using your explanation:

image.png.a9c99528cbb64886d2189dcd415ce447.png

I didn't know you could have 2x function HandleMIDI(event) in the same script. So each one is a block of conditions that are processed one after the other. So in this case it processes the first conditions and sends the notes to the instrument, then processes the second one and sends those to the instrument as well.

So something like this would transpose C1, but not C#1, then would transpose D1
image.png.9915ac898dda39d76eede2a3c0fd2958.png

I'm getting there...

Thanks!

Edited by Tiago Rocha
Link to comment
Share on other sites

2 hours ago, Tiago Rocha said:

I didn't know you could have 2x function HandleMIDI(event) in the same script.

Pretty sure you shouldn't do that, it's a callback that gets called on every MIDI event, and you should do *all* your processing in that callback.

2 hours ago, Tiago Rocha said:

So in this case it processes the first conditions and sends the notes to the instrument, then processes the second one and sends those to the instrument as well.

I don't even know what you're trying to do with that code..(!) Trying to modify the pitch after the event has been sent... ?

2 hours ago, Tiago Rocha said:

I'm getting there...

Not so much 🙂

There is no reason to have multiple handleMIDI callbacks. One is plenty, and you can do all your processing there, before finally letting the events you want to get dispatched.

Maybe if you list out exactly what operations you want to do, I can help...

  • Like 1
Link to comment
Share on other sites

You should be thinking along the lines of:

A MIDI event gets sent to this HandleMIDI function - all events individually get processed by this function.

Pseudocode (sorry, as you're posting screen images rather than code I can't just cut and past your posted code here, so this is all I can reasonably do):-

if (condition) {
	// do something like modify this event
}

if (othercondition) {
	// do something else, like modify this event differently
}

// add whatever other processing to each event type here
// (I'm keeping this simple in code terms for now)

if ((thirdcondition and fourthcondition) or fifthcondition) {
	// whatever events reach here will be sent on
	// otherwise they will be filtered out

	event.send()
}

To be more specific, you'd need to, well, be more specific as to what you are trying to do...

Link to comment
Share on other sites

You should look into "else if" statements and then get nesting your code as desired.

For example:

if (event instanceof Note)	{
	if (event.pitch == 36)
		event.pitch = 58;
	else if (event.pitch == 37)
		event.pitch = 59;
//	and so on
}
event.trace();
event.send();

Depending on where you put event.send() you'll get different behavior. In the above case all incoming data is passed through except specific notes as defined in the function (those get manipulated and then sent).

Compare this to

if (event instanceof Note)	{
	if (event.pitch == 36)
		event.pitch = 58;
	else if (event.pitch == 37)
		event.pitch = 59;
//	and so on
event.trace();
event.send();
}

In this case only notes are sent; all other data is filtered. Again, specific notes as defined are manipulated.

Compare this to

if (event instanceof Note)	{
	{
	if (event.pitch == 36)
		event.pitch = 58;
	else if (event.pitch == 37)
		event.pitch = 59;
//	and so on
	event.trace();
	event.send();
	}
}

In this case only the manipulated notes are sent and all other data (including notes not defined in the function) is filtered.

 

Edited by gacki
  • Like 2
Link to comment
Share on other sites

And here's another approach to avoid excessive if...else boilerplate code, using an object literal where the keys are the incoming notes and the values is the outgoing notes:

const noteMap = {
  //incoming note : outgoing note
  36: 57,
  37: 58,
  38: 59,
  // ...
};

function HandleMIDI(e) {
  if (e instanceof Note) {
    // Remap incoming notes if within the noteMap object, otherwise let notes pass unaffected
    e.pitch = noteMap[e.pitch] || e.pitch;
  }
  // Send remapped notes and all other MIDI events
  e.send();
}

J.

Edited by Jordi Torres
  • Like 1
Link to comment
Share on other sites

Posted (edited)
On 2/29/2024 at 4:44 PM, des99 said:

Pretty sure you shouldn't do that, it's a callback that gets called on every MIDI event, and you should do *all* your processing in that callback.

So use a single HandleMIDI and put everything inside?

On 2/29/2024 at 4:44 PM, des99 said:

I don't even know what you're trying to do with that code..(!) Trying to modify the pitch after the event has been sent... ?

That code was just for testing purposes, so I can learn how things work. In this case, since using more than one HandleMIDI is not advised, never mind that. I was just trying to figure out if you could use one HandleMIDI to make some changes while ignoring others, send those notes to the instrument and then the second HandleMIDI would do something else. But again, these were just tests anyway so I could understand the "mechanics" of Scripter. And sometimes doing things that make absolutely no sense, also helps.

On 2/29/2024 at 5:14 PM, des99 said:

sorry, as you're posting screen images rather than code

For some reason I didn't have the "code" button on my menu bar up until today. Maybe David changed my "status" and now I can use it? Maybe it was some member ranking "upgrade" thing. I don't know. It just wasn't there before and pasting code as normal text was kinda messy. But those were also tests anyway.

When you use this:

if ((thirdcondition and fourthcondition) or fifthcondition) {
	// whatever events reach here will be sent on
	// otherwise they will be filtered out

	event.send()
}

and you say they will be filtered out, you mean they are not sent to the instrument, because you are adding the event.send() inside the IF block, right? Because if it was

if ((thirdcondition and fourthcondition) or fifthcondition) {
	// whatever events reach here will be sent on
	// otherwise they will be filtered out
}
event.send()

then it means that all notes are sent to the instrument, but those that match the conditions are somehow changed based on the actions we add inside, right?

Edited by Tiago Rocha
  • Like 1
Link to comment
Share on other sites

@gacki thanks for the examples!

Yes, I had some code here (copied from other people sharing it online) that have the else if. So I have a few questions:

1 - I can use multiple else if, right? Like this:

if (event instanceof Note)	{
	if (event.pitch == 36)
		event.pitch = 58;
	else if (event.pitch == 37)
		event.pitch = 59;
	else if (event.pitch == 38)
		event.pitch = 60;
	else if (event.pitch == 39)
		event.pitch = 61;
}

2 - Then I can add a condition for everything else like:

if (event instanceof Note)	{
	if (event.pitch == 36)
		event.pitch = 58;
	else if (event.pitch == 37)
		event.pitch = 59;
	else if (event.pitch == 38)
		event.pitch = 60;
	else if (event.pitch == 39)
		event.pitch = 61;
  else 
    event.pitch = 100; // everything that doesn't match any of the conditions above will change the pitch to 100
}

Is this how to use the else by itself?

Link to comment
Share on other sites

2 minutes ago, Tiago Rocha said:

1 - I can use multiple else if, right? Like this:

Exactly like this, yes.

2 minutes ago, Tiago Rocha said:

2 - Then I can add a condition for everything else like:

Yes, this would set the pitch for all notes except 36 to 39 to 100.

From an aesthetic point of view I would put the "else" on the same tab distance as the "else if" before because it functionally belongs to that group. This makes everything slightly easier to read. The code will execute the same regardless.

  • Like 2
Link to comment
Share on other sites

On 3/1/2024 at 11:48 AM, Jordi Torres said:

And here's another approach to avoid excessive if...else boilerplate code, using an object literal where the keys are the incoming notes and the values is the outgoing notes:

const noteMap = {
  //incoming note : outgoing note
  36: 57,
  37: 58,
  38: 59,
  // ...
};

function HandleMIDI(e) {
  if (e instanceof Note) {
    // Remap incoming notes if within the noteMap object, otherwise let notes pass unaffected
    e.pitch = noteMap[e.pitch] || e.pitch;
  }
  // Send remapped notes and all other MIDI events
  e.send();
}

J.

Thanks for this solution! I saw that you used that on the code for the topic about my Alesis drum kit, but now I can see how it works.

So just to make sure I understand this e.pitch = noteMap[e.pitch] || e.pitch;

Change the event's pitch (e.pitch), which in the noteMap refers to the number on the left, to the noteMap pitch (noteMap[e.pitch]), which will be the note on the right), correct?
And then || e.pitch at the end is for the notes that don't match that condition?
So the || e.pitch at the end, assuming the note doesn't match the condition, is like writing:
e.pitch = e.pitch

right?

Link to comment
Share on other sites

5 minutes ago, gacki said:

From an aesthetic point of view I would put the "else" on the same tab distance as the "else if" before because it functionally belongs to that group. This makes everything slightly easier to read. The code will execute the same regardless.

Ok thanks. Sometimes I use VS Code, because it's easier to work with and I can do that cleaning automatically. Then I copy and paste it to Scripter. VS Code even shows some errors like missing brackets and all that, so it's good for a non-developer like myself to make sure everything is close to perfect 😉 I wish Scripter had this too, a button to arrange the code automatically.

Thanks for your time and help! Going to save all of this to my Scripter notes

6 minutes ago, des99 said:

Yep, that all looks correct. 👍

Great! Thanks!

  • Like 1
Link to comment
Share on other sites

3 minutes ago, Tiago Rocha said:

VS Code even shows some errors like missing brackets and all that, so it's good for a non-developer like myself to make sure everything is close to perfect

This is just as useful for developers, trust me! 😉

Link to comment
Share on other sites

Posted (edited)
3 minutes ago, des99 said:

This is just as useful for developers, trust me! 😉

Oh for sure! I mean, for me, even things that are probably super obvious to developers, is an bonus, because along the way when it shows me an error, that is also something that could be teaching me where to add the brackets, or a comma, etc. And this extension to make the code organized automatically, is also a way for me to see how it "should" be organized. 

I'm saying "should" because I remember a few years ago working with an experienced developer and I was helping him with some files to make his work easier and he told me to format the document a specific way because it was easier for him to then use it with his files, database, etc.

But yeah, VS Code has been a great tool for me to learn here and there.

Edited by Tiago Rocha
  • Like 1
Link to comment
Share on other sites

On 3/2/2024 at 2:20 PM, Tiago Rocha said:

So just to make sure I understand this e.pitch = noteMap[e.pitch] || e.pitch;

Change the event's pitch (e.pitch), which in the noteMap refers to the number on the left, to the noteMap pitch (noteMap[e.pitch]), which will be the note on the right), correct?
And then || e.pitch at the end is for the notes that don't match that condition?
So the || e.pitch at the end, assuming the note doesn't match the condition, is like writing:
e.pitch = e.pitch

right?

Right, that's pretty much it...

It's a conditional assignment (whenever you see "=" that's an assignment).

In other words, you're assigning a value to the pitch property of the incoming Note event object based on the result of that logical OR expression => noteMap[e.pitch] || e.pitch.

In this case you necessarily need to have e.pitch on the right side of the OR expression (instead of just having noteMap[e.pitch] on its own), because if no key matching the incoming Note event's pitch is found in the noteMap object, that would assign undefined to e.pitch (although Scripter converts that undefined value to 0 automatically).

So by having e.pitch on the right side of the OR expression, you assign whatever is the incoming pitch when that pitch is not present as a key in the noteMap object...and assigning e.pitch to e.pitch (e.pitch = e.pitch) in that case is the same as just letting the original pitch of the incoming Note event be sent when e.send() is called.

Here's some pictures to illustrate (using NoteOn instead of Note to ignore Note Off events):

Screenshot2024-03-03at20_59_19.thumb.png.245ea61ed1b02561b4fb623c36ecbb89.png

Screenshot2024-03-03at21_00_19.thumb.png.d5dd8f952ff60b6e18875fe158dda38f.png

J.

  • Like 1
  • Love 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...