BSNESv115+: Replace the 'snes_audio_sample' callback with a dynamic audio sample vector to reduce callbacks (#3010)
* BSNESv115+: Replace the 'snes_audio_sample' callback with a dynamic audio sample vector to reduce callbacks * fix integration for subbsnes core * reduce buffer allocations - also make frame setter private now that it's possible
This commit is contained in:
parent
f1e11dfc36
commit
039d822144
Binary file not shown.
|
@ -24,6 +24,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract void snes_set_hooks_enabled(bool readHookEnabled, bool writeHookEnabled, bool executeHookEnabled);
|
||||
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract short* snes_get_audiobuffer_and_size(out int size);
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
public abstract BsnesApi.SNES_REGION snes_get_region();
|
||||
[BizImport(CallingConvention.Cdecl)]
|
||||
|
@ -167,7 +169,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
}
|
||||
|
||||
public delegate void snes_video_frame_t(ushort* data, int width, int height, int pitch);
|
||||
public delegate void snes_audio_sample_t(short left, short right);
|
||||
public delegate short snes_input_poll_t(int port, int index, int id);
|
||||
public delegate void snes_controller_latch_t();
|
||||
public delegate void snes_no_lag_t(bool sgb_poll);
|
||||
|
@ -218,7 +219,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
public sealed class SnesCallbacks
|
||||
{
|
||||
public snes_video_frame_t videoFrameCb;
|
||||
public snes_audio_sample_t audioSampleCb;
|
||||
public snes_input_poll_t inputPollCb;
|
||||
public snes_controller_latch_t controllerLatchCb;
|
||||
public snes_no_lag_t noLagCb;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
||||
{
|
||||
|
@ -8,12 +11,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
|
||||
public ControllerDefinition ControllerDefinition => _controllers.Definition;
|
||||
|
||||
private short[] _audioBuffer = Array.Empty<short>();
|
||||
|
||||
public bool FrameAdvance(IController controller, bool render, bool renderSound)
|
||||
{
|
||||
FrameAdvancePre(controller, render, renderSound);
|
||||
|
||||
IsLagFrame = true;
|
||||
|
||||
bool resetSignal = controller.IsPressed("Reset");
|
||||
if (resetSignal)
|
||||
{
|
||||
|
@ -26,14 +29,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
Api.core.snes_power();
|
||||
}
|
||||
|
||||
IsLagFrame = true;
|
||||
// run the core for one frame
|
||||
Api.core.snes_run(false);
|
||||
Frame++;
|
||||
|
||||
if (IsLagFrame)
|
||||
{
|
||||
LagCount++;
|
||||
}
|
||||
FrameAdvancePost();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -65,7 +64,32 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
Api.core.snes_set_audio_enabled(renderSound);
|
||||
}
|
||||
|
||||
public int Frame { get; set; }
|
||||
internal void FrameAdvancePost()
|
||||
{
|
||||
int numSamples = UpdateAudioBuffer();
|
||||
_soundProvider.PutSamples(_audioBuffer, numSamples / 2);
|
||||
Frame++;
|
||||
|
||||
if (IsLagFrame)
|
||||
{
|
||||
LagCount++;
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe int UpdateAudioBuffer()
|
||||
{
|
||||
using (Api.exe.EnterExit())
|
||||
{
|
||||
short* rawAudioBuffer = Api.core.snes_get_audiobuffer_and_size(out int size);
|
||||
if (size > _audioBuffer.Length)
|
||||
_audioBuffer = new short[size];
|
||||
Marshal.Copy((IntPtr) rawAudioBuffer, _audioBuffer, 0, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
public int Frame { get; private set; }
|
||||
|
||||
public string SystemId => VSystemID.Raw.SNES;
|
||||
|
||||
|
@ -86,7 +110,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
}
|
||||
|
||||
Api.Dispose();
|
||||
_resampler.Dispose();
|
||||
_currentMsuTrack?.Dispose();
|
||||
|
||||
_disposed = true;
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.IO;
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.Base_Implementations;
|
||||
using BizHawk.Emulation.Cores.Components.W65816;
|
||||
|
||||
// http://wiki.superfamicom.org/snes/show/Backgrounds
|
||||
|
@ -47,7 +48,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
noLagCb = snes_no_lag,
|
||||
controllerLatchCb = snes_controller_latch,
|
||||
videoFrameCb = snes_video_refresh,
|
||||
audioSampleCb = snes_audio_sample,
|
||||
pathRequestCb = snes_path_request,
|
||||
traceCb = snes_trace,
|
||||
readHookCb = ReadHook,
|
||||
|
@ -80,7 +80,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
|
||||
// start up audio resampler
|
||||
InitAudio();
|
||||
ser.Register<ISoundProvider>(_resampler);
|
||||
ser.Register<ISoundProvider>(_soundProvider);
|
||||
|
||||
if (IsSGB)
|
||||
{
|
||||
|
@ -124,7 +124,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
private readonly ITraceable _tracer;
|
||||
|
||||
private IController _controller;
|
||||
private SpeexResampler _resampler;
|
||||
private SimpleSyncSoundProvider _soundProvider;
|
||||
private readonly string _romPath;
|
||||
private bool _disposed;
|
||||
|
||||
|
@ -284,12 +284,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
|
||||
private void InitAudio()
|
||||
{
|
||||
_resampler = new SpeexResampler(SpeexResampler.Quality.QUALITY_DESKTOP, 64080, 88200, 32040, 44100);
|
||||
}
|
||||
|
||||
private void snes_audio_sample(short left, short right)
|
||||
{
|
||||
_resampler.EnqueueSample(left, right);
|
||||
_soundProvider = new SimpleSyncSoundProvider();
|
||||
}
|
||||
|
||||
private void snes_trace(string disassembly, string registerInfo)
|
||||
|
|
|
@ -80,12 +80,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
|
|||
framePassed = _bsnesCore.Api.core.snes_run(subFrameRequested);
|
||||
}
|
||||
|
||||
_bsnesCore.Frame++;
|
||||
|
||||
if (framePassed && _bsnesCore.IsLagFrame)
|
||||
_bsnesCore.LagCount++;
|
||||
else
|
||||
_bsnesCore.IsLagFrame = false;
|
||||
if (!framePassed) _bsnesCore.IsLagFrame = false;
|
||||
_bsnesCore.FrameAdvancePost();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ auto ICD::ppuWrite(uint2 color) -> void {
|
|||
|
||||
auto ICD::apuWrite(float left, float right) -> void {
|
||||
double samples[] = {left, right};
|
||||
if(!system.runAhead && system.renderAudio) stream->write(samples);
|
||||
if(!system.runAhead && system.renderAudio && !scheduler.StepOnce) stream->write(samples);
|
||||
}
|
||||
|
||||
auto ICD::joypWrite(bool p14, bool p15) -> void {
|
||||
|
|
|
@ -42,7 +42,7 @@ auto MSU1::main() -> void {
|
|||
}
|
||||
}
|
||||
|
||||
if(!system.runAhead && system.renderAudio) stream->sample(float(left), float(right));
|
||||
if(!system.runAhead && system.renderAudio && !scheduler.StepOnce) stream->sample(float(left), float(right));
|
||||
step(1);
|
||||
synchronizeCPU();
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ auto DSP::main() -> void {
|
|||
|
||||
int count = spc_dsp.sample_count();
|
||||
if(count > 0) {
|
||||
if(!system.runAhead && system.renderAudio)
|
||||
if(!system.runAhead && system.renderAudio && !scheduler.StepOnce)
|
||||
for(uint n = 0; n < count; n += 2) {
|
||||
float left = samplebuffer[n + 0] / 32768.0f;
|
||||
float right = samplebuffer[n + 1] / 32768.0f;
|
||||
|
|
|
@ -146,8 +146,7 @@ EXPORT void snes_init(SnesInitData* init_data)
|
|||
emulator->configure("Hacks/Coprocessor/DelayedSync", init_data->fast_coprocessors);
|
||||
|
||||
emulator->configure("Video/BlurEmulation", false); // blurs the video when not using fast ppu. I don't like it so I disable it here :)
|
||||
// needed in order to get audio sync working. should probably figure out what exactly this does or how to change that properly
|
||||
Emulator::audio.setFrequency(SAMPLE_RATE);
|
||||
Emulator::audio.setFrequency(44100); // default is 48000, but bizhawk expects 44100
|
||||
|
||||
program->regionOverride = init_data->region_override;
|
||||
}
|
||||
|
@ -172,6 +171,7 @@ EXPORT void snes_reset(void)
|
|||
EXPORT bool snes_run(bool breakOnLatch)
|
||||
{
|
||||
program->breakOnLatch = breakOnLatch;
|
||||
audioBuffer.clear();
|
||||
emulator->run();
|
||||
return scheduler.event == Scheduler::Event::Frame;
|
||||
}
|
||||
|
@ -294,6 +294,11 @@ EXPORT System::Region snes_get_region(void) {
|
|||
return SuperFamicom::system.region();
|
||||
}
|
||||
|
||||
EXPORT short* snes_get_audiobuffer_and_size(int& out_size) {
|
||||
out_size = audioBuffer.size();
|
||||
return audioBuffer.data();
|
||||
}
|
||||
|
||||
EXPORT char snes_get_mapper(void) {
|
||||
string board = program->superFamicom.document["game/board"].text();
|
||||
string mapper = board.split('-', 1)[0];
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
#define EXPORT ECL_EXPORT
|
||||
|
||||
#define SAMPLE_RATE 32040
|
||||
|
||||
enum SNES_MEMORY {
|
||||
CARTRIDGE_RAM,
|
||||
CARTRIDGE_ROM,
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include <stdint.h>
|
||||
|
||||
typedef void (*snes_video_frame_t)(const uint16_t* data, int width, int height, int pitch);
|
||||
typedef void (*snes_audio_sample_t)(int16_t left, int16_t right);
|
||||
typedef int16_t (*snes_input_poll_t)(int port, int index, int id);
|
||||
typedef void (*snes_controller_latch_t)(void);
|
||||
typedef void (*snes_no_lag_t)(bool sgb_poll);
|
||||
|
@ -20,7 +19,6 @@ typedef bool (*snes_msu_end_t)(void);
|
|||
|
||||
struct SnesCallbacks {
|
||||
snes_video_frame_t snes_video_frame;
|
||||
snes_audio_sample_t snes_audio_sample;
|
||||
snes_input_poll_t snes_input_poll;
|
||||
snes_controller_latch_t snes_controller_latch;
|
||||
snes_no_lag_t snes_no_lag;
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
|
||||
#include "resources.hpp"
|
||||
#include <nall/vfs/biz_file.hpp>
|
||||
#include <vector>
|
||||
|
||||
static Emulator::Interface *emulator;
|
||||
static std::vector<short> audioBuffer;
|
||||
|
||||
struct Program : Emulator::Platform
|
||||
{
|
||||
|
@ -453,9 +455,8 @@ static int16_t d2i16(double v)
|
|||
|
||||
auto Program::audioFrame(const double* samples, uint channels) -> void
|
||||
{
|
||||
int16_t left = d2i16(samples[0]);
|
||||
int16_t right = d2i16(samples[1]);
|
||||
return snesCallbacks.snes_audio_sample(left, right);
|
||||
audioBuffer.push_back(d2i16(samples[0]));
|
||||
audioBuffer.push_back(d2i16(samples[1]));
|
||||
}
|
||||
|
||||
auto Program::notify(string message) -> void
|
||||
|
|
Loading…
Reference in New Issue