       {
         const unsigned long elapsed = millis() - gate_time_;
 
-        bool loop = widget_save_->params.vals.loop > -1;
-        const int8_t loop_start = widget_save_->params.vals.loop % 3;
-        bool loop_reverse = widget_save_->params.vals.loop > 2;
-        unsigned long pointer = rate_to_ms(1);
+        bool loop = cached_params_.loop > -1;
+        const int8_t loop_start = cached_params_.loop % 3;
+        bool loop_reverse = cached_params_.loop > 2;
+        unsigned long pointer = rate_to_ms(1, true);
         uint8_t p = 0;
         bool reverse = false;
         int8_t repeat_count = 0;

          if (reverse)
          {
            // if we're pointed backward, add the current point's rate
            pointer += rate_to_ms(p);
          }
          else
          {
            // if we're pointed forward, add the next point's rate
            pointer += rate_to_ms(p + 1);
          }
        }

        if (pointer < elapsed)
        {
          // done looping, sustain at point 3
          cv_current_ = level_to_cv(3);
        }
        else
        {
          // linearly interpolate between current and next point
          const float cv_start = level_to_cv(p);
          const float cv_end = level_to_cv(reverse ? p - 1 : p + 1);
          const float remaining = (float)(pointer - elapsed) / (float)rate_to_ms(reverse ? p : p + 1);
          cv_current_ = cv_end + (cv_start - cv_end) * remaining;
        }
      }

    int8_t repeat;    // 0 = continuous, 1 - 7 = finite repeats
  };

  ParameterValues cached_params_;

  DUINO_WidgetContainer<3> * container_outer_;
  DUINO_WidgetContainer<2> * container_loop_repeat_;
  DUINO_WidgetContainer<8> * container_points_;
