Jump to content

Can I use Scripter Sliders as displays and if so, how ?


fuzzfilth
Go to solution Solved by ski,

Recommended Posts

Here's a simple example where there are two GUI controls... one's a slider, the other is a menu. They display in real time the velocity and pitch of incoming notes.

 

In the PluginParameters array, each parameter is an element (as with any other array), and the first element is numbered zero. To that effect, note the difference in the way the two SetParameter functions are programmed. The first one references the explicit number of first the PluginParameters element (0), the second one references the parameter by name.

 

You can also get GUI elements to display the value of any variable. Just make sure the parameter is programmed to display an appropriate minValue, maxValue and (most importantly) the correct numberOfSteps. From 0 - 1 is one step. From 0 - 127 is 127 steps, while 1 - 127 is 126 steps.

 

787190167_ScreenShot2019-01-01at12_54_31PM.png.4723e9a5b71019b374585582779233e1.png

var PluginParameters = [
{name: "Slider 1",
type: "lin",
defaultValue: 0,
minValue:0,
maxValue:127,
numberOfSteps: 127
},

{name: "Slider 2",
type: "menu",
defaultValue: 0,
minValue:0,
maxValue:127,
numberOfSteps: 127,
valueStrings: MIDI._noteNames
}
]


function HandleMIDI(e) {

if (e instanceof NoteOn) {

SetParameter(0,e.velocity);
SetParameter("Slider 2",e.pitch)

}
e.trace();
e.send();
}

Edited by ski
Link to comment
Share on other sites

Here's an example of how a GUI control can display the value of a variable. Here, variable "r" will be a random number from 1 to 10 that changes every time you play a key.

 

SetParameter(0,r);

 

But the result of reading that value in SetParameter doesn't just display the random number... Instead, it displays one of the "string variables" -- an array within the parameter definition element itself.

 

/* This Script uses artificial intelligence (in the
loosest sense of the term) to answer a variety of common 
Logic operational questions. Just ask your question
out loud. Then hold down any key for the answer.
*/

var PluginParameters = [
{name: "❓",
type: "Menu",
defaultValue: 0,
minValue:0,
maxValue:10,
numberOfSteps: 10,
valueStrings:["----",
"That should work. Maybe it's a bug?",
"Forget it. Save, quit, take the day off.",
"If you wanna do that, get ProTools.",
"It can be done, but it's complicated.",
"RTFM.",
"Dunno. Post about it on LPH.",
"Call D. Nahmani, 1-800-LPHELP!",
"You don't know how to do THAT?",
"I dunno, what do you think?",
"Are you sure you want to know?"]
}

]

var r, previous;

function HandleMIDI(e) {

if (e instanceof NoteOn) {

r = Math.ceil(Math.random()*10);
if (r == previous) {
	r = Math.ceil(Math.random()*10);
}
SetParameter(0,r);
previous = r;
}

if (e instanceof NoteOff) {
SetParameter(0,0);
}

e.trace();
e.send();
}

Edited by ski
Link to comment
Share on other sites

Cool!

 

+1 to what Dewdman said. In my scripts I always explicitly define whether a parameter is allowed to be automatable (or not). But I believe I read somewhere that all parameters are automatable by default.

 

There are two parameter attributes which I believe are undocumented: disableAutomation and readOnly. Here's a code snippet, where a slider is explicitly defined as being not automatable as well as read-only:

 

