Go Back   Cockos Incorporated Forums > REAPER Forums > ReaScript, JSFX, REAPER Plug-in Extensions, Developer Forum

Reply
 
Thread Tools Display Modes
Old 06-22-2016, 11:04 AM   #1
RCJacH
Human being with feelings
 
Join Date: Apr 2016
Location: Beijing, China
Posts: 215
Default JS: Midi Events sent at the same tick are not recognized separately

I am currently working on a guitar strumming JS script and right now facing one problem. When I place two or more notes on the same PPQ tick, only the first note is recognized by midirecv command, and I could not find the reason why this is happening, since occasionally all notes are recognized as well. Is there a specific thing I need to put after midirecv for it to trigger per note?
RCJacH is offline   Reply With Quote
Old 06-22-2016, 12:18 PM   #2
DruMunkey
Human being with feelings
 
Join Date: Feb 2016
Posts: 232
Default

Quote:
Originally Posted by RCJacH View Post
I am currently working on a guitar strumming JS script and right now facing one problem. When I place two or more notes on the same PPQ tick, only the first note is recognized by midirecv command, and I could not find the reason why this is happening, since occasionally all notes are recognized as well. Is there a specific thing I need to put after midirecv for it to trigger per note?
I'm running into the exact same issue. I have numerous instances of midirepeat. When it's repeating a note, I find that when I use input quantize (this is all live playing btw) if a new note hits when the repeating note is playing, the new note is almost always ignored.

It's the "almost always" part that's driving me nuts! If it was always the same it would be easier to figure out what's going on...
DruMunkey is offline   Reply With Quote
Old 06-22-2016, 11:17 PM   #3
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
Default

You would need to post code to be sure, but a wild guess: Are you using while()?
Tale is offline   Reply With Quote
Old 06-23-2016, 12:01 AM   #4
RCJacH
Human being with feelings
 
Join Date: Apr 2016
Location: Beijing, China
Posts: 215
Default

How do I post as code block? Anyway the below is a stripped down version of the problematic code.


desc: MIDI/MIDI Guitar Strummer

slider2: 34<0,127,1> Lowest note of Chord input
slider3: 77<0,127,1> Highest note of Chord input

slider36: 0<0,16,1> Counter //Chord note Counter for debugging
in_pin:none
out_pin:none

@init
// Constants from the MIDI specification:
NUM_CHANNELS = 16;
NUM_NOTES = 128;

STATUS_CC = $xB0; // control change MIDI message code
STATUS_NOTE_ON = $x90; // Note On Message
STATUS_NOTE_OFF = $x80; // Note Off Message
CC_ALL_NOTES_OFF = 123;


// Variables of strum engine:

i_susPed = 64; // CC number that act as sustain pedal
b_susPed = 0; // Boolean of whether sustain pedal is on

a_NotesPressed = 0;
memset(a_NotesPressed, 0, NUM_CHANNELS * NUM_NOTES);

a_NotesPendOff = a_NotesPressed + (NUM_CHANNELS * NUM_NOTES);
memset(a_NotesPendOff, 0, NUM_CHANNELS * NUM_NOTES);

@slider

i_loLmt = slider2; // Lowest chord note
i_hiLmt = slider3; // Highest chord note

slider36 = 0;

@block
while(
midirecv(offset, msg1, msg2, msg3) ? (
// Break up the MIDI message into its component parameters.
in_ch = msg1 & $x0F;
in_type = msg1 & $xF0;
in_pit = msg2;
in_vel = msg3;

// By default, we pass all MIDI messages on.
b_passMsg = 1;

(in_type == STATUS_NOTE_ON || in_type == STATUS_NOTE_OFF) ? (
// Chord Notes
in_pit >= i_loLmt && in_pit <= i_hiLmt ? (
// Block output, since we only need a reference of notes
b_passMsg = 0;
// Calculate the memory position of input notes.
v = in_ch * NUM_NOTES + in_pit;
// Note On Message
(in_type == STATUS_NOTE_ON && in_vel > 0) ? (
slider36 += 1;
// If retrigger while susPed is On, rePress the chord key
b_susPed == 1 && a_NotesPendOff[v] > 0 ? a_NotesPendOff[v] = 0;
// This Causes Problems, only one note is recognized by the script, while other notes are passed directly to the next FX in chain. Problem vanishes if this line is deleted.
) : (
// Note Off Message
slider36 -= 1;
);
); // Chord Notes
); //in_type
); //midirecv
); //while
RCJacH is offline   Reply With Quote
Old 06-23-2016, 01:15 AM   #5
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
Default

Quote:
Originally Posted by RCJacH View Post
How do I post as code block?
Just place [ code ] [ / code ] tags around your code (without the spaces).

I am too lazy to test, but this might fix things:

