APU: Remove extra buffers.

This commit is contained in:
Brandon Wright 2019-02-09 12:03:34 -06:00
parent 8c9c3eb6a4
commit e938225cd2
7 changed files with 61 additions and 98 deletions

View File

@ -22,12 +22,11 @@ static const int APU_DENOMINATOR_NTSC = 328125;
static const int APU_NUMERATOR_PAL = 34176;
static const int APU_DENOMINATOR_PAL = 709379;
// Max number of sample frames we'll ever generate before call to port API and
// Max number of samples we'll ever generate before call to port API and
// moving the samples to the resampler.
// This is 535 sample frames, which corresponds to 1 video frame + some leeway
// for use with SoundSync.
static const int MAX_SAMPLE_FRAMES = 600;
static const int SAMPLE_FRAMES_LIMIT = 550;
// for use with SoundSync, multiplied by 2, for left and right samples.
static const int MINIMUM_BUFFER_SIZE = 550 * 2;
namespace SNES
{
@ -42,7 +41,6 @@ static void *callback_data = NULL;
static bool8 sound_in_sync = TRUE;
static bool8 sound_enabled = FALSE;
static uint16 dsp_buffer[MAX_SAMPLE_FRAMES * 2];
static Resampler *resampler = NULL;
@ -62,10 +60,8 @@ static double dynamic_rate_multiplier = 1.0;
namespace msu
{
// Always 16-bit, Stereo; 1.5x dsp buffer to never overflow
static const int buffer_size = MAX_SAMPLE_FRAMES * 6;
static uint8 mixing_buffer[buffer_size];
static Resampler *resampler = NULL;
static std::vector<uint16> resample_buffer;
static std::vector<int16> resample_buffer;
} // namespace msu
static void UpdatePlaybackRate(void);
@ -73,12 +69,6 @@ static void SPCSnapshotCallback(void);
static inline int S9xAPUGetClock(int32);
static inline int S9xAPUGetClockRemainder(int32);
static void reset_dsp_output()
{
SNES::dsp.spc_dsp.set_output((SNES::SPC_DSP::sample_t *)spc::dsp_buffer,
MAX_SAMPLE_FRAMES * 2);
}
bool8 S9xMixSamples(uint8 *dest, int sample_count)
{
int16 *out = (int16 *)dest;
@ -86,10 +76,7 @@ bool8 S9xMixSamples(uint8 *dest, int sample_count)
if (Settings.Mute)
{
memset(out, 0, sample_count << 1);
spc::resampler->clear();
if (Settings.MSU1)
msu::resampler->clear();
S9xClearSamples();
}
else
{
@ -119,6 +106,11 @@ bool8 S9xMixSamples(uint8 *dest, int sample_count)
}
}
if (spc::resampler->space_empty() >= 535 * 2)
spc::sound_in_sync = true;
else
spc::sound_in_sync = false;
return true;
}
@ -129,57 +121,17 @@ int S9xGetSampleCount(void)
void S9xFinalizeSamples(void)
{
if (!Settings.Mute)
{
if (!spc::resampler->push((short *)spc::dsp_buffer,
SNES::dsp.spc_dsp.sample_count()))
{
// Don't drop samples if SoundSync is enabled. The port will wait
// and call S9xSyncSound again to catch up.
// If the sample count is over a frame, it indicates the port
// didn't implement SoundSync correctly.
if (Settings.SoundSync && !Settings.TurboMode && !Settings.Mute &&
SNES::dsp.spc_dsp.sample_count() < SAMPLE_FRAMES_LIMIT)
{
spc::sound_in_sync = false;
return;
}
spc::resampler->clear();
spc::resampler->push((short *)spc::dsp_buffer,
SNES::dsp.spc_dsp.sample_count());
if (Settings.MSU1)
msu::resampler->clear();
}
}
// only generate msu1 if we really consumed the dsp samples (sample_count() resets at end of function),
// otherwise we will generate multiple times for the same samples - so this needs to be after all early
// function returns
if (Settings.MSU1)
{
// generate the same number of msu1 samples as dsp samples were generated
S9xMSU1SetOutput((int16 *)msu::mixing_buffer, msu::buffer_size);
S9xMSU1Generate(SNES::dsp.spc_dsp.sample_count());
if (!msu::resampler->push((short *)msu::mixing_buffer, S9xMSU1Samples()))
{
// should not occur, msu buffer is larger and we drop msu samples if spc buffer overruns
assert(0);
}
}
spc::sound_in_sync = true;
reset_dsp_output();
}
void S9xLandSamples(void)
{
if (spc::callback != NULL)
spc::callback(spc::callback_data);
if (spc::resampler->space_empty() >= 535 * 2)
spc::sound_in_sync = true;
else
S9xFinalizeSamples();
spc::sound_in_sync = false;
}
void S9xClearSamples(void)
@ -237,9 +189,11 @@ static void UpdatePlaybackRate(void)
bool8 S9xInitSound(int buffer_ms, int unused2)
{
// The resampler and spc unit use samples (16-bit short) as arguments.
int buffer_size_samples = MAX_SAMPLE_FRAMES * 2;
if (buffer_ms > 0)
buffer_size_samples = Settings.SoundPlaybackRate * buffer_ms * 2 / 1000;
int buffer_size_samples = MINIMUM_BUFFER_SIZE;
int requested_buffer_size_samples = Settings.SoundPlaybackRate * buffer_ms * 2 / 1000;
if (requested_buffer_size_samples > buffer_size_samples)
buffer_size_samples = requested_buffer_size_samples;
if (!spc::resampler)
{
@ -247,6 +201,9 @@ bool8 S9xInitSound(int buffer_ms, int unused2)
if (!spc::resampler)
return (FALSE);
}
else
spc::resampler->resize(buffer_size_samples);
if (!msu::resampler)
{
@ -257,7 +214,8 @@ bool8 S9xInitSound(int buffer_ms, int unused2)
else
msu::resampler->resize(buffer_size_samples * 3 / 2);
reset_dsp_output();
SNES::dsp.spc_dsp.set_output(spc::resampler);
S9xMSU1SetOutput(msu::resampler);
UpdatePlaybackRate();
@ -358,7 +316,7 @@ void S9xAPUEndScanline(void)
S9xAPUExecute();
SNES::dsp.synchronize();
if (SNES::dsp.spc_dsp.sample_count() >= APU_SAMPLE_BLOCK || !spc::sound_in_sync)
if (spc::resampler->space_filled() >= APU_SAMPLE_BLOCK || !spc::sound_in_sync)
S9xLandSamples();
}
@ -385,13 +343,9 @@ void S9xResetAPU(void)
SNES::cpu.frequency = Settings.PAL ? PAL_MASTER_CLOCK : NTSC_MASTER_CLOCK;
SNES::smp.power();
SNES::dsp.power();
reset_dsp_output();
SNES::dsp.spc_dsp.set_spc_snapshot_callback(SPCSnapshotCallback);
spc::resampler->clear();
if (Settings.MSU1)
msu::resampler->clear();
S9xClearSamples();
}
void S9xSoftResetAPU(void)
@ -401,12 +355,8 @@ void S9xSoftResetAPU(void)
SNES::cpu.reset();
SNES::smp.reset();
SNES::dsp.reset();
reset_dsp_output();
spc::resampler->clear();
if (Settings.MSU1)
msu::resampler->clear();
S9xClearSamples();
}
void S9xAPUSaveState(uint8 *block)

