Jump to content

TIP: Detect Transport state change


Recommended Posts

Scripter does not have any kind of callback to detect play and stop of the transport. You can detect whether it is currently playing or not, but you can't detect the moment that state changes in case you want some actions to happen just once when they first hit PLAY and something else one time when they first hit STOP.

 

This can make it a little difficult to handle certain things that need to happen at those times... Here is a method to handle that. If nothing else a learning experience...

 

Note - in the following code examples, I have added some buffered logging because without it, Scripter's tracing will exceed the limits of Scripter and drop some of them messages. So each of the following examples needs the following bit of code added to the end for it to properly display console.log messages. Also be advised that the console.log messages will take longer to get to the window, there may be some delay until all the messages flush to the window. So anyway, for each of the following examples, make sure this extra bit of code is tacked onto the end of each script if you are wanting to try these examples:

/********************
* buffered logging
********************/
var console = {
   maxFlush: 20,
   b:[],
   log: function(msg) {this.b.push(msg)},
   flush: function() {
       var i=0;
       while(i<=this.maxFlush && this.b.length>0) {
           Trace(this.b.shift());
           i++;
       }
   }
};
function Idle() {
   console.flush();
}

 

Now on to the explanation.....

 

  1. Scripter's TimingInfo object contains a flag letting you know if LogicPro is currently playing or not.
     
    var NeedsTimingInfo=true;
    
    function ProcessMIDI() {
       
       var info = GetTimingInfo();
       
       if (info.playing == true) {
           console.log("Playing at "+ info.blockStartBeat);
       }
       else {
           console.log("Stopped at "+ info.blockStartBeat);
       }
    }
    


     
     

  2. The above will tell you what LogicPro is currently doing, but we don't get any kind of indication immediately at the time the transport is started or stopped with PLAY or STOP. This means that during HandleMIDI() or ProcessMIDI() we can make decisions differently if its stopped or playing.. However, if we have certain stuff that needs to happen at the moment it starts playing, or the moment it is stopped... There is no easy way to catch that.
     
     
  3. You can keep track of things a little bit and detect this. For example:
     
    var NeedsTimingInfo=true;
    
    var isPlaying=false;
    
    function ProcessMIDI() {
       
       var info = GetTimingInfo();
       
       if (info.playing == true) {
       
           if(isPlaying==false) {
               console.log("== Recently started playing ==");
               isPlaying=true; 
           }
           else {
               console.log("still playing at " + info.blockStartBeat);
           }
       }
       else {
       
           if(isPlaying==true) {
               console.log("== Recently stopped ==");
               isPlaying = false;
           }
           else {
               console.log("Still Stopped at " + info.blockStartBeat);
           }
       }
    }
    


     
     

  4. The above works pretty good and you can put code into the appropriate place above to excecute at the moment the Transport is first started or stopped. However there is still a problem with this code. For one thing the GetTimingInfo function is a very expensive function in Scripter, it uses quite a lot of CPU, particularly with low buffer settings. This is especially stupid when the transport is stopped, during which time its unlikely you need to call GetTimingInfo and churn the CPU. Look how much its churning the CPU, you can watch the Trace log and see its way too much happening doing nothing, even while stopped.
     
     
  5. What is better is to avoid the calls to GetTimingInfo or any unnecessary things from happening if we can determine that the current state is stopped/playing without having to actually look at GetTimingInfo. And we sort of can. We can use an additional state variable in combination with the Reset() callback function. It turns out the Reset() function is called every time you hit PLAY. So that's nice.. Let's use it. When Reset() is called we will set the state of that variable to true, and whenever we detect through GetTimingInfo that the transport is stopped, we'll set it back to false. This way, we can avoid calling GetTimingInfo while not playing! Unfortunately, while it actually is playing we still will have to call the expensive GetTimingInfo in order to keep an eye out for if it has been stopped:
     
     
    var NeedsTimingInfo=true;
    
    var isPlaying=false;
    var started=true;
    
    function ProcessMIDI() {
       
       if(started == false) return;
       
       var info = GetTimingInfo();
       
       if (info.playing == true) {
       
           if(isPlaying==false) {
               console.log("== Recently started playing ==");
               isPlaying=true; 
           }
           else {
               console.log("still playing at " + info.blockStartBeat);
           }
       }
       else {
       
           if(isPlaying==true) {
               console.log("== Recently stopped ==");
               isPlaying = false;
           }
           else {
               console.log("Still Stopped at " + info.blockStartBeat);
           }
           started=false;
       }
    }
    
    function Reset() {
       started=true;
    }
    


     
     

  6. The above works pretty darn well for 99% of the time. One more situation to deal with which is that if the transport is already running when you hit Run Script....then the Reset() function won't get called to let your script know until you STOP and restart the transport. Admittedly in most working situations you won't be doing this once the script is done being coded. However, its worth pointing this out for the sake of learning. If you want the script to be able to detect it is playing in the rare case that you reload the script while the transport is already playing, then you have to add this extra level of complexity which is to detect "bootstrap" mode. Boot strap is when the script is loading. So with this boot strap mode we can look for whether its already playing and get all the flags synced up with that fact, like this:
     
    var NeedsTimingInfo=true;
    
    var isPlaying=false;
    var started=false;
    var bootstrap=true;
    
    function ProcessMIDI() {
    
       // while loading script, check to see if transport is already playing
       if(bootstrap) {
           info = GetTimingInfo();
           if(info.playing) {
               console.log("== Transport was already playing when you loaded Script ==");
               started=true;
               isPlaying=true;
           }
           bootstrap=false;
       }
       
       if(started == false) return;
       
       var info = GetTimingInfo();
       
       if (info.playing == true) {
       
           if(isPlaying==false) {
               console.log("== Recently started playing ==");
               isPlaying=true; 
           }
           else {
               console.log("still playing at " + info.blockStartBeat);
           }
       }
       else {
       
           if(isPlaying==true) {
               console.log("== Recently stopped ==");
               isPlaying = false;
           }
           else {
               console.log("Still Stopped at " + info.blockStartBeat);
           }
           started=false;
       }
    }
    
    function Reset() {
       started=true;
    }
    

 

 

So there you go. Nobody said it would be easy. But if you are needing to detect the transport when it starts and stops, without using too much CPU while stopped, the above is how you can do it. If nothing else maybe the above will serve as a learning exercise about Scripter.

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...