shithub: zelda3

Download patch

ref: cdc0e155b86c96083911fb5ba5dc607fd7a1d62e
parent: 81adacf8cc09b74a90e115e5b6760c398eeaff27
author: Keaton Greve <keatongreve@google.com>
date: Sun Sep 11 08:27:57 EDT 2022

Fix mono audio rendering

--- a/main.c
+++ b/main.c
@@ -33,7 +33,7 @@
 bool RunOneFrame(Snes *snes, int input_state, bool turbo);
 
 static bool LoadRom(const char *name, Snes *snes);
-static void PlayAudio(Snes *snes, SDL_AudioDeviceID device, int16 *audioBuffer);
+static void PlayAudio(Snes *snes, SDL_AudioDeviceID device, int channels, int16 *audioBuffer);
 static void RenderScreen(SDL_Window *window, SDL_Renderer *renderer, SDL_Texture *texture, bool fullscreen);
 static void HandleInput(int keyCode, int modCode, bool pressed);
 static void HandleGamepadInput(int button, bool pressed);
@@ -176,8 +176,9 @@
       g_config.audio_freq = kDefaultFreq;
   
   // audio_channels: As of SDL 2.0, supported values are 1 (mono), 2 (stereo), 4 (quad), and 6 (5.1).
+  // Currently, the SPC/DSP implementation only supports up to stereo.
   uint8 c = g_config.audio_channels;
-  if (c == 0 || c == 3 || c == 5 || c > 6)
+  if (c < 1 || c > 2)
       g_config.audio_channels = kDefaultChannels;
   
   // audio_samples: power of 2
@@ -229,7 +230,7 @@
     return 1;
   }
   g_samples_per_block = (534 * have.freq) / 32000;
-  int16_t* audioBuffer = (int16_t * )malloc(g_samples_per_block * 2 * sizeof(int16));
+  int16_t *audioBuffer = (int16_t * )malloc(g_samples_per_block * have.channels * sizeof(int16));
   SDL_PauseAudioDevice(device, 0);
 
   Snes *snes = snes_init(g_emulated_ram), *snes_run = NULL;
@@ -321,7 +322,7 @@
     if (is_turbo)
       continue;
 
-    PlayAudio(snes_run, device, audioBuffer);
+    PlayAudio(snes_run, device, have.channels, audioBuffer);
     RenderScreen(window, renderer, texture, (g_win_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0);
 
     SDL_RenderPresent(renderer); // vsyncs to 60 FPS
@@ -360,7 +361,7 @@
   return 0;
 }
 
-static void PlayAudio(Snes *snes, SDL_AudioDeviceID device, int16 *audioBuffer) {
+static void PlayAudio(Snes *snes, SDL_AudioDeviceID device, int channels, int16 *audioBuffer) {
   // generate enough samples
   if (snes) {
     while (snes->apu->dsp->sampleOffset < 534)
@@ -368,12 +369,11 @@
     snes->apu->dsp->sampleOffset = 0;
   }
 
-  dsp_getSamples(GetDspForRendering(), audioBuffer, g_samples_per_block);
-
+  dsp_getSamples(GetDspForRendering(), audioBuffer, g_samples_per_block, channels);
   for (int i = 0; i < 10; i++) {
-    if (SDL_GetQueuedAudioSize(device) <= g_samples_per_block * 4 * 6) {
+    if (SDL_GetQueuedAudioSize(device) <= g_samples_per_block * channels * sizeof(int16) * 6) {
       // don't queue audio if buffer is still filled
-      SDL_QueueAudio(device, audioBuffer, g_samples_per_block * 4);
+      SDL_QueueAudio(device, audioBuffer, g_samples_per_block * channels * sizeof(int16));
       return;
     }
     SDL_Delay(1);
--- a/snes/dsp.c
+++ b/snes/dsp.c
@@ -5,6 +5,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include <limits.h>
 #include "dsp_regs.h"
 #include "dsp.h"
 
@@ -633,14 +634,26 @@
   dsp->ram[adr] = val;
 }
 
-void dsp_getSamples(Dsp* dsp, int16_t* sampleData, int samplesPerFrame) {
+void dsp_getSamples(Dsp* dsp, int16_t* sampleData, int samplesPerFrame, int numChannels) {
   // resample from 534 samples per frame to wanted value
   float adder = 534.0 / samplesPerFrame;
   float location = 0.0;
-  for(int i = 0; i < samplesPerFrame; i++) {
-    sampleData[i * 2] = dsp->sampleBuffer[((int) location) * 2];
-    sampleData[i * 2 + 1] = dsp->sampleBuffer[((int) location) * 2 + 1];
-    location += adder;
+
+  if (numChannels == 1) {
+    for (int i = 0; i < samplesPerFrame; i++) {
+      int sampleL = dsp->sampleBuffer[((int)location) * 2];
+      int sampleR = dsp->sampleBuffer[((int)location) * 2 + 1];
+      sampleData[i] = (sampleL + sampleR) >> 1;
+      location += adder;
+    }
+  } else {
+    for (int i = 0; i < samplesPerFrame; i++) {
+      int sampleL = dsp->sampleBuffer[((int)location) * 2];
+      int sampleR = dsp->sampleBuffer[((int)location) * 2 + 1];
+      sampleData[i * 2] = sampleL;
+      sampleData[i * 2 + 1] = sampleR;
+      location += adder;
+    }
   }
   dsp->sampleOffset = 0;
 }
--- a/snes/dsp.h
+++ b/snes/dsp.h
@@ -94,7 +94,7 @@
 void dsp_cycle(Dsp* dsp);
 uint8_t dsp_read(Dsp* dsp, uint8_t adr);
 void dsp_write(Dsp* dsp, uint8_t adr, uint8_t val);
-void dsp_getSamples(Dsp* dsp, int16_t* sampleData, int samplesPerFrame);
+void dsp_getSamples(Dsp* dsp, int16_t* sampleData, int samplesPerFrame, int numChannels);
 void dsp_saveload(Dsp *dsp, SaveLoadFunc *func, void *ctx);
 
 #endif
--- a/spc_player.c
+++ b/spc_player.c
@@ -1368,8 +1368,8 @@
       SpcPlayer_GenerateSamples(p);
 
       int16_t audioBuffer[736 * 2];
-      dsp_getSamples(p->dsp, audioBuffer, 736);
-      SDL_QueueAudio(device, audioBuffer, 736 * 4);
+      dsp_getSamples(p->dsp, audioBuffer, 736, have.channels);
+      SDL_QueueAudio(device, audioBuffer, 736 * 2 * have.channels);
       while (SDL_GetQueuedAudioSize(device) >= 736 * 4 * 3/* 44100 * 4 * 300*/)
         SDL_Delay(1);
 
@@ -1435,8 +1435,8 @@
 
       if (p->dsp->sampleOffset == 534) {
         int16_t audioBuffer[736 * 2];
-        dsp_getSamples(p->dsp, audioBuffer, 736);
-        SDL_QueueAudio(device, audioBuffer, 736 * 4);
+        dsp_getSamples(p->dsp, audioBuffer, 736, have.channels);
+        SDL_QueueAudio(device, audioBuffer, 736 * 2 * have.channels);
         while (SDL_GetQueuedAudioSize(device) >= 736 * 4 * 3/* 44100 * 4 * 300*/) {
           SDL_Delay(1);
         }