diff --git a/frontends/sdl/src/main.rs b/frontends/sdl/src/main.rs
index 4dcb15e35a8bf98e919c8381840c1239cc30e998..40972d9bb3fac616891190e2cdfa6bc0ce268300 100644
--- a/frontends/sdl/src/main.rs
+++ b/frontends/sdl/src/main.rs
@@ -24,7 +24,7 @@ static TITLE: &str = "Boytacean";
 
 /// Base audio volume to be used as the basis of the
 /// amplification level of the volume
-static VOLUME: f32 = 100.0;
+static VOLUME: f32 = 40.0;
 
 pub struct Benchmark {
     count: usize,
diff --git a/src/apu.rs b/src/apu.rs
index e9f343bd11d99f0380b791fb0d9787ef2e58f952..5754345c1604ca3b08fd3f8654de8afece9ca597 100644
--- a/src/apu.rs
+++ b/src/apu.rs
@@ -17,6 +17,8 @@ pub enum Channel {
 pub struct Apu {
     ch1_timer: u16,
     ch1_sequence: u8,
+    ch1_envelope_sequence: u8,
+    ch1_envelope_enabled: bool,
     ch1_sweep_sequence: u8,
     ch1_output: u8,
     ch1_sweep_slope: u8,
@@ -28,11 +30,13 @@ pub struct Apu {
     ch1_direction: u8,
     ch1_volume: u8,
     ch1_wave_length: u16,
-    ch1_sound_length: bool,
+    ch1_length_stop: bool,
     ch1_enabled: bool,
 
     ch2_timer: u16,
     ch2_sequence: u8,
+    ch2_envelope_sequence: u8,
+    ch2_envelope_enabled: bool,
     ch2_output: u8,
     ch2_length_timer: u8,
     ch2_wave_duty: u8,
@@ -40,10 +44,9 @@ pub struct Apu {
     ch2_direction: u8,
     ch2_volume: u8,
     ch2_wave_length: u16,
-    ch2_sound_length: bool,
+    ch2_length_stop: bool,
     ch2_enabled: bool,
 
-    // @TODO start using this once we're ready for CH3
     ch3_timer: u16,
     ch3_position: u8,
     ch3_output: u8,
@@ -51,7 +54,7 @@ pub struct Apu {
     ch3_length_timer: u8,
     ch3_output_level: u8,
     ch3_wave_length: u16,
-    ch3_sound_length: bool,
+    ch3_length_stop: bool,
     ch3_enabled: bool,
 
     wave_ram: [u8; 16],
@@ -68,6 +71,8 @@ impl Apu {
         Self {
             ch1_timer: 0,
             ch1_sequence: 0,
+            ch1_envelope_sequence: 0,
+            ch1_envelope_enabled: false,
             ch1_sweep_sequence: 0,
             ch1_output: 0,
             ch1_sweep_slope: 0x0,
@@ -79,11 +84,13 @@ impl Apu {
             ch1_direction: 0x0,
             ch1_volume: 0x0,
             ch1_wave_length: 0x0,
-            ch1_sound_length: false,
+            ch1_length_stop: false,
             ch1_enabled: false,
 
             ch2_timer: 0,
             ch2_sequence: 0,
+            ch2_envelope_sequence: 0,
+            ch2_envelope_enabled: false,
             ch2_output: 0,
             ch2_length_timer: 0x0,
             ch2_wave_duty: 0x0,
@@ -91,10 +98,9 @@ impl Apu {
             ch2_direction: 0x0,
             ch2_volume: 0x0,
             ch2_wave_length: 0x0,
-            ch2_sound_length: false,
+            ch2_length_stop: false,
             ch2_enabled: false,
 
-            // @TODO start using this once we're ready for CH3
             ch3_timer: 0,
             ch3_position: 0,
             ch3_output: 0,
@@ -102,7 +108,7 @@ impl Apu {
             ch3_length_timer: 0x0,
             ch3_output_level: 0x0,
             ch3_wave_length: 0x0,
-            ch3_sound_length: false,
+            ch3_length_stop: false,
             ch3_enabled: false,
 
             wave_ram: [0u8; 16],
@@ -139,6 +145,7 @@ impl Apu {
                 self.ch1_sweep_slope = value & 0x07;
                 self.ch1_sweep_increase = value & 0x08 == 0x00;
                 self.ch1_sweep_pace = (value & 0x70) >> 4;
+                self.ch1_sweep_sequence = 0;
             }
             // 0xFF11 — NR11: Channel 1 length timer & duty cycle
             0xff11 => {
@@ -150,6 +157,8 @@ impl Apu {
                 self.ch1_pace = value & 0x07;
                 self.ch1_direction = (value & 0x08) >> 3;
                 self.ch1_volume = (value & 0xf0) >> 4;
+                self.ch1_envelope_enabled = self.ch1_pace > 0;
+                self.ch1_envelope_sequence = 0;
             }
             // 0xFF13 — NR13: Channel 1 wavelength low
             0xff13 => {
@@ -159,7 +168,7 @@ impl Apu {
             0xff14 => {
                 self.ch1_wave_length =
                     (self.ch1_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8);
-                self.ch1_sound_length |= value & 0x40 == 0x40;
+                self.ch1_length_stop |= value & 0x40 == 0x40;
                 self.ch1_enabled |= value & 0x80 == 0x80;
             }
 
@@ -182,7 +191,7 @@ impl Apu {
             0xff19 => {
                 self.ch2_wave_length =
                     (self.ch2_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8);
-                self.ch2_sound_length |= value & 0x40 == 0x40;
+                self.ch2_length_stop |= value & 0x40 == 0x40;
                 self.ch2_enabled |= value & 0x80 == 0x80;
             }
 
@@ -206,7 +215,7 @@ impl Apu {
             0xff1e => {
                 self.ch3_wave_length =
                     (self.ch3_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8);
-                self.ch3_sound_length |= value & 0x40 == 0x40;
+                self.ch3_length_stop |= value & 0x40 == 0x40;
                 self.ch3_enabled |= value & 0x80 == 0x80;
             }
 
@@ -239,7 +248,8 @@ impl Apu {
     fn tick(&mut self) {
         self.sequencer += 1;
         if self.sequencer >= 8192 {
-            // each of these steps runs at 518/8 Hz = 64Hz
+            // each of these steps runs at 512/8 Hz = 64Hz,
+            // meaning a complete loop runs at 512 Hz
             match self.sequencer_step {
                 0 => {
                     self.tick_length_all();
@@ -259,9 +269,7 @@ impl Apu {
                     self.tick_length_all();
                 }
                 7 => {
-                    //channels[0]->envelope_clock();
-                    //channels[1]->envelope_clock();
-                    //channels[3]->envelope_clock();
+                    self.tick_envelope_all();
                 }
                 _ => (),
             }
@@ -291,23 +299,26 @@ impl Apu {
     fn tick_length(&mut self, channel: Channel) {
         match channel {
             Channel::Ch1 => {
+                if !self.ch1_enabled {
+                    return;
+                }
                 self.ch1_length_timer = self.ch1_length_timer.saturating_add(1);
                 if self.ch1_length_timer >= 64 {
-                    self.ch1_enabled = false;
+                    self.ch1_enabled = !self.ch1_length_stop;
                     self.ch1_length_timer = 0;
                 }
             }
             Channel::Ch2 => {
                 self.ch2_length_timer = self.ch2_length_timer.saturating_add(1);
                 if self.ch2_length_timer >= 64 {
-                    self.ch2_enabled = false;
+                    self.ch2_enabled = !self.ch2_length_stop;
                     self.ch2_length_timer = 0;
                 }
             }
             Channel::Ch3 => {
                 self.ch3_length_timer = self.ch3_length_timer.saturating_add(1);
                 if self.ch3_length_timer >= 64 {
-                    self.ch3_enabled = false;
+                    self.ch3_enabled = !self.ch3_length_stop;
                     self.ch3_length_timer = 0;
                 }
             }
@@ -315,6 +326,51 @@ impl Apu {
         }
     }
 
+    fn tick_envelope_all(&mut self) {
+        self.tick_envelope(Channel::Ch1);
+    }
+
+    fn tick_envelope(&mut self, channel: Channel) {
+        match channel {
+            Channel::Ch1 => {
+                if !self.ch1_enabled || !self.ch1_envelope_enabled {
+                    return;
+                }
+                self.ch1_envelope_sequence += 1;
+                if self.ch1_envelope_sequence >= self.ch1_pace {
+                    if self.ch1_direction == 0x01 {
+                        self.ch1_volume = self.ch1_volume.saturating_add(1);
+                    } else {
+                        self.ch1_volume = self.ch1_volume.saturating_sub(1);
+                    }
+                    if self.ch1_volume == 0 || self.ch1_volume == 15 {
+                        self.ch1_envelope_enabled = false;
+                    }
+                    self.ch1_envelope_sequence = 0;
+                }
+            }
+            Channel::Ch2 => {
+                if !self.ch2_enabled || !self.ch2_envelope_enabled {
+                    return;
+                }
+                self.ch2_envelope_sequence += 1;
+                if self.ch2_envelope_sequence >= self.ch2_pace {
+                    if self.ch2_direction == 0x01 {
+                        self.ch2_volume = self.ch2_volume.saturating_add(1);
+                    } else {
+                        self.ch2_volume = self.ch2_volume.saturating_sub(1);
+                    }
+                    if self.ch2_volume == 0 || self.ch2_volume == 15 {
+                        self.ch2_envelope_enabled = false;
+                    }
+                    self.ch2_envelope_sequence = 0;
+                }
+            }
+            Channel::Ch3 => (),
+            Channel::Ch4 => (),
+        }
+    }
+
     fn tick_ch1_sweep(&mut self) {
         if self.ch1_sweep_pace == 0x0 {
             return;
@@ -403,7 +459,6 @@ impl Apu {
             } else {
                 output = 0;
             }
-            //println!("{} {}", self.ch3_output, self.ch3_output_level);
             self.ch3_output = output;
         } else {
             self.ch3_output = 0;