Code:
      ); //in_type
      1; // Force repeat while midirecv() is true
    ); //midirecv
  ); //while
I say this because the while syntax you use repeats while the last (not the first!) executed statement within its subblock returns true.

Another option would be to use the more C-style while syntax:

Code:
  while(midirecv(offset, msg1, msg2, msg3)) (
    ...
  ); //while
Tale is offline   Reply With Quote
Old 06-23-2016, 08:18 AM   #6
RCJacH
Human being with feelings
 
Join Date: Apr 2016
Location: Beijing, China
Posts: 215
Default

Quote:
Originally Posted by Tale View Post

I say this because the while syntax you use repeats while the last (not the first!) executed statement within its subblock returns true.
Thank you! That solved the problem!

Another quick question, right now the MIDI notes sent with this JS will not send midi note off msg (hanging notes) when I stop the host playback midway through a midi clip which functions pretty well otherwise, is there a way to deal with this?
RCJacH is offline   Reply With Quote
Old 06-23-2016, 10:21 AM   #7
DruMunkey
Human being with feelings
 
Join Date: Feb 2016
Posts: 232
Default

Quote:
Originally Posted by Tale View Post
You would need to post code to be sure, but a wild guess: Are you using while()?
Here's my modified/mangled version of the Midi Repeater... It does what I need, except the "let's ignore a note if another note is coming in."

And as you'll note, my version only works for one note per instance, so in my case, if there is a second instance for another note (I'm using this for drums which is why I needed note filter), so it does this ignore thing on played notes, or notes "played" by another instance of the JS.


Code:
desc:Mangled MIDI Note Repeater
//tags: MIDI processing