var PluginParameters = [
{name: "slider name",
type: "lin",
defaultValue: 5,
minValue:0,
maxValue:10,
numberOfSteps: 10,
disableAutomation: true,
readOnly: true
}

Link to comment
Share on other sites

Ok, so here's what I did with it:

 

To practice solid time and to monitor it as a drummer in clickless rehearsal- and live-situations, this is TempoMat. It takes the last ten Note Ons, interprets them as hits on 2 and 4 and displays the resulting tempos numerically and as a graph on the sliders.

 

http://www.birgit-obermaier.de/Media/tempomat.png

 

Here's the code:

 

var tempoX = [0,0,0,0,0,0,0,0,0,0,0]
var tempoZ = 0
var hit1 = 0
var hit2 = 0
var i = 0

function HandleMIDI(event) {
 if (event instanceof NoteOn) {
     
   hit1=hit2                                //capture the time stamps of two hits
   hit2=Date.now()                          //
   tempoZ = 120000/(hit2-hit1)              // 120000 divided by the time between both hits returns the played tempo if hits are on 2 and 4
 
   if (hit1>0 && tempoZ<220 && tempoZ>70){  // if two hits have been received and the resulting tempo is between 70 and 220, then
 
     for (i=10;i>1;i--){                    // do the following for the last 9 valid tempos, starting from the highest numbered array cell:
       tempoX[i]=tempoX[i-1]                // move the tempo value one position up in the array
       SetParameter(i.toString(),tempoX[i]) // set the slider accordingly
     }                                      // repeat these three lines until finished
     
     tempoX[1]=tempoZ;                      // write the newest tempo into the first array cell (cell 0 remains unused for counting convenience)
     SetParameter("1",tempoX[1])            // set the slider accordingly 
   }
 }
 event.send()
}

var PluginParameters = [{name:"1", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                       {name:"2", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                       {name:"3", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                       {name:"4", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                       {name:"5", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                       {name:"6", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                       {name:"7", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                       {name:"8", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                       {name:"9", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                       {name:"10", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220}];
                       
ResetParameterDefaults = true;

 

I might also implement a second, relative mode where hits with identical tempo locate the slider dead center and deviations from that locate it more left if slower and right if faster. This could be scaled to, say +/-10bpm from slowest to fastest to magnify small timing shifts.

 

It could do with far better screen efficiency, but apart from hiding the top section there is no way to actually scale and position the sliders and value boxes, right ?

Link to comment
Share on other sites

Pretty neat.

 

I don't understand exactly your last question?

 

A couple random ideas to throw out to you to try out or consider....

 

  1. SetParameter is a little bit expensive in terms of what it has to do. I would try to use the Idle() function for updating the GUI. When you define a function called Idle(), it will be called periodically but only when LPX is not in the middle of handling some other notes or doing other work it needs to do. So its a good time to do housekeeping tasks like updating the GUI. During HandleMIDI() what you want to do is just detect the notes, decide if you can calculate a tempo and if so, save it, set a flag and get out so Scripter and Logic can do other stuff for processing incoming midi . Then let Idle() update the GUI when it has a chance. Here's an example based your existing script:
     
    var tempoZ = 0
    var setTempo = 0
    var hit1 = 0
    var hit2 = 0
    var i = 0
    var dirtyFlg = false;
    
    function HandleMIDI(event) {
    
     if (event instanceof NoteOn) {
         
       hit1=hit2     
       hit2=Date.now()   
       tempoZ = 120000/(hit2-hit1) 
     
       if (!dirtyFlg && hit1>0 && tempoZ<220 && tempoZ>70){        
         dirtyFlg = true;
         setTempo = tempoZ;      
       }
     }
     event.send()
    }
    
    function Idle() {
     if(dirtyFlg) {
         for (var i=9;i>0;i--){                              
           SetParameter(i,GetParameter(i-1)) 
         }                                      
         SetParameter(0,setTempo)      
         dirtyFlg = false;
     }
    }
    
    var PluginParameters = [{name:"1", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                           {name:"2", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                           {name:"3", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                           {name:"4", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                           {name:"5", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                           {name:"6", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                           {name:"7", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                           {name:"8", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                           {name:"9", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220},
                           {name:"10", type:"lin", defaultValue:70, numberOfSteps:1500, minValue:70,maxValue:220}];
                           
    ResetParameterDefaults = true
    


     
     

  2. You could use TEXT type fields to avoid the sliders on the screen, not sure if you were asking that. But then to change them you don't use SetParameter, but rather you just change the PluginParameters[] to anything you want and call UpdatePluginParameters() to update the gui, which you can do during Idle also. Here is the above script modified that way, which avoids sliders... Just an alternative....not saying one way is better then the other. But I will say that SetParameter has underlying implications, it might call the ParameterChanged() function implicitly and its a little bit expensive. Also you can format the text name any way you want, rather then being limited to what the slider show can show. Or you could alternatively use a single item menu field to display the value and avoid seeing the slider, and still use SetParameter to do it that way. Anyway here is the example using the text label fields just to show how its possible.
     
    var tempoZ = 0
    var setTempo = 0
    var hit1 = 0
    var hit2 = 0
    var i = 0
    var dirtyFlg = false;
    
    function HandleMIDI(event) {
    
     if (event instanceof NoteOn) {
         
       hit1=hit2     
       hit2=Date.now()   
       tempoZ = 120000/(hit2-hit1) 
     
       if (!dirtyFlg && hit1>0 && tempoZ<220 && tempoZ>70){        
         dirtyFlg = true;
         setTempo = tempoZ;      
       }
     }
     event.send()
    }
    
    function Idle() {
     if(dirtyFlg) {
         for (var i=9;i>0;i--){
             PluginParameters[i].name = PluginParameters[i-1].name;                              
         }                                      
         PluginParameters[0].name = setTempo.toString();
         UpdatePluginParameters();
         dirtyFlg = false;
     }
    }
    
    var PluginParameters = [{name:"-", type:"text"},
                           {name:"-", type:"text", },
                           {name:"-", type:"text", },
                           {name:"-", type:"text", },
                           {name:"-", type:"text", },
                           {name:"-", type:"text", },
                           {name:"-", type:"text", },
                           {name:"-", type:"text", },
                           {name:"-", type:"text", },
                           {name:"-", type:"text", }];
                           
    ResetParameterDefaults = true
    


     

  3. It should be pointed out that Date.now() is a realtime function WHEN ITS CALLED and Scripter does not, strictly speaking, run in real time as the midi events come through. What I mean by that is that LPX calls the HandleMIDI() function at points of time it feels like, not exactly when the NoteOn comes. By the time HandleMIDI() has been called, some milliseconds of time have elapsed already since the actual NoteOn was detected, and that amount of time between the NoteOn and actually calling the HandleMIDI() function is not guaranteed at all to always be consistently the same.
     
    Its probably close enough to serve your purpose, but I think possibly a more accurate calculation might be obtained if you turn on timingInfo and compare the actual beatPos of each note and do some calculations based on that and use the host's current tempo as a reference to calculate the time difference between notes and calculate a real tempo from that. That way you're doing the calculation based on their actual timestamps of exactly when they occurred, without any regard to when LPX gets around to calling HandleMIDI(). I don't know, might be more complicated then its worth, but might be more accurate, technically speaking. If I get a minute tomorrow I'll try to make an example or you might figure it out before then.

Link to comment
Share on other sites

I don't find SetParameter expensive at all. OTOH, I find Idle() to be exactly that. It's called every 500 ms, and implementing will cause the Scripter GUI to become very laggy. At the very least it's unnerving to monitor.

 

I've also found UpdatePluginParameters to be very tricky to implement, because you can't just call it once and be done with it. It doesn't produce a one-time result as when using SetParameter or other routinely used function. If you call it once, you then have to prevent it from being called endlessly – which it will do unless you wrap it in a routine which ensures that it's only invoked once. BTW, I haven't really looked at your code to see if you're taking that into account or not. This is just my general commentary on the use of that function.

 

Just curious (as in "not meaning to start an argument, I'm actually curious") as to how you arrived at this conclusion when you wrote: "What I mean by that is that LPX calls the HandleMIDI() function at points of time it feels like, not exactly when the NoteOn comes."

Link to comment
Share on other sites

I don't find SetParameter expensive at all. OTOH, I find Idle() to be exactly that. It's called every 500 ms, and implementing will cause the Scripter GUI to become very laggy. At the very least it's unnerving to monitor.

 

The point is that Idle() happens when LPX doesn't need to process midi. LPX decides when it has some spare time to call it. When its "idle". Guess we disagree on that point, it suits this kind of situation perfectly. What may SEEM laggy is that the GUI doesn't always update right away, there can be a lag to when the GUI itself updates itself because LPX waits to call Idle() until its actually "idle". It doesn't have to wait that long usually, but this is a good thing because its staying out of the way of midi processing. If you don't like that little lag, then obviously don't use it that way, but if you want your script to process midi as efficiently as possible and prioritize that, that's how you keep the GUI stuff out of the way or anything else that doesn't have to respond to the midi right away, do it during Idle. Idle() itself is not any more burdensome to call then ProcessMIDI() is, its just doing it when LPX is idle, which is exactly a good time to call it and no problem at all, LPX is making sure to only call it when it doesn't need to do other things.

 

I've also found UpdatePluginParameters() to be very tricky to implement, because you can't just call it once and be done with it. It doesn't produce a one-time result as when using SetParameter or other routinely used function. If you call it once, you then have to prevent it from being called endlessly – which it will do unless you wrap it in a routine which ensures that it's only invoked once. BTW, I haven't really looked at your code to see if you're taking that into account or not. This is just my general commentary on the use of that function.

UpdatePluginParameters() does not call itself endlessly. You might be confusing it with the ParameterChanged() function which you do have to be careful with as it relates to SetParameter.. That is part of why SetParameter can be expensive. Also SetParameter is updating some internal data structures that holds the values for later lookup. So every call to SetParameter is doing that grunt work. Alternatively, when you change the contents of the PluginParameters[] array, no internal stuff happens at all, those updates are very quick, the only thing that finally does stuff is the UpdatePluginParameters() call, which essentially redraws the GUI. As I said before, I'm not saying one way is better or worse then the other, just pointing out some alternatives. There can be a place for both approaches.

 

UpdatePluginParameters() can be called to change the GUI any way you want. Hide/show fields, rearrange, relabel them, whatever you want. It doesn't cause the endless loop you are thinking of. That is what happens if you are not careful with the ParameterChanged() function, which relates to SetParameter() and part of the reason SetParameter can be expensive.

 

Just curious (as in "not meaning to start an argument, I'm actually curious") as to how you arrived at this conclusion when you wrote: "What I mean by that is that LPX calls the HandleMIDI() function at points of time it feels like, not exactly when the NoteOn comes."

 

This is the way all plugins work, including Scripter. midi comes in, its timestamped and LPX takes turns allowing plugins to process the incoming midi and update the audio buffer if applicable. When a midi plugin looks at midi, including midi that we could consider "live", its looking at it after LPX has already received that midi, timestamped it and placed it on a queue. LPX has lots of stuff its doing and Scripter has to wait until its turn. Scripter then says, "ok, my turn, what's on the queue?", and HandleMIDI() gets called so your script can do whatever it wants to that event, put it back on the queue, or not. Internally there is a timestamp, even when Scripter is not using NeedsTimingInfo. LPX then needs time to take that midi on the queue and potentially allow instrument audio plugins to render audio based on it, etc.. all of that happens during the latency period while it fills the audio buffer.

 

In any case, The point is, plugins do not process midi nor audio in actual real time. Yes its real time to our senses, but not in the way computer processing works. The midi comes in, its stamped, its placed on a queue, LPX is servicing a lot of stuff with however many cores you have and when it gets around to it, it finally will give Scripter a chance to read the queue and call HandleMIDI() to give your script as chance to make calculations and require the event or queue other events. Eventually LPX reads that queue and sends it externally or makes send through an instrument plugin. VERY MUCH NOT ACTUAL REAL TIME.

 

So at the time the script is actually running, which is some point of time after the midi event was received by LPX...that's when the Date.now() function is obtaining a timestamp. Its a later point in time then the actual midi event was received. A true calculation will use the event.beatPOS attribute to see the timestamp placed on the midi events more accurately by LPX...and make the calculation using those, rather then whatever millisecond in time when HandleMIDI happens to get called.

 

Of course, this may all be kind of anal, its possible that we are talking about 1 ms timing discrepancy, I don't really know. Maybe even less. Or maybe more. We don't really know because LPX does what it does, its not guaranteed to always be the same wait time until HandleMIDI is called. My experience has been that each processing block in scripter is roughly 1ms or so, but I have also found that its not always consistent, sometimes it skips some, etc.. 1ms is actually quite a long time in CPU processing timescale.

 

But still the only way to be absolutely sure the tempo calculation math is correct, it is better to use the beatPOS timestamps to calculate the gap between notes...not rely on calling Date.now() whenever Scripter gets around to it.

Link to comment
Share on other sites

Mmmm.... maybe we're going a little more than "just a bit off-piste" with this discussion. So I'll just say two things...

 

A) I'm not confusing the actions of the update parameters and parameter changed functions.

 

B) a great many of the behaviors you've described don't jibe at all with my experience working with Logic's Scripter. Like, not even close.

 

Go figure... 8-)

Link to comment
Share on other sites

Thanks guys for your thoughts.

 

I want the sliders because they give a good indication of how I'm doing at a quick glance, even in a live situation. I also like the number imdicators because they tell me the actual tempo. This gives me the opportunity to start a song without click and still bring in samples midway through the song. Usually you need to play the entire song to a click to pull that off. My qestion was if I can change the sliders' size and position, as I'd like them to be larger.

 

I am aware of the realtime issue. Feeding quantized 2 and 4 hits results in approx. one of 8 hits returning 119.998 instead of 120.0 like the others do. This will do nicely for me until my own precision can rival that...

Edited by fuzzfilth
Link to comment
Share on other sites

Here's a version that uses BeatPos, which will be more accurate. This is using the sliders as you prefer. Transport does NOT need to be playing for this to work.

 

var NeedsTimingInfo = true;

var setTempo = 0;
var hit1 = 0;
var hit2 = 0;
var i = 0;
var dirtyFlg = false;

function HandleMIDI(event) {

   if (event instanceof NoteOn) {

       var info = GetTimingInfo();
       var beatsPerSec = info.tempo / 60;

       hit1 = hit2;
       hit2 = (event.beatPos) / beatsPerSec * 1000; // convert to ms timestamp

       var tempoZ = 120000 / (hit2 - hit1);

       if (hit1 > 0 && tempoZ < 220 && tempoZ > 70) {
           dirtyFlg = true;
           setTempo = tempoZ;
       }
   }
   event.send();
}

function Idle() {
   if (dirtyFlg) {
       for (var i = 9; i > 0; i--) {
           SetParameter(i, GetParameter(i - 1));
       }
       SetParameter(0, setTempo);
       dirtyFlg = false;
   }
}

var PluginParameters = [{
       name: "1",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "2",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "3",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "4",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "5",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "6",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "7",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "8",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "9",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "10",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   }
];

ResetParameterDefaults = true;

 

Update: One downside of using event.beatPos to calculate the tempo more precisely, is that cycle modes are more complicated to handle. Here is a slight addition to the script that will correctly calculate the gap between notes and tempo, even when wrapping around in cycle mode

 

var NeedsTimingInfo = true;

var setTempo = 0;
var hit1 = 0;
var hit2 = 0;
var i = 0;
var dirtyFlg = false;

function HandleMIDI(event) {

   if (event instanceof NoteOn) {
   
       var info = GetTimingInfo();
       var beatsPerSec = info.tempo / 60;

       hit1 = hit2;
       hit2 = event.beatPos;
       
       // compute gap between notes in beats, handle cycle wrap around
       var deltaBeats = 0;
       if(info.cycling && hit1>hit2) {
           deltaBeats = (info.rightCycleBeat-hit1) + (hit2 - info.leftCycleBeat);
       }
       else {
           deltaBeats = hit2-hit1;
       }
       
       // Convert delta to ms timestamp and calculate tempo     
       var tempoZ = 120000 / (deltaBeats / beatsPerSec * 1000);

       if (tempoZ < 220 && tempoZ > 70) {
           dirtyFlg = true;
           setTempo = tempoZ;
       }
   }
   event.send();
}

function Idle() {
   if (dirtyFlg) {
       for (var i = 9; i > 0; i--) {
           SetParameter(i, GetParameter(i - 1));
       }
       SetParameter(0, setTempo);
       dirtyFlg = false;
   }
}

var PluginParameters = [{
       name: "1",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "2",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "3",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "4",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "5",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "6",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "7",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "8",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "9",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   },
   {
       name: "10",
       type: "lin",
       defaultValue: 70,
       numberOfSteps: 1500,
       minValue: 70,
       maxValue: 220
   }
];

ResetParameterDefaults = true;
Edited by Dewdman42
Link to comment
Share on other sites

...apart from hiding the top section there is no way to actually scale and position the sliders and value boxes, right ?

Having control over the appearance and layout of GUI controls is sorely lacking. The only thing you can do is change the order in which they (serially) appear.

 

About the only flexibility we have over the appearance of a control has to do with menus. They can take on the appearance of a checkbox, a pair of radio buttons, or a typical menu list.

Link to comment
Share on other sites

I'd love to see this whole system radically improved and extended throughout Logic. Not just improvements to the Scripter plugin, with GUI components and custom images (think like Kontakt's ability to create instruments), but also to incorporate the scripting environment into the actual environment, and the EXS24/Sampler system, to name a few...

 

I suspect though that the devs will likely think, like in a few areas in Logic, that what they've done is good enough for purpose, and move on to other things, only adding minor fixes and improvements going forward, and more or less leaving it alone otherwise...

Link to comment
Share on other sites

Some GUI improvements to Scripter would be interesting, but I think unlikely to happen, agreed. We should start a thread to put suggestions and ideas for improvements to Scripter. I have a few ideas myself.

 

I doubt the environment will ever gain the ability to host midi plugins. The main reason is because Plugins depend on latency compensation and having an audio buffer worth of time to do what they need to do, etc.. The current environment does not have any PDC technology and its coded highly efficiently to be as close to actual real time as possible. Some pretty fantastic changes to the LPX architecture would have to be done in order to support midi plugins, including Scripter, inside the environment. For the same reason I doubt Apple will ever make it possible to route the output from midi plugins back into the environment. It would open up a can of worms in terms of PDC and synchronization issues. I have been wishing for that for a long time too though. Other DAW's are able to send midi around and keep it all in sync, so its very unfortunate that LPX is not able to really do that without basically just throwing it out of sync into IAC and looping it around as a work around. which does work reasonably well in a non-sample accurate way.

 

But the environment is decades old code, probably written in a very very efficient manner. Very very efficient code from the old days is often very very hard to understand and very very risky to change. So on that front I'm not holding my breathe, LPX has evolved to where it is, based on the environment, and I don't think they are going to re-gut that part of Logic Pro pretty much ever.

Link to comment
Share on other sites

Well, it's not like the environment is a separate component. I think it would be fair to say that Logic is the environment, and that the environment is Logic.

 

As for improvements to the Scripter and whether we'll see improvements in the future... I guess it's fun to speculate. :wink:

Link to comment
Share on other sites

  • 4 months later...

Sooo. In the meantime, I took Tempomat as a starting point and developed it further into...drumroll...Tempomat 2.

 

Yeah, not totally visionary, I know. The scope this time is to return the current tempo from a live drummer and display it together with a reference or target tempo. All this in a stage-safe big and scalable display, yet with a small footprint so it does not waste any precious laptop screen estate.

 

Now, while I could perform all the calculations and stuff in Scripter, it has virtually zero GUI functionalities, so I had to abandon that. A quick stint with Reaktor got good initial results, but, again, I couldn't get the window small enough. Then I stumbled over JUCE which is kind of a front end for C++ to build audio plugins, among other stuff.

Ok, so an AU MIDI FX plugin written in C++ it is, then. Did I know C++ ? No, but having dabbled in BASIC when even I was young, got my feet wet in JavaScript just enough to be dangerous, and even managed to have Excel perform stunts which would have any accountant wet their panties over, so how hard can it be ?

Hard. It can. And it is. It took me three weeks to find out I had to use a . instead of a :: and all google searches only ever brought back something along the lines of “Oh, that’s easy, you just need to inflect a convoltation on the (mergoffled) backwibble in procrastic mode, but make sure you don’t overpledge the frobbleworth-constantation, its offlepoff conflictions can get nasty if you don’t frimbiffle them in abstract time before the grenforth gramblination runs out. But no worries, you can fix this with an easy grek or two.” This, to be honest, just made my eyes glaze over, if anything.

 

Anyway, now it's working and in use already.

 

t3.png.7b2db5aecf66a4b91efe15bbffc2a6f5.png

The top number is the current tempo, derived from the snare hits. The bottom is the target tempo which can be changed manually or via a CC message, so it's programmable per song or section. Simple and elegant, dare I say.

Next step is to teach it to detect and evaluate in-between ghost notes.

Edited by fuzzfilth
Link to comment
Share on other sites

Oh, that’s easy, you just need to inflect a convoltation on the (mergoffled) backwibble in procrastic mode, but make sure you don’t overpledge the frobbleworth-constantation, its offlepoff conflictions can get nasty if you don’t frimbiffle them in abstract time before the grenforth gramblination runs out. But no worries, you can fix this with an easy grek or two.

It's that easy huh? :mrgreen:

Link to comment
Share on other sites

Besides few words I didn't understand due to my limited English literacy, in the end, the whole thing did not made sense either...

But as long as it does for you, so you could pull something out of it, that's all that matters, right?

("This, to be honest, just made my eyes glaze over, if anything.")

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...