       }
     }
 
-    if(display_changed)
-    {
-      display->display_all();
-      display_changed = false;
+    // display selected envelope
+    if(selected_env != last_selected_env)
+    {
+      last_selected_env = selected_env;
+      display->fill_rect(53, 55, 7, 9, DUINO_SSD1306::Inverse);
+      display->fill_rect(68, 55, 7, 9, DUINO_SSD1306::Inverse);
+      display->display(53, 74, 6, 7);
+    }
+
+    // display gate
+    if(gate != last_gate)
+    {
+      last_gate = gate;
+      if(gate)
+      {
+        display->draw_char(60, 25, 0x0D, DUINO_SSD1306::White);
+      }
+      else
+      {
+        display->fill_rect(60, 25, 5, 7, DUINO_SSD1306::Black);
+      }
+      display->display(60, 64, 3, 3);
     }
   }
 
  private:
+  void invert_current_selection()
+  {
+    if(saving)
+    {
+      display->fill_rect(121, 0, 7, 7, DUINO_SSD1306::Inverse);
+      display->display(121, 127, 0, 0);
+    }
+    else
+    {
+      display->fill_rect(11 * (selected % 4) + (selected > 3 ? 85 : 1), 55, 9, 9, DUINO_SSD1306::Inverse);
+      display->display(11 * (selected % 4) + (selected > 3 ? 85 : 1), 11 * (selected % 4) + (selected > 3 ? 93 : 9),
+          6, 7);
+    }
+    delay(1);  // FIXME: SSD1306 unstable without this (too many I2C txs too quickly?)
+  }
+
   uint8_t selected;
-  int8_t v[4], v_last[4];
-  bool display_changed;
   bool saving;
+  int8_t v[8], v_last[8];
+  uint8_t last_selected_env;
+  bool last_gate;
 };
 
 DU_ADSR_Function * function;

    else if(gate)
    {
      gate_time = millis()
          - (unsigned long)(-float(adsr_values.A) * log(1 - (cv_current / (ENV_PEAK * ENV_SATURATION))));
    }
  }

 private:
  unsigned long gate_time;
  unsigned long release_time;
  float cv_current;

      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
