diff --git a/frontends/sdl/src/audio.rs b/frontends/sdl/src/audio.rs
index 2b5480bcc2498065f5bccac1a2287fbc9e8c1890..d0dabfc1d231d372137cb23aa38a9c3b8269d981 100644
--- a/frontends/sdl/src/audio.rs
+++ b/frontends/sdl/src/audio.rs
@@ -28,7 +28,7 @@ impl AudioCallback for AudioWave {
         for x in out.iter_mut() {
             *x = match self.audio_provider.lock() {
                 Ok(mut provider) => {
-                    let value = provider.tick_apu(self.spec.freq as u32) as f32 / 7.0;
+                    let value = provider.output_clock_apu(1, self.spec.freq as u32) as f32 / 7.0;
                     value
                 }
                 Err(_) => 0.0,
@@ -49,7 +49,7 @@ impl Audio {
         let desired_spec = AudioSpecDesired {
             freq: Some(44100),
             channels: Some(1),
-            samples: None,
+            samples: Some(2),
         };
 
         let device = audio_subsystem
diff --git a/frontends/sdl/src/main.rs b/frontends/sdl/src/main.rs
index 5844e69a9a8ae556ab0ba6aef5323108132d55a0..5aa26b4969d63cdb059d064c0e4142e19b0f5e44 100644
--- a/frontends/sdl/src/main.rs
+++ b/frontends/sdl/src/main.rs
@@ -6,7 +6,7 @@ pub mod graphics;
 
 use audio::Audio;
 use boytacean::{
-    gb::{AudioProvider, GameBoy},
+    gb::GameBoy,
     pad::PadKey,
     ppu::{PaletteInfo, PpuMode, DISPLAY_HEIGHT, DISPLAY_WIDTH},
 };
@@ -117,10 +117,6 @@ impl Emulator {
         self.audio = Some(Audio::new(sdl, audio_provider));
     }
 
-    pub fn tick_audio(&mut self, freq: u32) -> u8 {
-        self.system.lock().unwrap().tick_apu(freq)
-    }
-
     pub fn load_rom(&mut self, path: &str) {
         let mut system = self.system.lock().unwrap();
         let rom = system.load_rom_file(path);
@@ -288,10 +284,13 @@ impl Emulator {
                         // valid under the current block
                         let mut system = self.system.lock().unwrap();
 
-                        // runs the Game Boy clock, this operations should
-                        // include the advance of both the CPU and the PPU
+                        // runs the Game Boy clock, this operation should
+                        // include the advance of both the CPU, PPU, APU
+                        // and any other frequency based component of the system
                         counter_cycles += system.clock() as u32;
 
+                        // in case a V-Blank state has been reached a new frame is available
+                        // then the frame must be pushed into SDL for display
                         if system.ppu_mode() == PpuMode::VBlank && system.ppu_frame() != last_frame
                         {
                             // obtains the frame buffer of the Game Boy PPU and uses it
diff --git a/src/apu.rs b/src/apu.rs
index 0e1b92ef824b3f9afccaed3f122b4983c204b655..2c9cd6b01b45576ac9d22cddc53be5781ea9a2f1 100644
--- a/src/apu.rs
+++ b/src/apu.rs
@@ -34,6 +34,18 @@ pub struct Apu {
     ch2_wave_length: u16,
     ch2_sound_length: bool,
     ch2_enabled: bool,
+
+    ch3_timer: u16,
+    ch3_sequence: u8,
+    ch3_output: u8,
+    ch3_dac: bool,
+    ch3_length_timer: u8,
+    ch3_output_level: u8,
+    ch3_wave_length: u16,
+    ch3_sound_length: bool,
+    ch3_enabled: bool,
+
+    wave_ram: [u8; 16],
 }
 
 impl Apu {
@@ -65,10 +77,27 @@ impl Apu {
             ch2_wave_length: 0x0,
             ch2_sound_length: false,
             ch2_enabled: false,
+
+            ch3_timer: 0,
+            ch3_sequence: 0,
+            ch3_output: 0,
+            ch3_dac: false,
+            ch3_length_timer: 0x0,
+            ch3_output_level: 0x0,
+            ch3_wave_length: 0x0,
+            ch3_sound_length: false,
+            ch3_enabled: false,
+
+            wave_ram: [0u8; 16],
         }
     }
 
-    pub fn clock(&mut self, cycles: u8, freq: u32) {
+    pub fn clock(&mut self, cycles: u8) {
+        self.clock_f(cycles, 4194304);
+    }
+
+    pub fn clock_f(&mut self, cycles: u8, freq: u32) {
+        // @todo the performance here requires improvement
         for _ in 0..cycles {
             self.cycle(freq);
         }
@@ -76,7 +105,6 @@ impl Apu {
 
     pub fn read(&mut self, addr: u16) -> u8 {
         match addr {
-            0xff26 => 1 as u8, // @todo implement this
             _ => {
                 warnln!("Reading from unknown APU location 0x{:04x}", addr);
                 0xff
@@ -137,9 +165,44 @@ impl Apu {
                     (self.ch2_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8);
                 self.ch2_sound_length |= value & 0x40 == 0x40;
                 self.ch2_enabled |= value & 0x80 == 0x80;
+                if value & 0x80 == 0x80 {
+                    //self.ch2_timer = 0;
+                    //self.ch2_sequence = 0;
+                    //@todo improve this reset operation
+                }
                 println!("CH2 Enabled {}", self.ch2_enabled);
             }
 
+            // 0xFF1A — NR30: Channel 3 DAC enable
+            0xff1a => {
+                self.ch3_dac = value & 0x80 == 0x80;
+            }
+            // 0xFF1B — NR31: Channel 3 length timer
+            0xff1b => {
+                self.ch3_length_timer = value;
+            }
+            // 0xFF1C — NR32: Channel 3 output level
+            0xff1c => {
+                self.ch3_output_level = value & 0x60 >> 5;
+            }
+            // 0xFF1D — NR33: Channel 3 wavelength low [write-only]
+            0xff1d => {
+                self.ch3_wave_length = (self.ch3_wave_length & 0xff00) | value as u16;
+            }
+            // 0xFF1E — NR34: Channel 3 wavelength high & control
+            0xff1e => {
+                self.ch3_wave_length =
+                    (self.ch3_wave_length & 0x00ff) | (((value & 0x07) as u16) << 8);
+                self.ch3_sound_length |= value & 0x40 == 0x40;
+                self.ch3_enabled |= value & 0x80 == 0x80;
+                println!("CH3 Enabled {}", self.ch3_enabled);
+            }
+
+            // 0xFF30-0xFF3F — Wave pattern RAM
+            0xff30..=0xff3f => {
+                self.wave_ram[addr as usize - 0xff30] = value;
+            }
+
             _ => warnln!("Writing in unknown APU location 0x{:04x}", addr),
         }
     }
diff --git a/src/cpu.rs b/src/cpu.rs
index ac8e52585d83fc1049d316aa18c2fa54b7d32b43..237ef622b82478e4fc6f4433c1eaa051cfd5153c 100644
--- a/src/cpu.rs
+++ b/src/cpu.rs
@@ -267,6 +267,11 @@ impl Cpu {
         &mut self.mmu
     }
 
+    #[inline(always)]
+    pub fn mmu_i(&self) -> &Mmu {
+        &self.mmu
+    }
+
     #[inline(always)]
     pub fn ppu(&mut self) -> &mut Ppu {
         self.mmu().ppu()
@@ -277,6 +282,11 @@ impl Cpu {
         self.mmu().apu()
     }
 
+    #[inline(always)]
+    pub fn apu_i(&self) -> &Apu {
+        self.mmu_i().apu_i()
+    }
+
     #[inline(always)]
     pub fn pad(&mut self) -> &mut Pad {
         self.mmu().pad()
diff --git a/src/gb.rs b/src/gb.rs
index 125ec06df6e4b7defe6b3f5982b3d8bcb8ee0e40..bb779fe132dc054857b6549f6ebc36609889db9d 100644
--- a/src/gb.rs
+++ b/src/gb.rs
@@ -54,7 +54,8 @@ pub struct Registers {
 }
 
 pub trait AudioProvider {
-    fn tick_apu(&mut self, freq: u32) -> u8;
+    fn output_apu(&self) -> u8;
+    fn output_clock_apu(&mut self, cycles: u8, freq: u32) -> u8;
 }
 
 #[cfg_attr(feature = "wasm", wasm_bindgen)]
@@ -99,8 +100,8 @@ impl GameBoy {
         self.ppu().clock(cycles)
     }
 
-    pub fn apu_clock(&mut self, cycles: u8, freq: u32) {
-        self.apu().clock(cycles, freq)
+    pub fn apu_clock(&mut self, cycles: u8) {
+        self.apu().clock(cycles)
     }
 
     pub fn timer_clock(&mut self, cycles: u8) {
@@ -260,6 +261,10 @@ impl GameBoy {
         self.cpu.apu()
     }
 
+    pub fn apu_i(&self) -> &Apu {
+        self.cpu.apu_i()
+    }
+
     pub fn pad(&mut self) -> &mut Pad {
         self.cpu.pad()
     }
@@ -376,9 +381,13 @@ pub fn hook_impl(info: &PanicInfo) {
 }
 
 impl AudioProvider for GameBoy {
-    fn tick_apu(&mut self, freq: u32) -> u8 {
-        self.apu_clock(1, freq);
-        self.apu().output()
+    fn output_apu(&self) -> u8 {
+        self.apu_i().output()
+    }
+
+    fn output_clock_apu(&mut self, cycles: u8, freq: u32) -> u8 {
+        self.apu().clock_f(cycles, freq);
+        self.apu_i().output()
     }
 }
 
diff --git a/src/mmu.rs b/src/mmu.rs
index a718fa49ddd28003c3fc90f9bdb70b94d47c3fea..d3b389cfb01501c2314d9e1e69459e3a6e107eed 100644
--- a/src/mmu.rs
+++ b/src/mmu.rs
@@ -79,6 +79,10 @@ impl Mmu {
         &mut self.apu
     }
 
+    pub fn apu_i(&self) -> &Apu {
+        &self.apu
+    }
+
     pub fn pad(&mut self) -> &mut Pad {
         &mut self.pad
     }