Old 08-15-2022, 09:37 AM   #1
ronaldjeremy
Human being with feelings
 
Join Date: Feb 2022
Posts: 8
Default Loop through all notes in a track in JSFX?

I want to write a JSFX to scale midi velocities, only outputting midi velocities between 91 and 100, basing the appropriate velocity on the difference between the lowest and highest velocity of any note in the track.

The problem I am running into is that I cannot figure out how to add something in @init or @slider to find the lowest and highest velocities among all notes in the track when the plugin starts. I need to be able to loop through all of the notes in the track first to initialize min and max velocity variables before the midirecv loop.

It doesn't look like I can do things like MIDI_CountEvts, MIDI_GetNote etc in a JSFX, is it not possible to analyze the notes in the track in a JSFX?
ronaldjeremy is offline   Reply With Quote
Old 08-15-2022, 10:25 AM   #2
Fabian
Human being with feelings
 
Fabian's Avatar
 
Join Date: Sep 2008
Location: Sweden
Posts: 7,416
Default

JSFX do real-time processing, basically it only sees what is currently "active".

If you absolutely want to have a JSFX for this, one way would be to have two modes, one for collecting the min and max velocities, and then a processing mode where the JSFX adjusts the velocities in real-time. You would have to run the MIDI through the JSFX twice and (manually) shift mode in between.

But what you want to do is better done with off-line processing, with a script written in EEL or Lua. Such a script would have the same two modes but running off-line it would be much quicker and no hassle with the mode shift, the code would know beforehand the number of MIDI events to process.

Here https://mespotin.uber.space/Ultrasch...I%20Management you have a description of the API functions to manage MIDI items.
__________________
// MVHMF
I never always did the right thing, but all I did wasn't wrong...
Fabian is offline   Reply With Quote
Old 08-15-2022, 11:41 AM   #3
ronaldjeremy
Human being with feelings
 
Join Date: Feb 2022
Posts: 8
Default

Thank you @Fabian for your reply. So you are saying script can do the same live translation as a JSFX? If it would help, here is the code I have for the plugin, which works perfectly other than the fact I can't figure out how to initialize lowestVelocityOnTrack and highestVelocityOnTrack:

Code:
desc:Compress Velocity Range

slider1:91<0,127,1>Low velocity of output
slider2:100<0,127,1>High velocity of output

@init
noteOn = $x90; //note statusbyte
lowestVelocityOnTrack = 40; //i need this to be caluclated instead of hard coded
highestVelocityOnTrack = 110; //i need this to be caluclated instead of hard coded
rangeOnTrack = highestVelocityOnTrack - lowestVelocityOnTrack;

@slider
lowOutput = slider1;
highOutput = slider2;
desiredRange = highOutput - lowOutput;

@block
while (midirecv(offset,msg1,msg2,msg3)) (
  noteStatus = msg1 & $xF0; // strip channel info
  currentVel = msg3;
  noteStatus==noteOn ? (
      multiplier = (currentVel - lowestVelocityOnTrack) / rangeOnTrack;
      translatedVel = lowOutput + (desiredRange * multiplier);
      midisend(offset, msg1, msg2, translatedVel);
  );
)

Last edited by ronaldjeremy; 08-15-2022 at 12:38 PM.
ronaldjeremy is offline   Reply With Quote
Old 08-15-2022, 12:33 PM   #4
whats_up
Human being with feelings
 
Join Date: Nov 2020
Posts: 180
Default

Quote:
Originally Posted by ronaldjeremy View Post
So you are saying script can do the same live translation as a JSFX?
a PLUGIN script process notes as the host play them and send them to it (live).
a script can process notes offline.

PLUGIN script can not get all notes in a track
while script can

It seems that you want both
offline processing
and live

you can do this by collecting the notes from the whole track with a script
store the notes in common global memory (using gmem or other method)

then process the notes from a PLUGIN script, live.
__________________
Easy EEL to VST Building system
https://forum.cockos.com/showthread.php?t=245285
github: https://github.com/VisualCodeBase/CodeBase
whats_up is online now   Reply With Quote
Old 08-17-2022, 10:32 AM   #5
Fabian
Human being with feelings
 
Fabian's Avatar
 
Join Date: Sep 2008
Location: Sweden
Posts: 7,416
Default

Quote:
Originally Posted by whats_up View Post
you can do this by collecting the notes from the whole track with a script
store the notes in common global memory (using gmem or other method)

then process the notes from a PLUGIN script, live.
That's one way, yes.

But you can do it all off-line.

