       switch (selected % 4)
       {
         case 0:
-          adsr_values[e].A = uint16_t(widget_save_->params.vals.v[selected]) * 24;
+          adsr_values_[e].A = uint16_t(widget_save_->params.vals.v[selected]) * 24;
           break;
         case 1:
-          adsr_values[e].D = uint16_t(widget_save_->params.vals.v[selected]) * 24;
+          adsr_values_[e].D = uint16_t(widget_save_->params.vals.v[selected]) * 24;
           break;
         case 2:
-          adsr_values[e].S = (float(widget_save_->params.vals.v[selected]) / float(V_MAX)) * ENV_PEAK;
+          adsr_values_[e].S = (float(widget_save_->params.vals.v[selected]) / float(V_MAX)) * ENV_PEAK;
           break;
         case 3:
-          adsr_values[e].R = uint16_t(widget_save_->params.vals.v[selected]) * 24;
+          adsr_values_[e].R = uint16_t(widget_save_->params.vals.v[selected]) * 24;
           break;
       }
 


  void gate_callback()
  {
    gate = gt_read_debounce(DUINO_Function::GT3);
    if (gate)
    {
      retrigger = true;
    }
  }

  void switch_callback()
  {
    if (millis() - debounce > DEBOUNCE_MS)
    {
      selected_env++;
      selected_env %= 2;
      debounce = millis();
    }
  }



  virtual void function_loop()
  {
    if (retrigger_)
    {
      env_ = selected_env_;
      gate_time_ = 0;
      release_time_ = 0;
      retrigger_ = false;
    }

    if (gate_time_)
    {
      if (gate_)
      {
        uint16_t elapsed = millis() - gate_time_;
        if (elapsed < adsr_values_[env_].A)
        {
          // attack
          cv_current_ = ENV_PEAK * ENV_SATURATION * (1.0 - exp(-(float(elapsed) / float(adsr_values_[env_].A))));
        }
        else
        {
          // decay/sustain
          cv_current_ = adsr_values_[env_].S + (ENV_PEAK - adsr_values_[env_].S)
              * exp(ENV_DECAY_COEFF * (float(elapsed - adsr_values_[env_].A) / float(adsr_values_[env_].D)));
        }
      }
      else
      {
        if (release_time_)
        {
          uint16_t elapsed = millis() - release_time_;
          if(elapsed < adsr_values_[env_].R * ENV_RELEASE_HOLD)
          {
            // release
            cv_current_ = exp(ENV_RELEASE_COEFF * (float(elapsed) / float(adsr_values_[env_].R))) * cv_released_;
          }
          else
          {
            cv_current_ = 0.0;
            release_time_ = 0;
            gate_time_ = 0;
          }
        }
        else
        {
          release_time_ = millis();
          cv_released_ = cv_current_;
        }
      }

      cv_out(CO1, cv_current_);
      cv_out(CO3, cv_current_ / 2.0);
    }
    else if (gate_)
    {
      gate_time_ = millis()
          - (unsigned long)(-float(adsr_values_[env_].A) * log(1 - (cv_current_ / (ENV_PEAK * ENV_SATURATION))));
    }

    widget_loop();

    // display selected envelope
    if (selected_env_ != last_selected_env_)
    {
      last_selected_env_ = selected_env_;
      Display.fill_rect(53, 55, 7, 9, DUINO_SH1106::Inverse);
      Display.fill_rect(68, 55, 7, 9, DUINO_SH1106::Inverse);
      Display.display(53, 74, 6, 7);
    }

    // display gate
    if (gate_ != last_gate_)
    {
      last_gate_ = gate_;
      if (gate_)
      {
        Display.draw_bitmap_7(60, 25, icons, 0, DUINO_SH1106::White);
      }
