Cockos Incorporated Forums

Cockos Incorporated Forums (https://forum.cockos.com/index.php)
-   JSFX and ReaScript Discussion (https://forum.cockos.com/forumdisplay.php?f=3)
-   -   Could a spreadsheet action script be made? (https://forum.cockos.com/showthread.php?t=202979)

pipelineaudio 02-07-2018 04:02 PM

Could a spreadsheet action script be made?
 
I would love to see a script like this.

The second column, "Action to activate row" should be learnable,ideally, but assigning it would be ok.

Hopefully cells' contents could be copy and pastable.

Unfilled cells in columns 3 and 4 would be ignored

Cells in column 4 would be triggered when any other row is selected (might have to think about this last a bit, as you may want to use it to toggle on and off signal paths, but for now this should be good)

Oops, should probably have a column for name and comments

https://i.imgur.com/clPzklI.png

X-Raym 02-07-2018 06:18 PM

That is a very specific request, I dont see it that usable in the long run.

Anyway, what you can do is to use the Web Interface API, an HTML interactive table, and some JavaScript to wrap all that.

If you are patient, it may worth it. ^^

pipelineaudio 02-07-2018 06:44 PM

Trying to reduce the number of crazy macros it takes to make complicated switching setups in SWS Live Configs.

jico27 02-08-2018 05:01 PM

I like the idea! +1

pipelineaudio 02-17-2018 08:08 PM

Would this really have to be an extension instead?

mschnell 02-18-2018 01:27 AM

Supposedly an extension could be made (similar to LiveConfigs) that fires actions as a result of a single Reaper Action or Midi message received.

Unfortunately LiveConfigs can perform multiple activities but only fire a single action when entering and leaving a state (line).

Hence this extension at best could be an extended version of LiveConfigs.

I am considering to do a JSFX that works a bit like LiveConfigs, in that it is supposed to receive a Midi message to enter a "state" (similar to a line of a Spreadsheet) and sends out a bunch of Midi messages that are defined in that line when entering / leaving a stage.

Some of those Midi messages can now be routed down to the Control Path by MidiToReaControlPath and then be learned to Actions.

-Michael

pipelineaudio 02-18-2018 02:17 AM

Where exactly are the live configs files? Are they a dll or something?

mschnell 02-18-2018 04:22 AM

AFAI understand, LiveConfigs is an integral part of the SWS extension (supposedly residing in reaper_sws64.dll (or reaper_sws.dll) ) .

In fact I would be inclined to take on the task of being a maintainer for LiveConfigs (ands with that would be able to do an update as you requested), but as I can't just try to install the sources and compile test and release LiveConfigs, but need to install, compile, test and release the complete SWS extension, I don't dare to start with that.

-Michael

pipelineaudio 02-18-2018 02:08 PM

Man that sounds brutal!

I’m going to see if I can look inside a smaller extension and see just how insane they are

pipelineaudio 02-19-2018 11:03 PM

So this should really be an extension and not a script right?

mschnell 02-20-2018 07:49 AM

While of course an extension would provide the most desigh freedom (e.g. creating an editable "Spreadsheet view" like LiveConfig does, I suppose that for the purpose we have in mind, doing a JSFX that is configurable (e.g. by having it read a text file) and sends out Midi events and (via MidiToReaConptrolPath) have events learn those is a lot more easily doable.

-Michael

pipelineaudio 02-20-2018 12:21 PM

Jsfx can do that? It wouldn’t be as convenient as clicking in it and being able to pick commands from the command window though right? Or maybe you could copy command ids from the action window and paste them in...the assignment is part of the big deal to me, being able to tell it what action or cc you want to use to make it fire that row

mschnell 02-20-2018 01:28 PM

I suppose, as a proof of concept, tomorrow I'll try to draft a JSFX that reads "something" that denotes an Action a file and converts it to a CC to be sent down to trigger that action, when that CC reads some Midi messages or similar.

I understand that an Action can be learned to a CC# (and hopefully Midi channel, but not to the CC value). Am I right.

OTOH, I found that the action that triggers a "config" in LiveConfigs obviously comes with a "value",that denotes the row to be activated.

Does anybody know what happens to the CC value when an action is triggered by a CC # ? Is this value available in a script that is started by that action ?

-Michael

pipelineaudio 02-20-2018 01:45 PM

Quote:

Originally Posted by mschnell (Post 1957084)
I understand that an Action can be learned to a CC# (and hopefully Midi channel, but not to the CC value). Am I right.

I think this is true, I tried to confirm last night by assigning actions to different values of the same CC# and it said it was already mapped to another and couldn't.

mschnell 02-20-2018 02:05 PM

Quote:

Originally Posted by pipelineaudio (Post 1957097)
I think this is true, I tried to confirm last night by assigning actions to different values of the same CC# and it said it was already mapped to another and couldn't.

So where does the CC value go ??!!?? I don't believe it is just ignored.

-Michael

pipelineaudio 02-20-2018 02:43 PM

Quote:

Originally Posted by mschnell (Post 1957108)
So where does the CC value go ??!!?? I don't believe it is just ignored.

-Michael

I dont think it is either, since the same cc can both mute and unmute things for instance. I keep hammering Justin about it, but maybe we need to make a coherent, clean, specific thread in the feature request about it.

I would love to see something basically like this (though more "REAPERish" of course)

https://i.imgur.com/AQwpWB0.jpg?1

karbomusic 02-20-2018 03:21 PM

Quote:

Originally Posted by pipelineaudio (Post 1957097)
I think this is true, I tried to confirm last night by assigning actions to different values of the same CC# and it said it was already mapped to another and couldn't.

If you guys remember from the other thread where I mentioned there are scenarios where it will not warn - I'd have to look at my reply to remember how that happens.

pipelineaudio 02-20-2018 04:45 PM

Which thread? THis is all so exciting and so confusing at the same time

briandress 02-20-2018 05:11 PM

Quote:

Originally Posted by mschnell (Post 1957108)
So where does the CC value go ??!!?? I don't believe it is just ignored.

-Michael

so as far as i am aware CC comes in a specific format. I learned this from writing the arduino program for my midi controller.

when we write usbSendMidi command there are three values. CC control, CC Value, and Midi Channel

So reaper has 16 midi channels. and then there are 127 cc controls and each cc control has 127 cc values. right?

so I program the button to send the code. usbSendMidi (0,64,1) so this sends Midi Control Code 0 Value 64 on Midi Channel 1.

I think it is up to the specific software to decide which portion of that data it uses for its triggering.

briandress 02-20-2018 05:15 PM

Quote:

Originally Posted by pipelineaudio (Post 1957097)
I think this is true, I tried to confirm last night by assigning actions to different values of the same CC# and it said it was already mapped to another and couldn't.

This means that whatever is doing the mapping is only using the D1 value of the CC code. There is Data 1 and Data 2 in CC Data 1 is the control Code, which was mapped with your first value. You tried the same D1 but changed D2 and it wouldnt map because it was already taken.

pipelineaudio 02-20-2018 06:08 PM

its affected by the third byte value, but it won't let you assign the same second byte value to two things. I think...since it allows a cc for volume faders for example and responds correctly.

What we're talking about here is the very few (or very many) cases where reaper will not let you directly assign a midi value to it, but insists on learn only, and with no further parameter control over how it behaves.

This is worlds different than say the parameter automation, which gives you all sorts of control over what midi it uses and how it behaves (though still, I don't think quite enough)

karbomusic 02-20-2018 06:09 PM

Quote:

Originally Posted by pipelineaudio (Post 1957173)
Which thread? THis is all so exciting and so confusing at the same time

It was one of yours concerning MIDI or one you entered on the same subject.

karbomusic 02-21-2018 08:37 AM

Quote:

Originally Posted by pipelineaudio (Post 1957173)
Which thread? THis is all so exciting and so confusing at the same time


Here it is... It's the difference between learning a CC from a VST vs learning one from an action. Via action, it will complain/overwrite a previous action using the same CC. However, when using learn for VST FX, you can learn the same CC for as many params as you wish and control them all with the single CC. There is a twist to that, if you assign a CC to an action, forget about it, then assign the same CC to a VST param via learn, it will not complain but the VST param will not work because it is being intercepted by the CC tied to the previously learned action...

https://forum.cockos.com/showpost.ph...1&postcount=13

Quote:

It will, but it if you also assign the same CC to an action, that will override the plugin CC but you can assign the same CC to more than one plugin control so long as there are no bound actions involved. Action or no action is the key thing to remember here.

The only thing that denies or cares about duplicates, is duplicate key or CC bindings IN the actions window. Unless my very short test was flawed it's likely that the listener for MIDI attaches any matching actions first and if there is a match it runs the action and doesn't send the CC "down the line" and the plugin never sees it.

mschnell 02-21-2018 12:22 PM

Hmmm.

I don't even think it's an obvious or logical design decision that you can't learn a CC to multiple actions so that all of them would be fired when the CC is detected in the Control Path.

-Michael

karbomusic 02-21-2018 12:38 PM

It makes a lot of sense to write the original code that way because it is more rare to need multiple actions with the same CC when contrasted with the confusion it would cause users who were unaware. If use cases justify it down the road (such as pipe's need now) then it makes sense to revisit - my suggestion would be to simply throw the same warning it does now with an option to duplicate, overwrite, cancel.

However, what I described above isn't about multiple actions, it's about 1 action + 1 learned VST param which is a very similar but different issue.

briandress 02-21-2018 02:04 PM

Quote:

Originally Posted by karbomusic (Post 1957525)
It makes a lot of sense to write the original code that way because it is more rare to need multiple actions with the same CC when contrasted with the confusion it would cause users who were unaware. If use cases justify it down the road (such as pipe's need now) then it makes sense to revisit - my suggestion would be to simply throw the same warning it does now with an option to duplicate, overwrite, cancel.

However, what I described above isn't about multiple actions, it's about 1 action + 1 learned VST param which is a very similar but different issue.

so right now you cannot use the same CC code to turn off a VST and also have an action take place, basically?

karbomusic 02-21-2018 02:14 PM

Quote:

Originally Posted by briandress (Post 1957563)
so right now you cannot use the same CC code to turn off a VST and also have an action take place, basically?

I don't "think". It was just something I noticed when I was designing a small DIY controller over the last couple weeks. It wasn't something I personally needed, I had just been testing and couldn't understand why the VST param I just set wouldn't work, then realized I had set it to an action earlier.

I wouldn't discourage anyone from testing/confirming further to be sure since it wasn't something I put any time in, just noticed and moved on to finishing my work with testing my controller. Repro/test...

1. Assign an action to a controller knob via MIDI learn.
2. Now assign a VST parameter/knob to that same CC using MIDI learn.

#2 may not work if #1 is set if I didn't miss something which is possible.

briandress 02-21-2018 02:24 PM

Quote:

Originally Posted by karbomusic (Post 1957567)
I don't "think". It was just something I noticed when I was designing a small DIY controller over the last couple weeks. It wasn't something I personally needed, I had just been testing and couldn't understand why the VST param I just set wouldn't work, then realized I had set it to an action earlier.

I wouldn't discourage anyone from testing/confirming further to be sure since it wasn't something I put any time in, just noticed and moved on to finishing my work with testing my controller. Repro/test...

1. Assign an action to a controller knob via MIDI learn.
2. Now assign a VST parameter/knob to that same CC using MIDI learn.

#2 may not work if #1 is set if I didn't miss something which is possible.


gotcha. Im making a midi controller right now and im working with how i want the coding of the controller based on how reaper handles this switching.

The best I can come up with right now is having tracks loaded with "Presets" using Live Configs to switch them by using CC 0 values and then using the rest of CC 1-127 to switch VST parameters within individual tracks or "presets"

so the controller will default to sending banks of CC0 values but when one is selected will toggle to send CC s for VST parameters.

pipelineaudio 02-21-2018 02:39 PM

Oh yeah, shit....Karbo, meet Brian, he's making a midi controller too! Hopefully Justin lets us have a live forum section and we can really post some killer DIY's

mschnell 02-21-2018 02:43 PM

Quote:

Originally Posted by briandress (Post 1957569)
Im making a midi controller right now and im working with how i want the coding of the controller based on how reaper handles this switching.

Not really necessary. If you know how to do it. Recoding the midi-messages that come in from the controller is not hard at all.

-Michael

karbomusic 02-21-2018 02:55 PM

Ah nice! Welcome Brain. My small project is here, it's just a personal thing using an Arduino:

https://forum.cockos.com/showpost.ph...2&postcount=61

As far as the configs thing, I'm not familiar with it enough to know the answer. I have in the past emulated amp channel switching by placing VSTs then using MIDI CC to toggle the bypass state. For example, imagine two AMP sim VSTs... I assigned toggle bypass to both but set one of them enabled and one bypassed initially - thusly hitting the MIDI controller switch toggled both, effectively resulting in the equivalent of channel switching (think clean/dirty channels).

That's entirely possible because it uses the bypass CC on the actual sim, bypassing the restriction of the same CC we have in actions if that makes any sense. In reality, it looks like from within the actions window, Justin is just checking the list to see if another of the same CC exists then warns. What I don't know is if that causes other issues and that's why it exists or he did it as a safety feature for the user. I would suspect a little of both since an action triggered via CC doesn't seem to fall through to a VST CC but that's visibility I don't have to know for sure.

briandress 02-27-2018 12:31 PM

hows your testing going @pipelineaudio?

mschnell 02-27-2018 02:28 PM

Hi Pipe,
I did a preview release of a a "spreadsheet" or a kind of "Configs" JSFX. It's called "Midi CC Table".

The JSFX reads a file (the filename is selectable if multiple files are present). The file(s) must have a ".txt" extension and need to be located in a directory called "cc table" that needs to be located in the "Data" directory, which is right besides Reaper's "Effects" directory.

A sample file content is given below.

The file format is:
- Each line is associated with an incoming CC # (similar to LiveConfigs) (0, 1, 2, ...).
- Each line has up to 64 CC definitions which are separated by a blank (a "/" starts a comment up to the end of the line)
- empty lines are allowed, resulting in a nonexistent row that will not respond to it's input CC value.
- a CC definition can have two or three elements:
. - Midi Channel followed by a colon
. - CC #
. - CC value (optionally, if present separated by a "="), otherwise Zero is assumed)

The JSFX shows the first relevant rows of the table in it's graphic.

You can select an input channel and CC # by "sliders" (as usual).

The current functionality is, that it sends the CCs in the appropriate row whenever it receives an appropriate CC with this row number as it's value (similar as LiveConfigs).

Right now, we don't support a "State" (the number of the latest row that had been accessed and would be "selected").

I think the final version should additionally feature a set of CCs per row to be sent out when a row is left/deselected, and should not send out anything if the already selected row is accessed again. I suppose, with this, you can get rid of LiveConfigs in your setup.

If you want to fire actions (as stated in the original request), you need to use MidiToReaControlPath to send the CCs "down" into the guts of Reaper and "learn" your actions to the appropriate CCs.

Please test and let me know what you find !
Thanks,

Have fun !
-Michael

Code:

// Author: Michael Schnell,

desc:Midi CC Table

slider1:/cc table:none:CC Table
slider2:0<0,15,1{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}>MIDI Input Channel
slider3:1<0,127,1{0 Bank Sel M,1 Mod Wheel M,2 Breath M,3,4 Foot P M,5 Porta M,6 Data Entry M,7 Vol M,8 Balance M,9,10 Pan M,11 Expression M,12 Ctrl 1 M,13 Ctrl 2 M,14,15,16 GP Slider 1,17 GP Slider 2,18 GP Slider 3,19 GP Slider 4,20,21,22,23,24,25,26,27,28,29,30,31,32 Bank Sel L,33 Mod Wheel L,34 Breath L,35,36 Foot P L,37 Porta L,38 Data Entry L,39 Vol L,40 Balance L,41,42 Pan L,43 Expression L,44 Ctrl 1 L,45 Ctrl 2 L,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64 Hold P sw,65 Porta sw,66 Sustenuto sw,67 Soft P sw,68 Legato P sw,69 Hold 2 P sw,70 S.Variation,71 S.Timbre,72 S.Release,73 S.Attack,74 S.Brightness,75 S.Ctrl 6,76 S.Ctrl 7,77 S.Ctrl 8,78 S.Ctrl 9,79 S.Ctrl 10,80 GP B.1 sw,81 GP B.2 sw,82 GP B.3 sw,83 GP B.4 sw,84,85,86,87,88,89,90,91 Effects Lv,92 Trem Lv,93 Chorus Lv,94 Celeste Lv,95 Phaser Lv,96 Data B. Inc,97 Data B. Dec,98 NRP L,99 NRP M,100 RP L,101 RP M,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>CC Input

@init

//FUNCTIONS for reading .txt files
//offset = starting string number
//returns number of lines read

cols  = 64;
cols3 = cols*3;
//cc_nr_i  = 0*rows;
//cc_val_i = 1*rows;

ssb = 0;            // Spread sheet base


function slider_file_to_numbered_strings(slidernumber,offset)local(handle,lastvalue,lines)
//USE ONLY THE NUMBER OF THE SLIDER FOR "slidernumber"  - do not use "sliderx"
(

  slider(slidernumber) != lastvalue ? reload=0;
 
  !reload ? (
    handle=file_open(slider(slidernumber));
    file_string(handle,offset); 
    while( strlen(offset) && offset < 1023 )
      ( offset+=1;
        file_string(handle,offset);     
      );
    file_close(file);
    lines=offset;
    lastvalue=slider(slidernumber);
    reload=1;
  );
  lines;
);
 
@slider
  inChannel  = slider2;
  modcc      = slider3;

  lines = slider_file_to_numbered_strings(1, 0);

  row = 0;
  loop(lines,
    #s = strcpy(#, row);
    o  = 0;
    col = 0;
    cc  = -1;
    l  = strlen(#s);
    src = ssb + row*cols3+ col*3;
    src[0] = -1;
    while (o < l) (
      c = '0';
      j = 0;
      while ((c >= '0') && (c <= '9')) (
        j *= 10;
        j += c-'0';
        c = str_getchar(#s, o, 'c');
        o += 1;
      ); 
      c == ':' ? (                          // Channel
        src[0] = j-1;
//        ___0 = j;
      ) : c == '=' ? (                      // CC #
        src[1] = j;     
        cc = j;
//        ___1 = j;
      ) : (c == ' ') || (c == 13) || (c == '/') ? (      // Value
        cc >= 0 ? (
          src[2] = j;
//          ___2 = j;
        ) : (
          src[1] = j;
//          ___1 = j;
          src[2] = 0;
//          ___2 = 0;
        ); 
        col += 1;
        cc = -1;
        src = ssb + row*cols3+ col*3;
        src[0] = -1;
      ); 
    );
    row+=1;
  );

@block
  while (midirecv(offset, msg1, msg2, msg3)) (
    status = msg1 & $xF0;      // Extract message type
    channel = msg1 & $x0F;
    channel == inChannel ? (  // Is it on our channel?
      status == $xB0 ? (      // Is it a controller event?
        msg2 == modcc ? (      // Is it the right CC?
          ci = msg3;
          ci < row ? (
            cj  = 0;
            coli = ci * cols3;
            src = ssb + coli /*+ cj*3*/;
            while (src[0] >= 0) (
              midisend(offset, $xB0+src[0],  src[1],  src[2]);
              cj += 1;
//            src = ssb + coli + cj*3;
              src += 3;
            ); 
          );
        );
      );
    );         
    midisend(offset, msg1, msg2, msg3); // pass through
  );
 
@gfx 650 450 
  //display file
  gfx_r=gfx_g=gfx_b=0; gfx_a=1;
  gfx_x=gfx_y=0;
  gfx_rectto(gfx_w,gfx_h);
 
  gfx_setfont(2, Ariel,18);
  gfx_r=1;gfx_g=gfx_b=1;
  xx=10;
  yy=10;
  gfx_x=xx;gfx_y=yy;
  i=0;
  loop ( row,
    #t = sprintf(#, "%d >> ", i);
    j = 0;
    srb = ssb + i*cols3 /*+ j*3*/;
    while (srb[0] >= 0) (
      #s = sprintf(#, "%d:%d=%d  ", srb[0]+1, srb[1], srb[2]);
      #t += #s;
      j += 1;
//    srb = ssb + i*cols3 + j*3;
      srb += 3;
    ); 
    ssb[i*cols3 /* + 0*3 + 0 */  ] >= 0 ? (
      gfx_drawstr(#t);
      gfx_x=xx;
      gfx_y+=gfx_texth+3;
    ); 
    i+=1;
  );

Code:

1:1=1 1:1=2  // CC # 0
2:2=2
// CC #2 empty
3:3=1 3:3=2 3:3=3 3:3=4
7:7=1 7:7=2 7:7=3 7:7=4 7:7=5 7:7=6 7:7=7 7:7=8


pipelineaudio 02-27-2018 02:48 PM

allll right!

I'll be trying this today as time allows, awesome!

pipelineaudio 02-27-2018 08:09 PM

I'm not exactly sure how to fill out the lines

mschnell 02-27-2018 10:42 PM

I'm not exactly sure what you are asking.

I suppose you are able to use a text editor to create an appropriate file :) .


Have you been able to make the JSFX show the content of the example file ?


Do you mean the syntax ?

The example shows how to define the elements in a line. e.g. the two elements in the first line mean:

When a CC (with correct input channel and CC #) with value 0 is detected, send out CC #1 with value 1 on channel 1, and then CC#1 on channel 1 with value 2.

Of you just want to trigger actions, (AFAIK) the CC value is ignored by "learn", and hence not necessary to be written in the fileThe JSFX will assume 0 in that case.. Syntax just 3:4 -> CC# 4 on channel 3 with value 0.


Or do you mean the purpose / usage ?

I am not fluent with "learning" actions. Maybe you need to do second file that just sends out single CCs for dong the "learning" of different CC#s to dedicated actions.

Once that done, you have a list of CC#s with associated actions and from this you can construct a file that sends out multiple CCs per "row" and hence will trigger multiple actions when receiving a single CC message.

-Michael

pipelineaudio 02-28-2018 12:10 AM

Just the syntax, I'll try it again, I think I understand it better now

mschnell 02-28-2018 12:48 AM

I improved the messages above...
-Michael

mschnell 02-28-2018 10:39 AM

New version.
You now can select either the "Map" or the "Configs" mode.

In "Map" mode the CCs denoted in a row are sent out whenever a CC that points to that row is received.

In "Configs" mode an incoming CC selects a row. The sected Row is highlighted in the graph. Only if the selection is changed the JSFX will send out the appropriate "activate" CCs of the newly selected row. Moreover before that, it will send out the "deactivate" CCs for the formerly selected row. (This works similar as SWS LiveConfigs.)

To support the "Configs" Mode, an additional key-character is introduced in the table file: "<" as a seperatopr (instead of blank) starts the definition of "deactivate" CCs.

An example file see below.

-Michael

Code:

// Author: Michael Schnell,

desc:Midi CC Table

slider1:/cc table:none:CC Table
slider2:0<0,1,1{Map,Configs}>Function
slider3:0<0,15,1{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}>MIDI Input Channel
slider4:1<0,127,1{0 Bank Sel M,1 Mod Wheel M,2 Breath M,3,4 Foot P M,5 Porta M,6 Data Entry M,7 Vol M,8 Balance M,9,10 Pan M,11 Expression M,12 Ctrl 1 M,13 Ctrl 2 M,14,15,16 GP Slider 1,17 GP Slider 2,18 GP Slider 3,19 GP Slider 4,20,21,22,23,24,25,26,27,28,29,30,31,32 Bank Sel L,33 Mod Wheel L,34 Breath L,35,36 Foot P L,37 Porta L,38 Data Entry L,39 Vol L,40 Balance L,41,42 Pan L,43 Expression L,44 Ctrl 1 L,45 Ctrl 2 L,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64 Hold P sw,65 Porta sw,66 Sustenuto sw,67 Soft P sw,68 Legato P sw,69 Hold 2 P sw,70 S.Variation,71 S.Timbre,72 S.Release,73 S.Attack,74 S.Brightness,75 S.Ctrl 6,76 S.Ctrl 7,77 S.Ctrl 8,78 S.Ctrl 9,79 S.Ctrl 10,80 GP B.1 sw,81 GP B.2 sw,82 GP B.3 sw,83 GP B.4 sw,84,85,86,87,88,89,90,91 Effects Lv,92 Trem Lv,93 Chorus Lv,94 Celeste Lv,95 Phaser Lv,96 Data B. Inc,97 Data B. Dec,98 NRP L,99 NRP M,100 RP L,101 RP M,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}>CC Input

@init

//FUNCTIONS for reading .txt files
//offset = starting string number
//returns number of lines read

cols  = 32;
cols3  = cols*3;
cols23 = cols3*2;
//cc_nr_i  = 0*rows;
//cc_val_i = 1*rows;

ssb = 0;            // Spread sheet base


function slider_file_to_numbered_strings(slidernumber,offset)local(handle,lastvalue,lines)
//USE ONLY THE NUMBER OF THE SLIDER FOR "slidernumber"  - do not use "sliderx"
(

  slider(slidernumber) != lastvalue ? reload=0;
 
  !reload ? (
    handle=file_open(slider(slidernumber));
    file_string(handle,offset); 
    while( strlen(offset) && offset < 1023 )
      ( offset+=1;
        file_string(handle,offset);     
      );
    file_close(file);
    lines=offset;
    lastvalue=slider(slidernumber);
    reload=1;
  );
  lines;
);
 
@slider
  conf        = slider2;
  inChannel  = slider3;
  modcc      = slider4;
 
  act = -1;
  pre = -1;

  lines = slider_file_to_numbered_strings(1, 0);

  row = 0;
  loop(lines,
    #s = strcpy(#, row);
    o  = 0;
    col = 0;
    cc  = -1;
    l  = strlen(#s);
    src = ssb + row*cols23 + col*3;
    src[0]    = -1;
    src[cols3] = -1;
    while (o < l) (
      c = '0';
      j = 0;
      while ((c >= '0') && (c <= '9')) (
        j *= 10;
        j += c-'0';
        c = str_getchar(#s, o, 'c');
        o += 1;
      ); 
      c == ':' ? (                          // Channel
        src[0] = j-1;
//        ___0 = j;
      ) : c == '=' ? (                      // CC #
        src[1] = j;     
        cc = j;
//        ___1 = j;
      ) : (c == ' ') || (c == 13) || (c == '<') || (c == '/' || (o > l) )? (      // Value
        cc >= 0 ? (
          src[2] = j;
//          ___2 = j;
        ) : (
          src[1] = j;
//          ___1 = j;
          src[2] = 0;
//          ___2 = 0;
        ); 
        col += 1;
        cc = -1;
        src = ssb + row*cols23 + col*3;
//        ___s = src;
        src[0] = -1;
        c == '/' ? o = 999;              // abort line
        c == '<' ? (
          col = cols;                    // go on in this row
          src = ssb + row*cols23 + col*3; 
//          ___s1 = src;
//          c = '0';
//          j = 0;
//          src[0] = -1;     
        );
      ); 
    );
    row+=1;
  );
//  ___n  = 5*cols23;
//  ___x  = ssb[___n];
//  ___n1 = 5*cols23 + cols3;
//  ___x1 = ssb[___n1];
//  ___n2 = 5*cols23 + cols3 + 1;
//  ___x2 = ssb[___n2];
   

@block
  while (midirecv(offset, msg1, msg2, msg3)) (
    status = msg1 & $xF0;      // Extract message type
    channel = msg1 & $x0F;
    channel == inChannel ? (  // Is it on our channel?
      status == $xB0 ? (      // Is it a controller event?
        msg2 == modcc ? (      // Is it the right CC?
          ci = msg3;
          ci < row ? (
            conf ? (
              act = ci;
            ); 
            act != pre ? (
              conf ? (
                cj  = 0;
                coli = pre * cols23 + cols3;
                src = ssb + coli /*+ cj*3*/;
                while (src[0] >= 0) (
                  midisend(offset, $xB0+src[0],  src[1],  src[2]);
                  cj += 1;
                  src += 3;
                );
              ); 
              cj  = 0;
              coli = ci * cols23;
              src = ssb + coli /*+ cj*3*/;
              while (src[0] >= 0) (
                midisend(offset, $xB0+src[0],  src[1],  src[2]);
                cj += 1;
                src += 3;
              );
              pre = act;
            ); 
          );
        );
      );
    );         
    midisend(offset, msg1, msg2, msg3); // pass through
  );
 
@gfx 650 450 
  //display file
  gfx_r=gfx_g=gfx_b=0; gfx_a=1;
  gfx_x=gfx_y=0;
  gfx_rectto(gfx_w,gfx_h);
 
  gfx_setfont(2, Ariel,18);
  gfx_r=1;gfx_g=gfx_b=1;
  xx=10;
  yy=10;
  gfx_x=xx;gfx_y=yy;
  i=0;
  loop ( row,
    #t = sprintf(#, "%d >> ", i);
    j = 0;
    srb = ssb + i*cols23 /*+ j*3*/;
    while ((srb[0] >= 0) && (j < cols)) (
      #s = sprintf(#, "%d:%d=%d  ", srb[0]+1, srb[1], srb[2]);
      #t += #s;
      j += 1;
//    srb = ssb + i*cols3 + j*3;
      srb += 3;
    ); 
    j = 0;
    srb = ssb + i*cols23 + cols3;
    srb[0] >= 0 ? #t += " << ";
   
    while ((srb[0] >= 0) && (j < cols)) (
      #s = sprintf(#, "%d:%d=%d  ", srb[0]+1, srb[1], srb[2]);
      #t += #s;
      j += 1;
//    srb = ssb + i*cols3 + j*3;
      srb += 3;
    ); 
   
    ssb[i*cols23 /* + 0*3 + 0 */  ] >= 0 ? (
      i == act ? (
        gfx_r=1;gfx_g=1;gfx_b=0;
      ) : (
        gfx_r=0.7;gfx_g=0.7;gfx_b=0.7;
      );
      gfx_drawstr(#t);
      gfx_x=xx;
      gfx_y+=gfx_texth+3;
    ); 
    i+=1;
  );

example table file:
Code:

1:1=1 1:1=2  // CC # 0
2:2=2
// CC #2 empty
// 4
3:3=1 3:3=2 3:3=3 3:3=4<10:11
7:7=1 7:7=2 7:7=3 7:7=4 7:7=5 7:7=6 7:7=7 7:7=8<9:9=9 10:11=127


mschnell 02-28-2018 11:47 AM

BTW.:

If you want to learn a dedicated CC # to an action you might want to use the "Midi CC LFO Generator". If sends out an infinite series of CCs with dedicated Channel,CC#, and (if you want to) CC value.

-Michael


All times are GMT -7. The time now is 11:57 PM.

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