From fce45615390bc1531720a0565fb262cd51462c3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Sat, 4 Mar 2023 00:20:27 +0000
Subject: [PATCH] feat: support for stereo sound There's still no control over
 the channels themselves, but the basic interleaved buffer support is now
 coded. There's also new support for buffer size definition in seconds.

---
 frontends/sdl/src/audio.rs |  2 +-
 frontends/web/ts/gb.ts     | 14 ++++++--------
 src/apu.rs                 | 27 ++++++++++++++++++++++-----
 3 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/frontends/sdl/src/audio.rs b/frontends/sdl/src/audio.rs
index 94e897f2..c5c113c0 100644
--- a/frontends/sdl/src/audio.rs
+++ b/frontends/sdl/src/audio.rs
@@ -14,7 +14,7 @@ impl Audio {
 
         let desired_spec = AudioSpecDesired {
             freq: Some(44100),
-            channels: Some(1),
+            channels: Some(2),
             samples: Some(4096),
         };
 
diff --git a/frontends/web/ts/gb.ts b/frontends/web/ts/gb.ts
index ff789a00..dcde0e67 100644
--- a/frontends/web/ts/gb.ts
+++ b/frontends/web/ts/gb.ts
@@ -518,16 +518,14 @@ export class GameboyEmulator extends EmulatorBase implements Emulator {
     }
 
     get audioBuffer(): Float32Array[] {
-        const audioBuffer = [];
         const internalBuffer = this.gameBoy?.audio_buffer_eager(true) ?? [];
-        for (let channel = 0; channel < 2; channel++) {
-            const stream = new Float32Array(internalBuffer.length);
-            for (let index = 0; index < internalBuffer.length; index++) {
-                stream[index] = internalBuffer[index] / 100.0;
-            }
-            audioBuffer.push(stream);
+        const leftStream = new Float32Array(internalBuffer.length / 2);
+        const rightStream = new Float32Array(internalBuffer.length / 2);
+        for (let index = 0; index < internalBuffer.length; index += 2) {
+            leftStream[index / 2] = internalBuffer[index] / 100.0;
+            rightStream[index / 2] = internalBuffer[index + 1] / 100.0;
         }
-        return audioBuffer;
+        return [leftStream, rightStream];
     }
 
     get romInfo(): RomInfo {
diff --git a/src/apu.rs b/src/apu.rs
index ddbc0c32..8fb3fd7b 100644
--- a/src/apu.rs
+++ b/src/apu.rs
@@ -59,6 +59,9 @@ pub struct Apu {
     ch3_length_stop: bool,
     ch3_enabled: bool,
 
+    right_enabled: bool,
+    left_enabled: bool,
+
     wave_ram: [u8; 16],
 
     sampling_rate: u16,
@@ -70,7 +73,7 @@ pub struct Apu {
 }
 
 impl Apu {
-    pub fn new(sampling_rate: u16) -> Self {
+    pub fn new(sampling_rate: u16, buffer_size: f32) -> Self {
         Self {
             ch1_timer: 0,
             ch1_sequence: 0,
@@ -114,6 +117,9 @@ impl Apu {
             ch3_length_stop: false,
             ch3_enabled: false,
 
+            left_enabled: true,
+            right_enabled: true,
+
             wave_ram: [0u8; 16],
 
             sampling_rate,
@@ -123,8 +129,10 @@ impl Apu {
             sequencer: 0,
             sequencer_step: 0,
             output_timer: 0,
-            audio_buffer: VecDeque::with_capacity(sampling_rate as usize),
-            audio_buffer_max: sampling_rate as usize,
+            audio_buffer: VecDeque::with_capacity(
+                (sampling_rate as f32 * buffer_size as f32 * 2.0) as usize,
+            ),
+            audio_buffer_max: (sampling_rate as f32 * buffer_size as f32 * 2.0) as usize,
         }
     }
 
@@ -171,6 +179,9 @@ impl Apu {
         self.ch3_length_stop = false;
         self.ch3_enabled = false;
 
+        self.left_enabled = true;
+        self.right_enabled = true;
+
         self.sequencer = 0;
         self.sequencer_step = 0;
         self.output_timer = 0;
@@ -342,8 +353,14 @@ impl Apu {
             // volume item is added to the queue
             if self.audio_buffer.len() >= self.audio_buffer_max {
                 self.audio_buffer.pop_front();
+                self.audio_buffer.pop_front();
+            }
+            if self.left_enabled {
+                self.audio_buffer.push_back(self.output());
+            }
+            if self.right_enabled {
+                self.audio_buffer.push_back(self.output());
             }
-            self.audio_buffer.push_back(self.output());
 
             // @TODO the CPU clock is hardcoded here, we must handle situations
             // where there's some kind of overclock
@@ -542,6 +559,6 @@ impl Apu {
 
 impl Default for Apu {
     fn default() -> Self {
-        Self::new(44100)
+        Self::new(44100, 1.0)
     }
 }
-- 
GitLab