OSC: add /scrub function
authorLen Ovens <len@ovenwerks.net>
Mon, 1 May 2017 14:08:02 +0000 (07:08 -0700)
committerLen Ovens <len@ovenwerks.net>
Mon, 1 May 2017 14:08:02 +0000 (07:08 -0700)
libs/surfaces/osc/osc.cc
libs/surfaces/osc/osc.h

index 7e7adb819a4275e96607387f41002fa1821dcdcf..20d89edfe28c2b73a0820cfb71b917952505ce7f 100644 (file)
@@ -100,6 +100,7 @@ OSC::OSC (Session& s, uint32_t port)
        , default_gainmode (0)
        , tick (true)
        , bank_dirty (false)
+       , scrub_speed (0)
        , gui (0)
 {
        _instance = this;
@@ -421,6 +422,7 @@ OSC::register_callbacks()
                REGISTER_CALLBACK (serv, "/goto_start", "f", goto_start);
                REGISTER_CALLBACK (serv, "/goto_end", "", goto_end);
                REGISTER_CALLBACK (serv, "/goto_end", "f", goto_end);
+               REGISTER_CALLBACK (serv, "/scrub", "f", scrub);
                REGISTER_CALLBACK (serv, "/rewind", "", rewind);
                REGISTER_CALLBACK (serv, "/rewind", "f", rewind);
                REGISTER_CALLBACK (serv, "/ffwd", "", ffwd);
@@ -1749,6 +1751,52 @@ OSC::record_enabled (lo_message msg)
        lo_message_free (reply);
 }
 
+int
+OSC::scrub (float delta, lo_message msg)
+{
+       if (!session) return -1;
+
+       scrub_place = session->transport_frame ();
+
+       float speed;
+
+       boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
+       boost::posix_time::time_duration diff = now - scrub_time;
+       if (diff.total_milliseconds() > 35) {
+               // speed 1 (or 0 if jog wheel supports touch)
+               speed = delta;
+       } else if ((diff.total_milliseconds() > 20) && (fabs(scrub_speed) == 1)) {
+               // add some hysteresis to stop excess speed jumps
+               speed = delta;
+       } else {
+               speed = (int)(delta * 2);
+       }
+       scrub_time = now;
+       if (scrub_speed == speed) {
+               // Already at that speed no change
+               return 0;
+       }
+       scrub_speed = speed;
+
+       if (speed > 0) {
+               if (speed == 1) {
+                       session->request_transport_speed (.5);
+               } else {
+                       session->request_transport_speed (1);
+               }
+       } else if (speed < 0) {
+               if (speed == -1) {
+                       session->request_transport_speed (-.5);
+               } else {
+                       session->request_transport_speed (-1);
+               }
+       } else {
+               session->request_transport_speed (0);
+       }
+
+       return 0;
+}
+
 // master and monitor calls
 int
 OSC::master_set_gain (float dB)
@@ -3564,6 +3612,18 @@ OSC::periodic (void)
                }
        }
 
+       if (scrub_speed != 0) {
+               // for those jog wheels that don't have 0 on release (touch), time out.
+               boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
+               boost::posix_time::time_duration diff = now - scrub_time;
+               if (diff.total_milliseconds() > 100) {
+                       scrub_speed = 0;
+                       session->request_transport_speed (0);
+                       // locate to the place PH was at last tick
+                       session->request_locate (scrub_place, false);
+               }
+       }
+
        for (GlobalObservers::iterator x = global_observers.begin(); x != global_observers.end(); x++) {
 
                OSCGlobalObserver* go;
index bc612b0881fd6ab7ec8eaa388d89c23c3c5fa65e..2157b0e27840a6792df1a1e6a84b5bf994cbc7a7 100644 (file)
@@ -184,6 +184,9 @@ class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
        uint32_t default_gainmode;
        bool tick;
        bool bank_dirty;
+       float scrub_speed;                      // Current scrub speed
+       double scrub_place;                     // place of play head at latest jog/scrub wheel tick
+       boost::posix_time::ptime scrub_time;    // when did the wheel move last?
        bool global_init;
        boost::shared_ptr<ARDOUR::Stripable> _select;   // which stripable out of /surface/stripables is gui selected
 
@@ -371,6 +374,7 @@ class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
        // pan position needs message info to send feedback
        PATH_CALLBACK1_MSG(master_set_pan_stereo_position,f);
 
+       PATH_CALLBACK1_MSG(scrub,f);
        PATH_CALLBACK1_MSG(set_surface_bank_size,i);
        PATH_CALLBACK1_MSG(set_surface_strip_types,i);
        PATH_CALLBACK1_MSG(set_surface_feedback,i);
@@ -543,6 +547,7 @@ class OSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCUIRequest>
        int set_surface_gainmode (uint32_t gm, lo_message msg);
        int refresh_surface (lo_message msg);
 
+       int scrub (float delta, lo_message msg);
        int master_set_gain (float dB);
        int master_set_fader (float position);
        int master_set_trim (float dB);