diff --git a/src/droplets/ad_droplet.cpp b/src/droplets/ad_droplet.cpp
new file mode 100644
index 0000000..f69678c
--- /dev/null
+++ b/src/droplets/ad_droplet.cpp
@@ -0,0 +1,94 @@
+#include "ad_droplet.h"
+
+void AD::Init(DaisyPatch* m_patch,
+	      float sample_rate,
+	      AnalogControl attack_knob,
+	      AnalogControl decay_knob) {
+    patch = m_patch;
+    env.Init(sample_rate);
+    env.SetMax(1.0f);
+    env.SetMin(0.0f);
+    env.SetCurve(0.0f);
+    attack_param.Init(attack_knob, .01f, 3.0f, Parameter::EXPONENTIAL);
+    decay_param.Init(decay_knob, .01f, 3.0f, Parameter::EXPONENTIAL);
+  }
+
+void AD::Process(DacHandle::Channel chn,
+		 DaisyPatch::GateInput gate) {
+  if(patch->gate_input[gate].Trig()) {
+    env.Trigger();
+  }
+
+  env.SetTime(ADENV_SEG_ATTACK, attack_param.Process());
+  env.SetTime(ADENV_SEG_DECAY, decay_param.Process());
+  
+  sig = env.Process();
+  patch->seed.dac.WriteValue(chn,
+			     sig * 4095.0f);
+}
+
+float AD::GetSignal() {
+  return sig;
+}
+
+ADDroplet::ADDroplet(DaisyPatch* m_patch,
+		       DropletState m_state,
+		       float sample_rate) :
+  Droplet(m_patch,
+	  m_state) {
+  switch (GetState()) {
+  default:
+  case DropletState::kFull:
+    ad[0].Init(Patch(),
+		sample_rate,
+		Patch()->controls[Patch()->CTRL_1],
+		Patch()->controls[Patch()->CTRL_2]);
+    ad[1].Init(Patch(),
+		sample_rate,
+		Patch()->controls[Patch()->CTRL_3],
+		Patch()->controls[Patch()->CTRL_4]);
+    break;
+  case DropletState::kLeft:
+    ad[0].Init(Patch(),
+		sample_rate,
+		Patch()->controls[Patch()->CTRL_1],
+		Patch()->controls[Patch()->CTRL_2]);
+    break;
+  case DropletState::kRight:
+    ad[0].Init(Patch(),
+		sample_rate,
+		Patch()->controls[Patch()->CTRL_3],
+		Patch()->controls[Patch()->CTRL_4]);
+    break;
+  }
+}
+
+ADDroplet::~ADDroplet() {}
+
+void ADDroplet::Control() {}
+
+void ADDroplet::Process(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size) {
+  Patch()->ProcessAnalogControls();
+
+  for(size_t i = 0; i < size; i++) {
+    if (GetState() == DropletState::kRight) {
+      ad[0].Process(DacHandle::Channel::TWO, DaisyPatch::GATE_IN_2);
+    } else {
+      ad[0].Process(DacHandle::Channel::ONE, DaisyPatch::GATE_IN_1);
+    }
+    if (GetState() == DropletState::kFull) {
+      ad[1].Process(DacHandle::Channel::TWO, DaisyPatch::GATE_IN_2);
+    }
+    int env_sel = 0;
+    for (size_t chn = GetChannelMin(); chn < GetChannelMax(); chn++) {
+      if(GetState() == DropletState::kFull && chn > 1) {
+	env_sel = 1;
+      }
+      out[chn][i] = in[chn][i] * ad[env_sel].GetSignal();
+    }
+  }
+}
+
+void ADDroplet::Draw() {
+  DrawName("AD");
+}
diff --git a/src/droplets/ad_droplet.h b/src/droplets/ad_droplet.h
new file mode 100644
index 0000000..7c08ead
--- /dev/null
+++ b/src/droplets/ad_droplet.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#ifndef CASCADE_DROPLETS_AD_DROPLET_H_
+#define CASCADE_DROPLETS_AD_DROPLET_H_
+
+#include "daisysp.h"
+#include "daisy_patch.h"
+
+#include "droplet.h"
+#include "../util.h"
+
+using namespace daisy;
+using namespace daisysp;
+
+class AD {
+private:
+  AdEnv         env;
+  Parameter     attack_param;
+  Parameter     decay_param;
+  Parameter     curve_param;
+  float         sig;
+  DaisyPatch*   patch;
+public:
+  void Init(DaisyPatch* m_patch,
+	    float samplerate,
+	    AnalogControl attackKnob,
+	    AnalogControl decaynob);
+
+  void Process(DacHandle::Channel chn, DaisyPatch::GateInput gate);
+
+  float GetSignal();
+};
+
+class ADDroplet: public Droplet {
+private:
+  AD ad[2];
+
+public:
+  /*
+   * Constructor for a AD droplet.
+   *
+   * @param m_patch pointer to patch
+   * @param m_state droplet position
+   */
+  ADDroplet(DaisyPatch* m_patch,
+	     DropletState m_state,
+	     float sample_rate);
+  
+  /*
+   * Destructor for vco droplet.
+   */
+  ~ADDroplet();
+
+  /*
+   * Processes user controls and inputs.
+   */
+  void Control();
+
+  /*
+   * Processes audio input and outputs.
+   *
+   * @param in the audio inputs for the patch
+   * @param out the audio outputs for the patch
+   * @param size the number of inputs and outputs
+   */
+  void Process(AudioHandle::InputBuffer in,
+	       AudioHandle::OutputBuffer out,
+	       size_t size);
+
+  /*
+   * Processes information to be shown on the display. 
+   */
+  void Draw();
+};
+
+#endif // CASCADE_DROPLETS_AD_DROPLET_H_
diff --git a/src/main.cpp b/src/main.cpp
index 4aefe8e..b838207 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -115,6 +115,10 @@ static void AudioThrough(AudioHandle::InputBuffer in,
 Droplet* GetDroplet(DropletState state) {
   switch(selected_menu->GetState()) {
   default:
+    case MenuState::kAD:
+    return new ADDroplet(&patch,
+			 state,
+			 sample_rate);
   case MenuState::kLFO:
     return new LFODroplet(&patch,
 			  state,
diff --git a/src/main.h b/src/main.h
index 39bbef4..795178d 100644
--- a/src/main.h
+++ b/src/main.h
@@ -12,6 +12,7 @@
 #include "menu.h"
 #include "droplets/droplet.h"
 #include "droplets/droplet_manager.h"
+#include "droplets/ad_droplet.h"
 #include "droplets/lfo_droplet.h"
 #include "droplets/mixer_droplet.h"
 #include "droplets/noise_droplet.h"
diff --git a/src/menu.cpp b/src/menu.cpp
index b6728d6..569825c 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -9,6 +9,7 @@ Menu::Menu(DaisyPatch* m_patch,
 
   head = new MenuItem(MenuState::kSplit, "Split");
   head->AddItemEnd(new MenuItem(MenuState::kChange, ""));
+  head->AddItemEnd(new MenuItem(MenuState::kAD, "AD"));
   head->AddItemEnd(new MenuItem(MenuState::kLFO, "LFO"));
   head->AddItemEnd(new MenuItem(MenuState::kMixer, "Mixer"));
   head->AddItemEnd(new MenuItem(MenuState::kNoise, "Noise"));
diff --git a/src/menu_item.h b/src/menu_item.h
index 2e29c60..22ccbdd 100644
--- a/src/menu_item.h
+++ b/src/menu_item.h
@@ -5,7 +5,7 @@
 
 #include <string>
 
-enum class MenuState {kSplit, kChange, kLFO, kMixer, kNoise, kVCA, kVCO};
+enum class MenuState {kSplit, kChange, kAD, kLFO, kMixer, kNoise, kVCA, kVCO};
 
 class MenuItem {
  private: