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);
}