Old 06-14-2017, 08:09 PM   #1
Spacemen Tree
Human being with feelings
 
Spacemen Tree's Avatar
 
Join Date: Mar 2013
Posts: 484
Default [JS fx] does a CC controled transpose JS exist?

Hi.

Anyone know if someone has made a JS that transposes incoming MIDI notes with the transpose amount being controlled by CC?

If not can someone please do it?

Similar to this VST but with the transpose amount being user defineable.



Thanks
__________________
"After silence, that which comes nearest to expressing the inexpressible is music", Aldous Huxley
Spacemen Tree is offline   Reply With Quote
Old 06-14-2017, 10:33 PM   #2
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Germany
Posts: 3,050
Default

I did something like that and use it in my live setup.

It uses a CC on/off switch.

Off: no transposing

On: transposing on.

The initial transpose offset is taken from a slider and hence stored/recalled by Reaper.

If the first note on event after setting "on" is within the lowest two octaves of an 88 key keyboard, this note is not played, but sets the transpose offset.

(Moreover another on/off CC is used to optionally add a note one octave below the one played.)

-Michael
__________________
www.boa-sorte.de

Last edited by mschnell; 06-15-2017 at 02:07 AM.
mschnell is offline   Reply With Quote
Old 06-16-2017, 05:09 AM   #3
Spacemen Tree
Human being with feelings
 
Spacemen Tree's Avatar
 
Join Date: Mar 2013
Posts: 484
Default

Hi Michael.

Would you be so kind to share the code? So I can look at it... Don't know if there's much point because I'm not familiar to JS.

But unless anyone wants to make it for me I'm going to have to take a crack at it...

Did some copy pasting already after looking up a few JS fx code but so far no results. JS is a bit alien for me right now.

Code:
desc:Transposer

slider1:1<0,127,1>CC Up
slider2:0<0,127,1>CC Down
slider3:0<0,127,1>transpose

@init
CC_MSG =11;
CCValue = 0;

@slider
ccup = slider1;
ccdown = slider2;
transpose =  slider3;

@block
while (
  midirecv(mpos, msg1, msg23) ? (
    CCValue = (msg23/256)|0;
    msg3 = (msg23/256)|0;
    msg2 = msg23-(msg3*256);
    (msg2 == ccup) ? (
          msg1 = 9*16;
          msg2 = note; 
          msg3 = vel;
          trig = 1;
          transpose = transpose + 12;
          msg23 = (msg3*256+msg2)|0;
          midisend(mpos,msg1, msg23);
        );
    (msg2 == ccdown) ? (
          msg1 = 9*16;
          msg2 = note; 
          msg3 = vel;
          trig = 1;
          transpose = transpose - 12;
          msg23 = (msg3*256+msg2)|0;
          midisend(mpos,msg1, msg23);
        );
        );        
);
If anyone want to give some pointers, I'd appreciate it.
the above was just to see if given the input CC I could move the "transpose" slider.
I thought I'd worry later about the actual transposing
__________________
"After silence, that which comes nearest to expressing the inexpressible is music", Aldous Huxley
Spacemen Tree is offline   Reply With Quote
Old 06-16-2017, 06:46 AM   #4
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Germany
Posts: 3,050
Default

Here you are:

Code:
desc:MIDI Octave
//tags: MIDI processing

