diff --git a/frontends/sdl/src/audio.rs b/frontends/sdl/src/audio.rs
index cb0282620847480f24cf740543db808745671701..94e897f245a65bd9f2ab95ba469388fd60d81e24 100644
--- a/frontends/sdl/src/audio.rs
+++ b/frontends/sdl/src/audio.rs
@@ -1,78 +1,26 @@
-use boytacean::gb::{AudioProvider, GameBoy};
 use sdl2::{
-    audio::{AudioCallback, AudioDevice, AudioSpec, AudioSpecDesired},
+    audio::{AudioQueue, AudioSpecDesired},
     AudioSubsystem, Sdl,
 };
-use std::sync::{Arc, Mutex};
-
-pub struct AudioWave {
-    /// Specification of the audion settings that have been put in place
-    /// for the playing of this audio wave.
-    spec: AudioSpec,
-
-    /// The object that is going to be used as the provider of the audio
-    /// operation.
-    audio_provider: Arc<Mutex<Box<GameBoy>>>,
-
-    /// The number of audio ticks that have passed since the beginning
-    /// of the audio playback, the value wraps around (avoids overflow).
-    ticks: usize,
-}
-
-impl AudioCallback for AudioWave {
-    type Channel = f32;
-
-    fn callback(&mut self, out: &mut [f32]) {
-        self.ticks = self.ticks.wrapping_add(out.len() as usize);
-
-        out.fill(0.0);
-
-        match self.audio_provider.try_lock() {
-            Ok(provider) => {
-                for (place, data) in out.iter_mut().zip(provider.output_buffer_apu().iter()) {
-                    *place = *data as f32 / 7.0;
-                }
-            }
-            Err(_) => (),
-        }
-
-        self.audio_provider.lock().unwrap().clear_buffer_apu();
-
-        /*
-        for x in out.iter_mut() {
-            *x = match self.audio_provider.lock() {
-                Ok(mut provider) => {
-                    let value = provider.output_clock_apu(1, self.spec.freq as u32) as f32 / 7.0;
-                    value
-                }
-                Err(_) => 0.0,
-            }
-        }*/
-    }
-}
 
 pub struct Audio {
-    pub device: AudioDevice<AudioWave>,
+    pub device: AudioQueue<f32>,
     pub audio_subsystem: AudioSubsystem,
 }
 
 impl Audio {
-    pub fn new(sdl: &Sdl, audio_provider: Arc<Mutex<Box<GameBoy>>>) -> Self {
+    pub fn new(sdl: &Sdl) -> Self {
         let audio_subsystem = sdl.audio().unwrap();
 
         let desired_spec = AudioSpecDesired {
             freq: Some(44100),
             channels: Some(1),
-            samples: None,
+            samples: Some(4096),
         };
 
-        let device = audio_subsystem
-            .open_playback(None, &desired_spec, |spec| AudioWave {
-                spec: spec,
-                audio_provider: audio_provider,
-                ticks: 0,
-            })
-            .unwrap();
+        // creates the queue that is going to be used to update the
+        // audio stream with new values during the main loop
+        let device = audio_subsystem.open_queue(None, &desired_spec).unwrap();
 
         // starts the playback by resuming the audio
         // device's activity
diff --git a/frontends/sdl/src/main.rs b/frontends/sdl/src/main.rs
index 2d97c7c75c0255bb530e09b7614184f90db2e4fb..a5cf1c02ca0951cbd86bd684f42b18361ad5780a 100644
--- a/frontends/sdl/src/main.rs
+++ b/frontends/sdl/src/main.rs
@@ -6,17 +6,13 @@ pub mod graphics;
 
 use audio::Audio;
 use boytacean::{
-    gb::GameBoy,
+    gb::{AudioProvider, GameBoy},
     pad::PadKey,
     ppu::{PaletteInfo, PpuMode, DISPLAY_HEIGHT, DISPLAY_WIDTH},
 };
 use graphics::{surface_from_bytes, Graphics};
 use sdl2::{event::Event, keyboard::Keycode, pixels::PixelFormatEnum, Sdl};
-use std::{
-    cmp::max,
-    sync::{Arc, Mutex},
-    time::SystemTime,
-};
+use std::{cmp::max, time::SystemTime};
 
 /// The scale at which the screen is going to be drawn
 /// meaning the ratio between Game Boy resolution and
@@ -43,7 +39,7 @@ impl Default for Benchmark {
 }
 
 pub struct Emulator {
-    system: Arc<Mutex<Box<GameBoy>>>,
+    system: GameBoy,
     graphics: Option<Graphics>,
     audio: Option<Audio>,
     logic_frequency: u32,
@@ -56,7 +52,7 @@ pub struct Emulator {
 }
 
 impl Emulator {
-    pub fn new(system: Arc<Mutex<Box<GameBoy>>>) -> Self {
+    pub fn new(system: GameBoy) -> Self {
         Self {
             system,
             graphics: None,
@@ -99,10 +95,10 @@ impl Emulator {
         }
     }
 
-    pub fn start(&mut self, screen_scale: f32, audio_provider: Arc<Mutex<Box<GameBoy>>>) {
+    pub fn start(&mut self, screen_scale: f32) {
         let sdl = sdl2::init().unwrap();
         self.start_graphics(&sdl, screen_scale);
-        self.start_audio(&sdl, audio_provider);
+        self.start_audio(&sdl);
     }
 
     pub fn start_graphics(&mut self, sdl: &Sdl, screen_scale: f32) {
@@ -117,13 +113,12 @@ impl Emulator {
         ));
     }
 
-    pub fn start_audio(&mut self, sdl: &Sdl, audio_provider: Arc<Mutex<Box<GameBoy>>>) {
-        self.audio = Some(Audio::new(sdl, audio_provider));
+    pub fn start_audio(&mut self, sdl: &Sdl) {
+        self.audio = Some(Audio::new(sdl));
     }
 
     pub fn load_rom(&mut self, path: &str) {
-        let mut system = self.system.lock().unwrap();
-        let rom = system.load_rom_file(path);
+        let rom = self.system.load_rom_file(path);
         println!(
             "========= Cartridge =========\n{}\n=============================",
             rom
@@ -145,7 +140,7 @@ impl Emulator {
         let initial = SystemTime::now();
 
         for _ in 0..count {
-            cycles += self.system.lock().unwrap().clock() as u32;
+            cycles += self.system.clock() as u32;
         }
 
         let delta = initial.elapsed().unwrap().as_millis() as f32 / 1000.0;
@@ -159,8 +154,6 @@ impl Emulator {
 
     pub fn toggle_palette(&mut self) {
         self.system
-            .lock()
-            .unwrap()
             .ppu()
             .set_palette_colors(self.palettes[self.palette_index].colors());
         self.palette_index = (self.palette_index + 1) % self.palettes.len();
@@ -239,7 +232,7 @@ impl Emulator {
                         ..
                     } => {
                         if let Some(key) = key_to_pad(keycode) {
-                            self.system.lock().unwrap().key_press(key)
+                            self.system.key_press(key)
                         }
                     }
                     Event::KeyUp {
@@ -247,12 +240,12 @@ impl Emulator {
                         ..
                     } => {
                         if let Some(key) = key_to_pad(keycode) {
-                            self.system.lock().unwrap().key_lift(key)
+                            self.system.key_lift(key)
                         }
                     }
                     Event::DropFile { filename, .. } => {
-                        self.system.lock().unwrap().reset();
-                        self.system.lock().unwrap().load_boot_default();
+                        self.system.reset();
+                        self.system.load_boot_default();
                         self.load_rom(&filename);
                     }
                     _ => (),
@@ -283,33 +276,44 @@ impl Emulator {
                         break;
                     }
 
+                    // 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 += self.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 self.system.ppu_mode() == PpuMode::VBlank
+                        && self.system.ppu_frame() != last_frame
                     {
-                        // obtains a locked reference to the system that is going to be
-                        // valid under the current block
-                        let mut system = self.system.lock().unwrap();
-
-                        // 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
-                            // to update the stream texture, that will latter be copied
-                            // to the canvas
-                            let frame_buffer = system.frame_buffer().as_ref();
-                            texture
-                                .update(None, frame_buffer, DISPLAY_WIDTH * 3)
-                                .unwrap();
-
-                            // obtains the index of the current PPU frame, this value
-                            // is going to be used to detect for new frame presence
-                            last_frame = system.ppu_frame();
-                        }
+                        // obtains the frame buffer of the Game Boy PPU and uses it
+                        // to update the stream texture, that will latter be copied
+                        // to the canvas
+                        let frame_buffer = self.system.frame_buffer().as_ref();
+                        texture
+                            .update(None, frame_buffer, DISPLAY_WIDTH * 3)
+                            .unwrap();
+
+                        // obtains the index of the current PPU frame, this value
+                        // is going to be used to detect for new frame presence
+                        last_frame = self.system.ppu_frame();
                     }
+
+                    // obtains the new audio buffer and queues it into the audio
+                    // subsystem ready to be processed
+                    let audio_buffer = self
+                        .system
+                        .audio_buffer()
+                        .iter()
+                        .map(|v| *v as f32 / 7.0)
+                        .collect::<Vec<f32>>();
+                    self.audio
+                        .as_mut()
+                        .unwrap()
+                        .device
+                        .queue_audio(&audio_buffer)
+                        .unwrap();
+                    self.system.clear_audio_buffer();
                 }
 
                 // in case there's at least one new frame that was drawn during
@@ -370,16 +374,14 @@ impl Emulator {
 fn main() {
     // creates a new Game Boy instance and loads both the boot ROM
     // and the initial game ROM to "start the engine"
-    let game_boy = Arc::new(Mutex::new(Box::new(GameBoy::new())));
-    game_boy.try_lock().unwrap().as_mut().load_boot_default();
+    let mut game_boy = GameBoy::new();
+    game_boy.load_boot_default();
 
-    // creates a new generic emulator structure loads the default
+    // creates a new generic emulator structure then starts
+    // both the video and audio sub-systems, loads default
     // ROM file and starts running it
     let mut emulator = Emulator::new(game_boy);
-
-    let game_boy_ref = emulator.system.clone();
-
-    emulator.start(SCREEN_SCALE, game_boy_ref);
+    emulator.start(SCREEN_SCALE);
     emulator.load_rom("../../res/roms/pocket.gb");
     emulator.toggle_palette();
     emulator.run();
diff --git a/src/gb.rs b/src/gb.rs
index 8861dc704d0672d355f0a71f226f0fba2d04f845..7bb4b788470144b6a28487fcf5df738f038c2917 100644
--- a/src/gb.rs
+++ b/src/gb.rs
@@ -56,8 +56,8 @@ pub struct Registers {
 pub trait AudioProvider {
     fn output_apu(&self) -> u8;
     fn output_clock_apu(&mut self, cycles: u8, freq: u32) -> u8;
-    fn output_buffer_apu(&self) -> &Vec<u8>;
-    fn clear_buffer_apu(&mut self);
+    fn audio_buffer(&self) -> &Vec<u8>;
+    fn clear_audio_buffer(&mut self);
 }
 
 #[cfg_attr(feature = "wasm", wasm_bindgen)]
@@ -393,11 +393,11 @@ impl AudioProvider for GameBoy {
         self.apu_i().output()
     }
 
-    fn output_buffer_apu(&self) -> &Vec<u8> {
+    fn audio_buffer(&self) -> &Vec<u8> {
         self.apu_i().output_buffer()
     }
 
-    fn clear_buffer_apu(&mut self) {
+    fn clear_audio_buffer(&mut self) {
         self.apu().clear_buffer()
     }
 }