//slider1:1<8,0,0.03125>Beats
//slider1:1<8,0,.0625>Beats
slider1:1<8,0,.001>Beats
slider2:60<0,127,1{0: C-1,1: C#/Db-1,2: D-1,3: D#/Eb-1,4: E-1,5: F-1,6: F#/Gb-1,7: G-1,8: G#/Ab-1,9: A-1,10: A#/Bb-1,11: B-1,12: C0,13: C#/Db0,14: D0,15: D#/Eb0,16: E0,17: F0,18: F#/Gb0,19: G0,20: G#/Ab0,21: A0,22: A#/Bb0,23: B0,24: C1,25: C#/Db1,26: D1,27: D#/Eb1,28: E1,29: F1,30: F#/Gb1,31: G1,32: G#/Ab1,33: A1,34: A#/Bb1,35: B1,36: C2,37: C#/Db2,38: D2,39: D#/Eb2,40: E2,41: F2,42: F#/Gb2,43: G2,44: G#/Ab2,45: A2,46: A#/Bb2,47: B2,48: C3,49: C#/Db3,50: D3,51: D#/Eb3,52: E3,53: F3,54: F#/Gb3,55: G3,56: G#/Ab3,57: A3,58: A#/Bb3,59: B3,60: C4,61: C#/Db4,62: D4,63: D#/Eb4,64: E4,65: F4,66: F#/Gb4,67: G4,68: G#/Ab4,69: A4,70: A#/Bb4,71: B4,72: C5,73: C#/Db5,74: D5,75: D#/Eb5,76: E5,77: F5,78: F#/Gb5,79: G5,80: G#/Ab5,81: A5,82: A#/Bb5,83: B5,84: C6,85: C#/Db6,86: D6,87: D#/Eb6,88: E6,89: F6,90: F#/Gb6,91: G6,92: G#/Ab6,93: A6,94: A#/Bb6,95: B6,96: C7,97: C#/Db7,98: D7,99: D#/Eb7,100: E7,101: F7,102: F#/Gb7,103: G7,104: G#/Ab7,105: A7,106: A#/Bb7,107: B7,108: C8,109: C#/Db8,110: D8,111: D#/Eb8,112: E8,113: F8,114: F#/Gb8,115: G8,116: G#/Ab8,117: A8,118: A#/Bb8,119: B8,120: C9,121: C#/Db9,122: D9,123: D#/Eb9,124: E9,125: F9,126: F#/Gb9,127: G9}>note
slider3:.0625<1,0,.0625>Beat Quant
slider4:1<8,0,.001>Qtz'd Beat

@init 
status=0;
status2=128;
memset(status,-1,128);
memset(status2,0,128);

@slider 
div=slider1;
note_slider = slider2 & 127;
beat_quant = slider3;

quant=div/beat_quant;
quant_test=div/beat_quant==floor(div/beat_quant);
div/beat_quant != floor(div/beat_quant) ? (
  div=ceil(quant)*beat_quant;
);
slider4=div;
@block

midirecv(ts,msg1,msg23) ? (

  m=msg1&240;
  note=msg23&127;
while(note_slider==note) ? (
  (m == 9*16 && msg23>=256) ? (
    status[note]=0;
    vel=(msg23/256);
    vel<1?vel=1:vel>=127?vel=127:vel|=0;
    status2[note]=vel;
    
    midisend(ts,9*16,note+vel*256); // send note on
  ) : (m == 8*16 || m == 9*16) ? (
    status[note]=-1;
    status2[note]>0 ? (
      midisend(ts,8*16,note); // send note off
      status2[note]=0;
    );
  )) : (
    midisend(ts,msg1,msg23); 
  );
  bla=1;
);


inc = (samplesblock/srate*(tempo/60)*2/div);
x=0;
loop(128,
  status[x]>=0.0 ? 
  (
    status[x] += inc;
    status[x] >= 1.0 ? 
    (

      status[x] -= 1.0;
        status2[x]>0.0 ? (
          midisend(0,8*16,x);
        )
        :
        (
          midisend(0,9*16,x - status2[x]*256);
        );
      status2[x]*=-1;
    );
  );
 x+=1;
   
);

@sample
DruMunkey is offline   Reply With Quote
Old 06-23-2016, 01:57 PM   #8
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,793
Default

IMHO you always need to do midirecv() within a loop.

Look at many example given.

I usually do:
while (midirecv(offs, m1, m2) ) ( // m2 contains both note and velocity
s = m1&$xF0; // Status
....
)

-Michael
mschnell is online now   Reply With Quote
Old 06-24-2016, 01:41 AM   #9
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
Default

Quote:
Originally Posted by RCJacH View Post
Another quick question, right now the MIDI notes sent with this JS will not send midi note off msg (hanging notes) when I stop the host playback midway through a midi clip which functions pretty well otherwise, is there a way to deal with this?
I guess you could add All Notes Off (CC#123) support:

Code:
msg1 & 0xF0 == 0xB0 && msg2 == 123 ? (
  // To-do: Release notes still playing here.
);
Of course you would have to track which notes are still playing (but maybe you are already doing that?). Or, if the receiving parties also support All Notes Off, maybe you could simply forward the All Notes Off message.
Tale is offline   Reply With Quote
Old 06-24-2016, 03:49 AM   #10
RCJacH
Human being with feelings
 
Join Date: Apr 2016
Location: Beijing, China
Posts: 215
Default

Quote:
Originally Posted by Tale View Post
I guess you could add All Notes Off (CC#123) support:

Code:
msg1 & 0xF0 == 0xB0 && msg2 == 123 ? (
  // To-do: Release notes still playing here.
);
Of course you would have to track which notes are still playing (but maybe you are already doing that?). Or, if the receiving parties also support All Notes Off, maybe you could simply forward the All Notes Off message.
Thank you, I have added CC123 Chunk in the script, but the problem is that I'm not receiving the CC123 when I stop the host, even when I put the chunk right after midirecv (using a slider as boolean to check if msg received), and I cannot figure out why. I even separated the chunk, but I'm not receiving any CC or any msg2 == 123 when I stop the host.
RCJacH is offline   Reply With Quote
Old 06-24-2016, 04:42 AM   #11
Tale
Human being with feelings
 
Tale's Avatar
 
Join Date: Jul 2008
Location: The Netherlands
Posts: 3,653
Default

Quote:
Originally Posted by RCJacH View Post
Thank you, I have added CC123 Chunk in the script, but the problem is that I'm not receiving the CC123 when I stop the host, even when I put the chunk right after midirecv (using a slider as boolean to check if msg received), and I cannot figure out why. I even separated the chunk, but I'm not receiving any CC or any msg2 == 123 when I stop the host.
Assuming the host is REAPER, then you can enable/disable All Notes Off, and I guess the same goes for other hosts. Maybe you can use a MIDI logger to see if the hosts sends All Notes Off or not?
Tale is offline   Reply With Quote
Old 06-25-2016, 01:10 PM   #12
DruMunkey
Human being with feelings
 
Join Date: Feb 2016
Posts: 232
Default

The "magic 1;" worked! I added it to the note repeat and it no longer ignores notes at same time!

Yea!
DruMunkey is offline   Reply With Quote
Old 06-25-2016, 03:20 PM   #13
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,793
Default

Quote:
Originally Posted by DruMunkey View Post
The "magic 1;" worked! I added it to the note repeat and it no longer ignores notes at same time!
I had been hit by this issue as well, and needed support from this forum.

It is due to the two different kinds of while - constructions (with one and with two bracket clauses). The one with only one bracket is "bottom controlled", which is not exactly obvious in the code. If using the two-bracket-clause variant, the "magic 1;" is not necessary. (See my example above.)

-Michael
mschnell is online now   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 10:57 AM.


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