Get "Play from here" position (ticks?) in JavaScript

Hi,

Is there any way of fetching the “Play from here” position (in tick units?) in a JavaScript process? I would like to send the position in an OSC message when the play button of the transport is pressed.

Thanks,

Iain

Heya :slight_smile:

There are multiple “timing” information you can get from the JS process, through the “token” and “state” parameters.

“token” durations, dates, etc. are relative to this object’s parent time interval
“state” are the global things for the entire execution of the score

Check the documentation here: Javascript | score documentation ; all the properties should be listed a bit further in the page ; maybe some conversion is necessary to get the dates in the time base you are looking for.

See also this example:

Thanks a lot Jean-Michaël! I see that “token.date / 705600000;” in the “tick:” callback gives me that value that I’m after when “Play from here” is used. It seems though, that I need to delay the “start:” and the “resume:” callbacks by one tick (if I’m not mistaken). In the case of the “resume” callback, it uses the time value from the last pause and in the case of “start”, a “QMetaObject::invokeMethod and SLOT macro: No such method” error results.

Do you know how I might resolve this?

import Score 1.0
Script {
  ValueInlet { id: in1 }
  property var time: 0
  property int samples_since_beginning: 0
  property var logicalTime: 0

  tick: function(token, state) {
    if (typeof in1.value !== 'undefined') {
  logicalTime = token.date / 705600000;
  Device.write("Pi:/LogicalTime", logicalTime);
  //samples_since_beginning += state.buffer_size;
  //Device.write("Pi:/teste2", samples_since_beginning / 44100);  
    }
  }
  start: function() { 
    Device.write("Pi:/NewStart", logicalTime);
    console.log("This is Start");
   }
  stop: function() { console.log("I am called on stop"); 
  //out1.value = 0;
  }
  pause: function() { 
  console.log("Called on pause"); 
  }
  resume: function() { console.log("I am called on resume"); 
  Device.write("Pi:/Resume", logicalTime);
  }
}

Cheers

Edit: I tried a crude delay but this simply delays the problem by the defined time! :slight_smile:
Edit 2: Also tried setting a global flag to true in the start: and resume: callbacks, then placing an if statement in the tick: callback to read the “LogicalTime” node when true. I assumed that this would happen on the next tick. Unfortunately the result is the same, the updated value is that of the logical time at the the last pause.

Here are some steps to reproduce the problem. In Score there is a JavaScript process with the following code spanning the timeline and with a device “Pi” set up with two float child nodes: LogicalTime and test:

import Score 1.0
Script {
  property bool timeFlag: false 
  property var logicalTime: 0

 tick: function(token, state) {
  logicalTime = token.date / 705600;
  console.log(logicalTime);
  Device.write("Pi:/LogicalTime", logicalTime);
 
    if (timeFlag) {
        console.log("entering if");
        let timeVal = Device.read("Pi:/LogicalTime");
        Device.write("Pi:/test", timeVal); 
        timeFlag = false;   
        console.log("leaving if");
    }
  
  }
  
  start: function() { 
    console.log("This is Start");
    timeFlag = true;
 
   }
  stop: function() { 
  console.log("I am called on stop"); 
  //out1.value = 0;
  }
  pause: function() { 
  console.log("Called on pause"); 
  }
  resume: function() { 
  console.log("I am called on resume"); 
  timeFlag = true;
  }
}
  1. press play then shortly afterwards press pause.
  2. take note of the “LogicalTime” and “test” node values.
  3. go to the message log and clear it, if necessary.
  4. In the timeline, right click somewhere ahead of the play cursor selecting “Play from here”
  5. Press play again followed by pause or stop.

At the top of the message log, the first message, as expected, is “I am called on resume”. The second message is however “Warn: QMetaObject::InvokeMethod: No such method JS::Script_QML_2::transport(QVariant) (:0)”. After that is a debug console message with the LogicalTime in msec. And this is the correct value that should get set in the node “test”. It does not however. The value that is set is the value of LogicalTime noted in step 2 above, ie. the LogicalTime value at the pause rather than the value at the position marked with “Play from here”.

I’m sorry, the following code works, reading from the de logicalTime node was causing the problem:

import Score 1.0
Script {
  property bool timeFlag: false
  property var logicalTime: 0

 tick: function(token, state) {
  logicalTime = token.date / 705600;
 
    if (timeFlag) {
        Device.write("Pi:/test", logicalTime); 
        timeFlag = false; 
    }  
  }
  
  start: function() { 
    console.log("This is Start");
    timeFlag = true;
   }
  stop: function() { 
  console.log("I am called on stop"); 
  //out1.value = 0;
  }
  pause: function() { 
  console.log("Called on pause"); 
  }
  resume: function() { 
  console.log("I am called on resume"); 
  timeFlag = true;
  }
}

Edit. and this also solves things like “Play from here” being used while the transport is in motion (with the “test” node renamed “Start”:


import Score 1.0
Script {
  property bool timeFlag: false
  property var logicalTime: 0
  property var lastLogicalTime: 0

 tick: function(token, state) {
  logicalTime = token.date / 705600;
 
    if (timeFlag) {
        Device.write("Pi:/Start", logicalTime); 
        timeFlag = false; 
    }
    
  let diff = Math.abs(logicalTime - lastLogicalTime);
  if (diff > 20) { timeFlag = true; } 
  lastLogicalTime = logicalTime;
  }
  
  start: function() { 
    //console.log("This is Start");
    timeFlag = true;
 
   }
  stop: function() { 
  //console.log("I am called on stop"); 
  }
  pause: function() { 
  //Device.write("Pi:/Stop", 0); 
  }
  resume: function() { 
  timeFlag = true;
  }
}

But I have another question:

Is it possible to send and OSC message when the Pause button is pressed? Any messages written to a device in the pause callback seem only to get sent when Play is pressed again and the transport is moving.