View File

@ -64,7 +64,19 @@ static BOOST::uint8_t const initial_regs [SPC_DSP::register_count] =
out [0] = l;\
out [1] = r;\
out += 2;\
}\
}
#define SPC_DSP_OUT_HOOK(l, r) \
{ \
resampler->push_sample(l, r); \
if (Settings.MSU1) \
S9xMSU1Generate(2); \
}
void SPC_DSP::set_output( Resampler *resampler )
{
this->resampler = resampler;
}
void SPC_DSP::set_output( sample_t* out, int size )
{

View File

@ -22,6 +22,8 @@ public:
typedef short sample_t;
void set_output( sample_t* out, int out_size );
void set_output( Resampler* resampler );
// Number of samples written to output since it was last set, always
// a multiple of 2. Undefined if more samples were generated than
// output buffer could hold.
@ -135,6 +137,8 @@ public:
private:
enum { brr_block_size = 9 };
Resampler *resampler;
struct state_t
{
uint8_t regs [register_count];
@ -193,6 +197,7 @@ private:
// non-emulation state
uint8_t* ram; // 64K shared RAM between DSP and SMP
int mute_mask;
sample_t* out;
sample_t* out_end;
sample_t* out_begin;

View File

@ -2,6 +2,8 @@
#define __SNES_HPP
#include "../../../snes9x.h"
#include "../../resampler.h"
#include "../../../msu1.h"
#define SNES9X

View File

@ -23,7 +23,7 @@ struct Resampler
float r_frac;
int r_left[4], r_right[4];
static inline int16_t short_clamp(int16_t n)
static inline int16_t short_clamp(int n)
{
return (int16_t)(((int16_t)n != n) ? (n >> 31) ^ 0x7fff : n);
}

View File

@ -18,7 +18,7 @@ uint32 audioLoopPos;
size_t partial_frames;
// Sample buffer
int16 *bufPos, *bufBegin, *bufEnd;
static Resampler *msu_resampler = NULL;
#ifdef UNZIP_SUPPORT
static int unzFindExtension(unzFile &file, const char *ext, bool restart = TRUE, bool print = TRUE, bool allowExact = FALSE)
@ -174,10 +174,8 @@ void S9xResetMSU(void)
MSU1.MSU1_AUDIO_POS = 0;
MSU1.MSU1_RESUME_POS = 0;
bufPos = 0;
bufBegin = 0;
bufEnd = 0;
if (msu_resampler)
msu_resampler->clear();
partial_frames = 0;
@ -231,7 +229,7 @@ void S9xMSU1Generate(size_t sample_count)
{
partial_frames += 4410 * (sample_count / 2);
while ((bufPos < (bufEnd - 2)) && partial_frames >= 3204)
while (partial_frames >= 3204)
{
if (MSU1.MSU1_STATUS & AudioPlaying && audioStream)
{
@ -245,9 +243,7 @@ void S9xMSU1Generate(size_t sample_count)
*left = ((int32)(int16)GET_LE16(left) * MSU1.MSU1_VOLUME / 255);
*right = ((int32)(int16)GET_LE16(right) * MSU1.MSU1_VOLUME / 255);
*(bufPos++) = *left;
*(bufPos++) = *right;
msu_resampler->push_sample(*left, *right);
MSU1.MSU1_AUDIO_POS += 4;
partial_frames -= 3204;
}
@ -274,8 +270,7 @@ void S9xMSU1Generate(size_t sample_count)
{
MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating);
partial_frames -= 3204;
*(bufPos++) = 0;
*(bufPos++) = 0;
msu_resampler->push_sample(0, 0);
}
}
}
@ -392,13 +387,12 @@ void S9xMSU1WritePort(uint8 port, uint8 byte)
size_t S9xMSU1Samples(void)
{
return bufPos - bufBegin;
return msu_resampler->space_filled();
}
void S9xMSU1SetOutput(int16 * out, size_t size)
void S9xMSU1SetOutput(Resampler *resampler)
{
bufPos = bufBegin = out;
bufEnd = out + size;
msu_resampler = resampler;
}
void S9xMSU1PostLoadState(void)
@ -427,9 +421,8 @@ void S9xMSU1PostLoadState(void)
}
}
bufPos = 0;
bufBegin = 0;
bufEnd = 0;
if (msu_resampler)
msu_resampler->clear();
partial_frames = 0;
}

3
msu1.h
View File

@ -7,6 +7,7 @@
#ifndef _MSU1_H_
#define _MSU1_H_
#include "snes9x.h"
#include "apu/resampler.h"
#define MSU1_REVISION 0x02
@ -51,7 +52,7 @@ void S9xMSU1Generate(size_t sample_count);
uint8 S9xMSU1ReadPort(uint8 port);
void S9xMSU1WritePort(uint8 port, uint8 byte);
size_t S9xMSU1Samples(void);
void S9xMSU1SetOutput(int16 *out, size_t size);
void S9xMSU1SetOutput(Resampler *resampler);
void S9xMSU1PostLoadState(void);
#endif