slider1:0<-11,11,1>Transpose Semitones
slider2:-5<-11,11,1>Previous Transpose
slider3:21<0,127,1>Lowest Key (MIDI Note #)
slider4:65<0,127,1>Midi CC Transpose
slider5:66<0,127,1>Midi CC Octave


// these lines tell Reaper the effect has no audio input/output,
// which enables processing optimizations.
// MIDI-only FX should always have these lines.
in_pin:none
out_pin:none

@init
global_info = 0;
notebuf = 0; // 4 entries per open note: orignote, channel, vel, transnote
buflen = 0;
last_transpose = 0;
gmem[global_info] = last_transpose;
last_samplepos = 0;
last_oct=0;
oo=0;
att=0;
oct1=slider3;
lowc=(((oct1+13) / 12) | 0) * 12;  // if lowest key is a C -> one octave up

@slider
att=0;
oct1=slider3;
lowc=(((oct1+13) / 12) | 0) * 12;  // if lowest key is a C -> one octave up

@block
samplepos = play_position*srate;
samplechg = samplepos-last_samplepos;
samplechg < -samplesblock/2.0 || samplechg > samplesblock*3.0/2.0 ? (
  buflen = 0;  // clear state on seek   
);
last_samplepos = samplepos;
slider1|0 != last_transpose || oct != last_oct ? (
  last_transpose = slider1|0;
  gmem[global_info] = last_transpose;
  last_oct  = oct;
  i = 0;
  loop (
    buflen,    
    n = notebuf[4*i]|0; // original note
    c = notebuf[4*i+1]|0; // channel
    v = notebuf[4*i+2]|0; // velocity
    t = notebuf[4*i+3]|0; // transposed note
    midisend(0, $x80|c, t&0x7F); // clear the sustaining transposed note    
    t & 0x80 ? (                 // octave had been sent
      midisend(0, $x80|c, (t&0x7F)-12); // clear the sustaining octave note        
    );
    t = (n+last_transpose)|0; // new transposed note    
    t < 0 ? t = 0 : t > 127 ? t = 127;
//    midisend(0, $x90|c, (v*256)|t); // send the new transposed note
    notebuf[4*i+3] = t; // update the buffer 
    oct ? (
      t-=12;
//      midisend(0, 0x90|c, (v*256)|t); // send the new octave note
      notebuf[4*i+3] = t|0x80; // update the buffer 
    );
    i = i+1;
  );
);
while (midirecv(offs, m1, m2) ) (       // m2 contains both note and velocity
    s = m1&$xF0;                        // Status
    s != 0xF0 ? (
      s == 0x90 || s == $x80 ? (        // note-on or note-off
        n = m2&0xFF;                    // original note
        v = (m2&$xFF00)/256;            // velocity
        no = s==0x90 && v != 0;
        att && no ? (                   // we are special
          att = 0;                      // next key is normal       
          (n >= lowc) && (n < lowc+24) ? (  // transpose request
            n -= lowc+12;                // +0 ... +11
            slider1 = n;
            m1 = 0;                      // no output
          );
        );  
        m1 ? (
          n >= 0 ? (
            c = m1&0xF; // channel
            t = (n+last_transpose)|0; // transposed note
            t < 0 ? t = 0 : t > 127 ? t = 127;
            m2 = m2+t-n; // apply transposition      
            oo && (t>12) ? (
              mo = m2-12;   //Sub - Octave
             ) : (
              mo = 0;
            );  
            i = -1;
            while (  // look for this note|channel already in the buffer
              i = i+1;
              i < buflen && (notebuf[4*i]|0 != n || notebuf[4*i+1]|0 != c);
            );
            no ? (// note-on, add to buffer        
              notebuf[4*i] = n;
              notebuf[4*i+1] = c;
              notebuf[4*i+2] = v;
              notebuf[4*i+3] = t | oo;
              i == buflen ? buflen = buflen+1;
             ) : (// note-off, remove from buffer        
              i < buflen ? (
                memcpy(notebuf+4*i, notebuf+4*(i+1), 4*(buflen-i-1));  // delete the entry
                buflen = buflen-1;
              );  
            );
          );
        );
       ):(
        s == 0xB0 ? (
          m2 == 0x017E ? (
            oct =1;
            oo = 0x80;
            m1 = 0;
           ):(
            m2 == 0x007F ? (
              oct = 0;
              oo = 0;
              m1 = 0;
             ):( 
              (m2 & 0x7F) == slider4 ? (
                (m2 >> 8 ) < 64 ? (             
                  slider2 = last_transpose;
                  att = 0;
                  slider1 = 0;
                  m1 = 0;
                 ) : (
                  slider1 = slider2;
                  last_transpose = 0;
                  gmem[global_info] = last_transpose;
                  att = 1;
                  m1 = 0;                 
                ); 
              );  
            );
          );        
        );  
      );
      m1 ? (
        midisend(offs, m1, m2);
        no ? (
          att = 0;                   // next key is handled normally
        );  
        mo && (s == 0x90 || s == $x80) ? ( // Sub-Octave
          midisend(offs, m1, mo);
        );  
      );
      
      
      nb0 = notebuf[4*0];            // why does this kill the error ?!?!?!?!?
      nb1 = notebuf[4*1];
      
      
        
    );
);
__________________
www.boa-sorte.de
mschnell is offline   Reply With Quote
Old 06-16-2017, 10:18 AM   #5
ashcat_lt
Human being with feelings
 
Join Date: Dec 2012
Posts: 2,225
Default

Is there some reason you don't want to just use Parameter Modulation for this?
ashcat_lt is offline   Reply With Quote
Old 06-16-2017, 11:33 AM   #6
nofish
Human being with feelings
 
nofish's Avatar
 
Join Date: Oct 2007
Location: home is where the heart is
Posts: 6,956
Default

Tbh I don't get the request because sliders of any JS can be MIDI learned and thus controlled via CC no ? (So I'd think any MIDI transpose JS would do, and there are a couple in Reaper's stock JS).

What am I missing here ?

edit:
If you want to control with CC's from MIDI tracks and not an external controller you could use MIDItoReaControlPath.

Last edited by nofish; 06-16-2017 at 11:54 AM.
nofish is offline   Reply With Quote
Old 06-16-2017, 12:46 PM   #7
ashcat_lt
Human being with feelings
 
Join Date: Dec 2012
Posts: 2,225
Default

Quote:
Originally Posted by nofish View Post
edit:
If you want to control with CC's from MIDI tracks and not an external controller you could use MIDItoReaControlPath.
Well...You could just use Paramater Modulation.

I prefer that anyway because you have a lot more control and it keeps the routing all discrete rather than spamming the global control path.

Edit - And of course this will work with an external controller as well. You don't have to enable it for control or anything. Just route the midi signals around as necessary, PM|MIDI Link, done.
ashcat_lt is offline   Reply With Quote
Old 06-16-2017, 03:21 PM   #8
Spacemen Tree
Human being with feelings
 
Spacemen Tree's Avatar
 
Join Date: Mar 2013
Posts: 484
Default

Hi.

Little insight on what I'm trying to do:

I've set up a OSC template for when I need to do quick midi melody or whatever.
So since I've only fitted two octaves on the screen I was thinking I'd set two other buttons in that template that would send CC to control a transposing plugin and that would allow me to access other keyboard ranges.

I thought there's got to be a JS fx because like almost everything been done there. Oddly enough didn't find one. There's that J's VST midi plugin but it won't do octaves and I couldn't find any other one.


Does ReaControlMIDI or Parameter Modulation work for this?
__________________
"After silence, that which comes nearest to expressing the inexpressible is music", Aldous Huxley
Spacemen Tree is offline   Reply With Quote
Old 06-16-2017, 09:54 PM   #9
Spacemen Tree
Human being with feelings
 
Spacemen Tree's Avatar
 
Join Date: Mar 2013
Posts: 484
Default

Quote:
Originally Posted by mschnell View Post
Here you are:
Thanks so much Michael.
__________________
"After silence, that which comes nearest to expressing the inexpressible is music", Aldous Huxley
Spacemen Tree is offline   Reply With Quote
Old 06-17-2017, 03:58 AM   #10
Spacemen Tree
Human being with feelings
 
Spacemen Tree's Avatar
 
Join Date: Mar 2013
Posts: 484
Default

Well, incredibly, contrary to my expectations, I was able to do it

If anyone wants to comment on the code I'd appreciate it, it's my first JS-fx and it's more of a hack job than anything else, so I'm sure there's lots of room for improvement...

The options I think are self-explanatory. If not:

* down CC -- select a CC from dropdown list and when sent from keyboard, ipad, etc, it subtracts x semitones from current range.
* up CC -- same as above but inversely
* Factor -- number of semitones added/ subtracted (as a unit) when transposing
* Amount -- number of semitones currently added/ subtracted as a total

If you are feeling up to it could use an explanation (like draw me a picture type) of exactly how MIDI bytes and all that work. I could gather some understanding from the JS docs and from here https://ccrma.stanford.edu/~craig/ar...essenmidi.html but some down to earth 1+1 explanation would be greatly appreciated.

EDIT: It's here https://stash.reaper.fm/v/30982/MIDI%...Transposer.zip
__________________
"After silence, that which comes nearest to expressing the inexpressible is music", Aldous Huxley

Last edited by Spacemen Tree; 06-19-2017 at 03:12 AM.
Spacemen Tree is offline   Reply With Quote
Old 06-17-2017, 04:30 AM   #11
mschnell
Human being with feelings
 
mschnell's Avatar
 
Join Date: Jun 2013
Location: Germany
Posts: 3,050
Default

Great ! Congrats,
-Michael
__________________
www.boa-sorte.de
mschnell is offline   Reply With Quote
Old 06-19-2017, 03:10 AM   #12
Spacemen Tree
Human being with feelings
 
Spacemen Tree's Avatar
 
Join Date: Mar 2013
Posts: 484
Default

Made some small corrections/ alterations to the code. Also, added a version of the JS-fx with a simple slider instead of a dropdown list for CC, if like me you dont need the CC info and don't want to scroll to get to higher CC numbers. Upped it to the stash: https://stash.reaper.fm/v/30982/MIDI%...Transposer.zip
__________________
"After silence, that which comes nearest to expressing the inexpressible is music", Aldous Huxley
Spacemen Tree is offline   Reply With Quote
Old 06-20-2017, 01:47 PM   #13
snooks
Human being with feelings
 
Join Date: Sep 2015
Posts: 1,451
Default

Quote:
Originally Posted by Spacemen Tree View Post
If you are feeling up to it could use an explanation (like draw me a picture type) of exactly how MIDI bytes and all that work.
What exactly is unclear and I'll happily fill in the blanks?
snooks 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 04:37 PM.


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