diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d13c103754540620654f88272f1411a26c191f6..87d626651dccd33971d223aef38f909ebe5232ef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
-*
+* Support for audio channel 4 (noise) 🔈
 
 ### Changed
 
@@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Fixed
 
-*
+* Envelope support for both channel 2 and 4
 
 ## [0.7.3] - 2023-04-02
 
diff --git a/frontends/sdl/README.md b/frontends/sdl/README.md
index ac9ab6a5d8636e34a8274ef37750aedebac25738..75c153a41485dcef6f204b8b9d1450bde176794e 100644
--- a/frontends/sdl/README.md
+++ b/frontends/sdl/README.md
@@ -16,3 +16,10 @@ Then you can use the following command to build and run Boytacean SDL:
 cargo build
 cargo run
 ```
+
+To reload the code continuously use the cargo watch tool:
+
+```bash
+cargo install cargo-watch
+cargo watch -x run
+```
diff --git a/src/apu.rs b/src/apu.rs
index b44762b9655abc245d1a74036188923083b22b17..712d88ee01ceea371231b31fc9d7e80c8e1b3fd4 100644
--- a/src/apu.rs
+++ b/src/apu.rs
@@ -9,6 +9,8 @@ const DUTY_TABLE: [[u8; 8]; 4] = [
     [0, 1, 1, 1, 1, 1, 1, 0],
 ];
 
+const CH4_DIVISORS: [u8; 8] = [8, 16, 32, 48, 64, 80, 96, 112];
+
 pub enum Channel {
     Ch1,
     Ch2,
@@ -59,6 +61,21 @@ pub struct Apu {
     ch3_length_stop: bool,
     ch3_enabled: bool,
 
+    ch4_timer: i16,
+    ch4_envelope_sequence: u8,
+    ch4_envelope_enabled: bool,
+    ch4_output: u8,
+    ch4_length_timer: u8,
+    ch4_pace: u8,
+    ch4_direction: u8,
+    ch4_volume: u8,
+    ch4_divisor: u8,
+    ch4_width_mode: bool,
+    ch4_clock_shift: u8,
+    ch4_lfsr: u16,
+    ch4_length_stop: bool,
+    ch4_enabled: bool,
+
     right_enabled: bool,
     left_enabled: bool,
 
@@ -117,11 +134,32 @@ impl Apu {
             ch3_length_stop: false,
             ch3_enabled: false,
 
+            ch4_timer: 0,
+            ch4_envelope_sequence: 0,
+            ch4_envelope_enabled: false,
+            ch4_output: 0,
+            ch4_length_timer: 0x0,
+            ch4_pace: 0x0,
+            ch4_direction: 0x0,
+            ch4_volume: 0x0,
+            ch4_divisor: 0x0,
+            ch4_width_mode: false,
+            ch4_clock_shift: 0x0,
+            ch4_lfsr: 0x0,
+            ch4_length_stop: false,
+            ch4_enabled: false,
+
             left_enabled: true,
             right_enabled: true,
 
+            /// The RAM that is used to sore the wave information
+            /// to be used in channel 3 audio
             wave_ram: [0u8; 16],
 
+            /// The rate at which audio samples are going to be
+            /// taken, ideally this value should be aligned with
+            /// the sampling rate of the output device. A typical
+            /// sampling rate would be of 44.1kHz.
             sampling_rate,
 
             /// Internal sequencer counter that runs at 512Hz
@@ -179,6 +217,21 @@ impl Apu {
         self.ch3_length_stop = false;
         self.ch3_enabled = false;
 
+        self.ch4_timer = 0;
+        self.ch4_envelope_sequence = 0;
+        self.ch4_envelope_enabled = false;
+        self.ch4_output = 0;
+        self.ch4_length_timer = 0x0;
+        self.ch4_pace = 0x0;
+        self.ch4_direction = 0x0;
+        self.ch4_volume = 0x0;
+        self.ch4_divisor = 0x0;
+        self.ch4_width_mode = false;
+        self.ch4_clock_shift = 0x0;
+        self.ch4_lfsr = 0x0;
+        self.ch4_length_stop = false;
+        self.ch4_enabled = false;
+
         self.left_enabled = true;
         self.right_enabled = true;
 
@@ -242,7 +295,8 @@ impl Apu {
             }
 
             // @TODO the CPU clock is hardcoded here, we must handle situations
-            // where there's some kind of overclock
+            // where there's some kind of overclock, and for that to happen the
+            // current CPU clock must be propagated here
             self.output_timer += (4194304.0 / self.sampling_rate as f32) as i16;
         }
     }
@@ -335,6 +389,48 @@ impl Apu {
                 self.ch3_enabled |= value & 0x80 == 0x80;
             }
 
+            // 0xFF20 — NR41: Channel 4 length timer
+            0xff20 => {
+                self.ch4_length_timer = value & 0x3f;
+            }
+            // 0xFF21 — NR42: Channel 4 volume & envelope
+            0xff21 => {
+                self.ch4_pace = value & 0x07;
+                self.ch4_direction = (value & 0x08) >> 3;
+                self.ch4_volume = (value & 0xf0) >> 4;
+                self.ch4_envelope_enabled = self.ch4_pace > 0;
+                self.ch4_envelope_sequence = 0;
+            }
+            // 0xFF22 — NR43: Channel 4 frequency & randomness
+            0xff22 => {
+                self.ch4_divisor = value & 0x07;
+                self.ch4_width_mode = value & 0x08 == 0x08;
+                self.ch4_clock_shift = (value & 0xf0) >> 4;
+            }
+            // 0xFF23 — NR44: Channel 4 control
+            0xff23 => {
+                self.ch4_length_stop |= value & 0x40 == 0x40;
+                self.ch4_enabled |= value & 0x80 == 0x80;
+                if value & 0x80 == 0x80 {
+                    self.ch4_timer = ((CH4_DIVISORS[self.ch4_divisor as usize] as u16)
+                        << self.ch4_clock_shift) as i16;
+                    self.ch4_lfsr = 0x7ff1;
+                }
+            }
+
+            // 0xFF24 — NR50: Master volume & VIN panning
+            0xff24 => {
+                //@TODO: Implement master volume & VIN panning
+            }
+            // 0xFF25 — NR51: Sound panning
+            0xff25 => {
+                //@TODO: Implement sound panning
+            }
+            // 0xFF26 — NR52: Sound on/off
+            0xff26 => {
+                //@TODO: Implement sound on/off
+            }
+
             // 0xFF30-0xFF3F — Wave pattern RAM
             0xff30..=0xff3f => {
                 self.wave_ram[addr as usize & 0x000f] = value;
@@ -345,7 +441,7 @@ impl Apu {
     }
 
     pub fn output(&self) -> u8 {
-        self.ch1_output + self.ch2_output + self.ch3_output
+        self.ch1_output + self.ch2_output + self.ch3_output + self.ch4_output
     }
 
     pub fn ch1_output(&self) -> u8 {
@@ -360,6 +456,10 @@ impl Apu {
         self.ch3_output
     }
 
+    pub fn ch4_output(&self) -> u8 {
+        self.ch4_output
+    }
+
     pub fn audio_buffer(&self) -> &VecDeque<u8> {
         &self.audio_buffer
     }
@@ -407,13 +507,21 @@ impl Apu {
                     self.ch3_length_timer = 0;
                 }
             }
-            Channel::Ch4 => (),
+            Channel::Ch4 => {
+                self.ch4_length_timer = self.ch4_length_timer.saturating_add(1);
+                if self.ch4_length_timer >= 64 {
+                    self.ch4_enabled = !self.ch4_length_stop;
+                    self.ch4_length_timer = 0;
+                }
+            }
         }
     }
 
     #[inline(always)]
     fn tick_envelope_all(&mut self) {
         self.tick_envelope(Channel::Ch1);
+        self.tick_envelope(Channel::Ch2);
+        self.tick_envelope(Channel::Ch4);
     }
 
     #[inline(always)]
@@ -454,7 +562,23 @@ impl Apu {
                 }
             }
             Channel::Ch3 => (),
-            Channel::Ch4 => (),
+            Channel::Ch4 => {
+                if !self.ch4_enabled || !self.ch4_envelope_enabled {
+                    return;
+                }
+                self.ch4_envelope_sequence += 1;
+                if self.ch4_envelope_sequence >= self.ch4_pace {
+                    if self.ch4_direction == 0x01 {
+                        self.ch4_volume = self.ch4_volume.saturating_add(1);
+                    } else {
+                        self.ch4_volume = self.ch4_volume.saturating_sub(1);
+                    }
+                    if self.ch4_volume == 0 || self.ch4_volume == 15 {
+                        self.ch4_envelope_enabled = false;
+                    }
+                    self.ch4_envelope_sequence = 0;
+                }
+            }
         }
     }
 
@@ -485,6 +609,7 @@ impl Apu {
         self.tick_ch1(cycles);
         self.tick_ch2(cycles);
         self.tick_ch3(cycles);
+        self.tick_ch4(cycles);
     }
 
     #[inline(always)]
@@ -559,6 +684,39 @@ impl Apu {
         self.ch3_timer += ((2048 - self.ch3_wave_length) << 1) as i16;
         self.ch3_position = (self.ch3_position + 1) & 31;
     }
+
+    #[inline(always)]
+    fn tick_ch4(&mut self, cycles: u8) {
+        self.ch4_timer = self.ch4_timer.saturating_sub(cycles as i16);
+        if self.ch4_timer > 0 {
+            return;
+        }
+
+        if self.ch4_enabled {
+            // obtains the current value of the LFSR based as
+            // the XOR of the 1st and 2nd bit of the LFSR
+            let result = ((self.ch4_lfsr & 0x0001) ^ ((self.ch4_lfsr >> 1) & 0x0001)) == 0x0001;
+
+            // shifts the LFSR to the right and in case the
+            // value is positive sets the 15th bit to 1
+            self.ch4_lfsr >>= 1;
+            self.ch4_lfsr |= if result { 0x0001 << 14 } else { 0x0 };
+
+            // in case the short width mode (7 bits) is set then
+            // the 6th bit will be set to value of the 15th bit
+            if self.ch4_width_mode {
+                self.ch4_lfsr &= 0xbf;
+                self.ch4_lfsr |= if result { 0x40 } else { 0x00 };
+            }
+
+            self.ch4_output = if result { self.ch4_volume } else { 0 };
+        } else {
+            self.ch4_output = 0;
+        }
+
+        self.ch4_timer +=
+            ((CH4_DIVISORS[self.ch4_divisor as usize] as u16) << self.ch4_clock_shift) as i16;
+    }
 }
 
 impl Default for Apu {
diff --git a/src/cpu.rs b/src/cpu.rs
index 237ef622b82478e4fc6f4433c1eaa051cfd5153c..8f9b95ff297a2c6fe2d0fad9059ff7232f2893f9 100644
--- a/src/cpu.rs
+++ b/src/cpu.rs
@@ -127,7 +127,7 @@ impl Cpu {
             self.halted = false;
         }
 
-        if self.ime {
+        if self.ime && self.mmu.ie != 0x00 {
             // @TODO aggregate all of this interrupts in the MMU, as there's
             // a lot of redundant code involved in here which complicates the
             // readability and maybe performance of this code
diff --git a/src/mmu.rs b/src/mmu.rs
index d3b389cfb01501c2314d9e1e69459e3a6e107eed..bc4a9ddd43ca2d8a814f4d0af2c09bce448d2a6d 100644
--- a/src/mmu.rs
+++ b/src/mmu.rs
@@ -170,7 +170,7 @@ impl Mmu {
                                 0x00
                             }
                         },
-                        0x10..=26 | 0x30..=0x37 => self.apu.read(addr),
+                        0x10..=0x26 | 0x30..=0x37 => self.apu.read(addr),
                         0x40 | 0x50 | 0x60 | 0x70 => self.ppu.read(addr),
                         _ => {
                             debugln!("Reading from unknown IO control 0x{:04x}", addr);
@@ -241,7 +241,7 @@ impl Mmu {
                                 0x04..=0x07 => self.timer.write(addr, value),
                                 _ => debugln!("Writing to unknown IO control 0x{:04x}", addr),
                             },
-                            0x10..=26 | 0x30..=0x37 => self.apu.write(addr, value),
+                            0x10..=0x26 | 0x30..=0x37 => self.apu.write(addr, value),
                             0x40 | 0x60 | 0x70 => {
                                 match addr & 0x00ff {
                                     // 0xFF46 — DMA: OAM DMA source address & start
diff --git a/src/pad.rs b/src/pad.rs
index 246706d8b3e1552c5d596795c35be0ea7abc92bf..36c10a1715f80741916a3d6dd55bce5e28d67532 100644
--- a/src/pad.rs
+++ b/src/pad.rs
@@ -114,7 +114,7 @@ impl Pad {
         }
 
         // signals that a JoyPad interrupt is pending to be
-        // handled as a key pressed has been done
+        // handled as a key press has been performed
         self.int_pad = true;
     }