Old 06-14-2017, 08:09 PM   #1
Spacemen Tree
Human being with feelings
 
Spacemen Tree's Avatar
 
Join Date: Mar 2013
Posts: 515
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: Krefeld, Germany
Posts: 14,770
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

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: 515
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: Krefeld, Germany
Posts: 14,770
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];
      
      
        
    );
);
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: 7,293
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: 12,107
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, 09:54 PM   #7
Spacemen Tree
Human being with feelings
 
Spacemen Tree's Avatar
 
Join Date: Mar 2013
Posts: 515
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   #8
Spacemen Tree
Human being with feelings
 
Spacemen Tree's Avatar
 
Join Date: Mar 2013
Posts: 515
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
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:10 PM.


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