You use MIDI_GetAllEvts(take, #buf) to get a list of all the events of the current take of the MIDI item into buf. Then you go through buf and process every note on event to read its velocity, and collect the highest and lowest velocity. Then you go through buf again and adjust the velocities to your liking. Finally you use MIDI_SetAllEvts(take, buf) to update the MIDI item take with the new velocities.

It seems rather straightforward.

Details are here
https://mespotin.uber.space/Ultrasch...IDI_GetAllEvts
https://mespotin.uber.space/Ultrasch...IDI_SetAllEvts
__________________
// MVHMF
I never always did the right thing, but all I did wasn't wrong...
Fabian is offline   Reply With Quote
Old 08-18-2022, 02:11 AM   #6
whats_up
Human being with feelings
 
Join Date: Nov 2020
Posts: 180
Default

Quote:
Originally Posted by Fabian View Post
That's one way, yes.

But you can do it all off-line.

You use MIDI_GetAllEvts(take, #buf) to get a list of all the events of the current take of the MIDI item into buf. Then you go through buf and process every note on event to read its velocity, and collect the highest and lowest velocity. Then you go through buf again and adjust the velocities to your liking. Finally you use MIDI_SetAllEvts(take, buf) to update the MIDI item take with the new velocities.

It seems rather straightforward.

Details are here
https://mespotin.uber.space/Ultrasch...IDI_GetAllEvts
https://mespotin.uber.space/Ultrasch...IDI_SetAllEvts
Thank you, helpful.
__________________
Easy EEL to VST Building system
https://forum.cockos.com/showthread.php?t=245285
github: https://github.com/VisualCodeBase/CodeBase
whats_up is online now   Reply With Quote
Old 08-18-2022, 10:14 AM   #7
ronaldjeremy
Human being with feelings
 
Join Date: Feb 2022
Posts: 8
Default

Quote:
Originally Posted by Fabian View Post
That's one way, yes.
But you can do it all off-line.
The thing is, I am not looking to modify the midi notes on the track, I want to leave them intact. I just want to add the JSFX to the track and have it translate the notes on the fly according to the formula.

@whats_up looks to be right in that I need to use a script to find min and max, and I like the idea of using gmem to share them with the JSFX.

The only problem then would be to have some way of triggering a script to run in the @init section of the JSFX. So that JSFX starts, runs the script, the script writes min/max variables to gmem, then the JSFX can access those via gmem. Is there a way to trigger a script from JSFX @init?
ronaldjeremy is offline   Reply With Quote
Old 08-18-2022, 10:39 AM   #8
Fabian
Human being with feelings
 
Fabian's Avatar
 
Join Date: Sep 2008
Location: Sweden
Posts: 7,416
Default

Quote:
Originally Posted by ronaldjeremy View Post
The thing is, I am not looking to modify the midi notes on the track, I want to leave them intact.
OK I see. I misunderstood that.

Quote:
Originally Posted by ronaldjeremy View Post
The only problem then would be to have some way of triggering a script to run in the @init section of the JSFX. So that JSFX starts, runs the script, the script writes min/max variables to gmem, then the JSFX can access those via gmem. Is there a way to trigger a script from JSFX @init?
I am not sure about "in the @init section", but a jsfx and a script can communicate over gmem. Your jsfx sets a specific gmem variable that your script monitors, and then your script does its work and writes the min and max values in gmem variables, and then sets another gmem variable to tell the jsfx to do its job. This needs a bit of care as racing problems might occur, but it is possible (I have done almost exactly this for communicating with a jsfx). Avoiding that the jsfx and the script write to the same variable would seem to be the safest.

Note that there could be problems at the startup as the script would need some time going through the MIDI item before it knows the min and max values, but the jsfx would start to receive MIDI items as soon as play is pressed. Maybe with large enough block size (and not too long MIDI item) this could be made to work, but I see a potential problem here.
__________________
// MVHMF
I never always did the right thing, but all I did wasn't wrong...
Fabian is offline   Reply With Quote
Old 08-18-2022, 10:55 AM   #9
Fabian
Human being with feelings
 
Fabian's Avatar
 
Join Date: Sep 2008
Location: Sweden
Posts: 7,416
Default

Thinking about this...

I would run the script first, so that when play is hit the jsfx simply reads the min/max values from the gmem variables. That removes all the hassle of communicating back and forth between the script and the jsfx. The script only writes those values into gmem, and the jsfx only reads them.
__________________
// MVHMF
I never always did the right thing, but all I did wasn't wrong...
Fabian is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 09:52 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.