DSP: Add option to enable/disable AAC

This commit is contained in:
wheremyfoodat 2024-11-28 17:47:36 +02:00
parent 93c143d79d
commit b251f84ab1
13 changed files with 44 additions and 23 deletions

View file

@ -18,7 +18,8 @@ namespace Audio::AAC {
public: public:
// Decode function. Takes in a reference to the AAC response & request, and a callback for paddr -> pointer conversions // Decode function. Takes in a reference to the AAC response & request, and a callback for paddr -> pointer conversions
void decode(AAC::Message& response, const AAC::Message& request, PaddrCallback paddrCallback); // We also allow for optionally muting the AAC output (setting all of it to 0) instead of properly decoding it, for debug/research purposes
void decode(AAC::Message& response, const AAC::Message& request, PaddrCallback paddrCallback, bool enableAudio = false);
~Decoder(); ~Decoder();
}; };
} // namespace Audio::AAC } // namespace Audio::AAC

View file

@ -14,6 +14,7 @@
// The DSP core must have access to the DSP service to be able to trigger interrupts properly // The DSP core must have access to the DSP service to be able to trigger interrupts properly
class DSPService; class DSPService;
class Memory; class Memory;
struct EmulatorConfig;
namespace Audio { namespace Audio {
// There are 160 stereo samples in 1 audio frame, so 320 samples total // There are 160 stereo samples in 1 audio frame, so 320 samples total
@ -31,6 +32,7 @@ namespace Audio {
Memory& mem; Memory& mem;
Scheduler& scheduler; Scheduler& scheduler;
DSPService& dspService; DSPService& dspService;
EmulatorConfig& settings;
Samples sampleBuffer; Samples sampleBuffer;
bool audioEnabled = false; bool audioEnabled = false;
@ -39,7 +41,8 @@ namespace Audio {
public: public:
enum class Type { Null, Teakra, HLE }; enum class Type { Null, Teakra, HLE };
DSPCore(Memory& mem, Scheduler& scheduler, DSPService& dspService) : mem(mem), scheduler(scheduler), dspService(dspService) {} DSPCore(Memory& mem, Scheduler& scheduler, DSPService& dspService, EmulatorConfig& settings)
: mem(mem), scheduler(scheduler), dspService(dspService), settings(settings) {}
virtual ~DSPCore() {} virtual ~DSPCore() {}
virtual void reset() = 0; virtual void reset() = 0;
@ -62,5 +65,5 @@ namespace Audio {
virtual void setAudioEnabled(bool enable) { audioEnabled = enable; } virtual void setAudioEnabled(bool enable) { audioEnabled = enable; }
}; };
std::unique_ptr<DSPCore> makeDSPCore(DSPCore::Type type, Memory& mem, Scheduler& scheduler, DSPService& dspService); std::unique_ptr<DSPCore> makeDSPCore(EmulatorConfig& config, Memory& mem, Scheduler& scheduler, DSPService& dspService);
} // namespace Audio } // namespace Audio

View file

@ -206,7 +206,7 @@ namespace Audio {
SampleBuffer decodeADPCM(const u8* data, usize sampleCount, Source& source); SampleBuffer decodeADPCM(const u8* data, usize sampleCount, Source& source);
public: public:
HLE_DSP(Memory& mem, Scheduler& scheduler, DSPService& dspService); HLE_DSP(Memory& mem, Scheduler& scheduler, DSPService& dspService, EmulatorConfig& config);
~HLE_DSP() override {} ~HLE_DSP() override {}
void reset() override; void reset() override;

View file

@ -23,7 +23,7 @@ namespace Audio {
bool loaded = false; // Have we loaded a component? bool loaded = false; // Have we loaded a component?
public: public:
NullDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService) : DSPCore(mem, scheduler, dspService) {} NullDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService, EmulatorConfig& config) : DSPCore(mem, scheduler, dspService, config) {}
~NullDSP() override {} ~NullDSP() override {}
void reset() override; void reset() override;

View file

@ -77,7 +77,7 @@ namespace Audio {
} }
public: public:
TeakraDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService); TeakraDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService, EmulatorConfig& config);
~TeakraDSP() override {} ~TeakraDSP() override {}
void reset() override; void reset() override;

View file

@ -41,6 +41,7 @@ struct EmulatorConfig {
bool audioEnabled = false; bool audioEnabled = false;
bool vsyncEnabled = true; bool vsyncEnabled = true;
bool aacEnabled = true; // Enable AAC audio?
bool enableRenderdoc = false; bool enableRenderdoc = false;
bool printAppVersion = true; bool printAppVersion = true;

View file

@ -96,7 +96,9 @@ void EmulatorConfig::load() {
auto dspCoreName = toml::find_or<std::string>(audio, "DSPEmulation", "HLE"); auto dspCoreName = toml::find_or<std::string>(audio, "DSPEmulation", "HLE");
dspType = Audio::DSPCore::typeFromString(dspCoreName); dspType = Audio::DSPCore::typeFromString(dspCoreName);
audioEnabled = toml::find_or<toml::boolean>(audio, "EnableAudio", false); audioEnabled = toml::find_or<toml::boolean>(audio, "EnableAudio", false);
aacEnabled = toml::find_or<toml::boolean>(audio, "EnableAACAudio", true);
} }
} }
@ -167,6 +169,7 @@ void EmulatorConfig::save() {
data["Audio"]["DSPEmulation"] = std::string(Audio::DSPCore::typeToString(dspType)); data["Audio"]["DSPEmulation"] = std::string(Audio::DSPCore::typeToString(dspType));
data["Audio"]["EnableAudio"] = audioEnabled; data["Audio"]["EnableAudio"] = audioEnabled;
data["Audio"]["EnableAACAudio"] = aacEnabled;
data["Battery"]["ChargerPlugged"] = chargerPlugged; data["Battery"]["ChargerPlugged"] = chargerPlugged;
data["Battery"]["BatteryPercentage"] = batteryPercentage; data["Battery"]["BatteryPercentage"] = batteryPercentage;

View file

@ -5,7 +5,7 @@
#include <vector> #include <vector>
using namespace Audio; using namespace Audio;
void AAC::Decoder::decode(AAC::Message& response, const AAC::Message& request, AAC::Decoder::PaddrCallback paddrCallback) { void AAC::Decoder::decode(AAC::Message& response, const AAC::Message& request, AAC::Decoder::PaddrCallback paddrCallback, bool enableAudio) {
// Copy the command and mode fields of the request to the response // Copy the command and mode fields of the request to the response
response.command = request.command; response.command = request.command;
response.mode = request.mode; response.mode = request.mode;
@ -95,9 +95,18 @@ void AAC::Decoder::decode(AAC::Message& response, const AAC::Message& request, A
} }
} }
for (int sample = 0; sample < info->frameSize; sample++) { if (enableAudio) {
for (int stream = 0; stream < channels; stream++) { for (int sample = 0; sample < info->frameSize; sample++) {
audioStreams[stream].push_back(frame[(sample * channels) + stream]); for (int stream = 0; stream < channels; stream++) {
audioStreams[stream].push_back(frame[(sample * channels) + stream]);
}
}
} else {
// If audio is not enabled, push 0s
for (int sample = 0; sample < info->frameSize; sample++) {
for (int stream = 0; stream < channels; stream++) {
audioStreams[stream].push_back(0);
}
} }
} }
} else { } else {

View file

@ -8,17 +8,17 @@
#include "audio/null_core.hpp" #include "audio/null_core.hpp"
#include "audio/teakra_core.hpp" #include "audio/teakra_core.hpp"
std::unique_ptr<Audio::DSPCore> Audio::makeDSPCore(DSPCore::Type type, Memory& mem, Scheduler& scheduler, DSPService& dspService) { std::unique_ptr<Audio::DSPCore> Audio::makeDSPCore(EmulatorConfig& config, Memory& mem, Scheduler& scheduler, DSPService& dspService) {
std::unique_ptr<DSPCore> core; std::unique_ptr<DSPCore> core;
switch (type) { switch (config.dspType) {
case DSPCore::Type::Null: core = std::make_unique<NullDSP>(mem, scheduler, dspService); break; case DSPCore::Type::Null: core = std::make_unique<NullDSP>(mem, scheduler, dspService, config); break;
case DSPCore::Type::Teakra: core = std::make_unique<TeakraDSP>(mem, scheduler, dspService); break; case DSPCore::Type::Teakra: core = std::make_unique<TeakraDSP>(mem, scheduler, dspService, config); break;
case DSPCore::Type::HLE: core = std::make_unique<HLE_DSP>(mem, scheduler, dspService); break; case DSPCore::Type::HLE: core = std::make_unique<HLE_DSP>(mem, scheduler, dspService, config); break;
default: default:
Helpers::warn("Invalid DSP core selected!"); Helpers::warn("Invalid DSP core selected!");
core = std::make_unique<NullDSP>(mem, scheduler, dspService); core = std::make_unique<NullDSP>(mem, scheduler, dspService, config);
break; break;
} }

View file

@ -8,6 +8,7 @@
#include "audio/aac_decoder.hpp" #include "audio/aac_decoder.hpp"
#include "audio/dsp_simd.hpp" #include "audio/dsp_simd.hpp"
#include "config.hpp"
#include "services/dsp.hpp" #include "services/dsp.hpp"
namespace Audio { namespace Audio {
@ -20,7 +21,8 @@ namespace Audio {
}; };
} }
HLE_DSP::HLE_DSP(Memory& mem, Scheduler& scheduler, DSPService& dspService) : DSPCore(mem, scheduler, dspService) { HLE_DSP::HLE_DSP(Memory& mem, Scheduler& scheduler, DSPService& dspService, EmulatorConfig& config)
: DSPCore(mem, scheduler, dspService, config) {
// Set up source indices // Set up source indices
for (int i = 0; i < sources.size(); i++) { for (int i = 0; i < sources.size(); i++) {
sources[i].index = i; sources[i].index = i;
@ -713,9 +715,8 @@ namespace Audio {
response.command = request.command; response.command = request.command;
response.mode = request.mode; response.mode = request.mode;
// TODO: Make this a toggle in config.toml. Currently we have it on by default. // We allow disabling AAC audio. Mostly useful for debugging & figuring out if an audio track is AAC or not.
constexpr bool enableAAC = true; if (settings.aacEnabled) {
if (enableAAC) {
aacDecoder->decode(response, request, [this](u32 paddr) { return getPointerPhys<u8>(paddr); }); aacDecoder->decode(response, request, [this](u32 paddr) { return getPointerPhys<u8>(paddr); });
} }
break; break;

View file

@ -36,8 +36,8 @@ struct Dsp1 {
Segment segments[10]; Segment segments[10];
}; };
TeakraDSP::TeakraDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService) TeakraDSP::TeakraDSP(Memory& mem, Scheduler& scheduler, DSPService& dspService, EmulatorConfig& config)
: DSPCore(mem, scheduler, dspService), pipeBaseAddr(0), running(false) { : DSPCore(mem, scheduler, dspService, config), pipeBaseAddr(0), running(false) {
// Set up callbacks for Teakra // Set up callbacks for Teakra
Teakra::AHBMCallback ahbm; Teakra::AHBMCallback ahbm;

View file

@ -28,7 +28,7 @@ Emulator::Emulator()
{ {
DSPService& dspService = kernel.getServiceManager().getDSP(); DSPService& dspService = kernel.getServiceManager().getDSP();
dsp = Audio::makeDSPCore(config.dspType, memory, scheduler, dspService); dsp = Audio::makeDSPCore(config, memory, scheduler, dspService);
dspService.setDSPCore(dsp.get()); dspService.setDSPCore(dsp.get());
audioDevice.init(dsp->getSamples()); audioDevice.init(dsp->getSamples());

View file

@ -172,6 +172,7 @@ static void configInit() {
{"panda3ds_use_vsync", "Enable VSync; enabled|disabled"}, {"panda3ds_use_vsync", "Enable VSync; enabled|disabled"},
{"panda3ds_dsp_emulation", "DSP emulation; HLE|LLE|Null"}, {"panda3ds_dsp_emulation", "DSP emulation; HLE|LLE|Null"},
{"panda3ds_use_audio", "Enable audio; disabled|enabled"}, {"panda3ds_use_audio", "Enable audio; disabled|enabled"},
{"panda3ds_enable_aac", "Enable AAC audio; enabled|disabled"},
{"panda3ds_use_virtual_sd", "Enable virtual SD card; enabled|disabled"}, {"panda3ds_use_virtual_sd", "Enable virtual SD card; enabled|disabled"},
{"panda3ds_write_protect_virtual_sd", "Write protect virtual SD card; disabled|enabled"}, {"panda3ds_write_protect_virtual_sd", "Write protect virtual SD card; disabled|enabled"},
{"panda3ds_battery_level", "Battery percentage; 5|10|20|30|50|70|90|100"}, {"panda3ds_battery_level", "Battery percentage; 5|10|20|30|50|70|90|100"},
@ -194,6 +195,8 @@ static void configUpdate() {
config.batteryPercentage = fetchVariableRange("panda3ds_battery_level", 5, 100); config.batteryPercentage = fetchVariableRange("panda3ds_battery_level", 5, 100);
config.dspType = Audio::DSPCore::typeFromString(fetchVariable("panda3ds_dsp_emulation", "null")); config.dspType = Audio::DSPCore::typeFromString(fetchVariable("panda3ds_dsp_emulation", "null"));
config.audioEnabled = fetchVariableBool("panda3ds_use_audio", false); config.audioEnabled = fetchVariableBool("panda3ds_use_audio", false);
config.aacEnabled = fetchVariableBool("panda3ds_enable_aac", true);
config.sdCardInserted = fetchVariableBool("panda3ds_use_virtual_sd", true); config.sdCardInserted = fetchVariableBool("panda3ds_use_virtual_sd", true);
config.sdWriteProtected = fetchVariableBool("panda3ds_write_protect_virtual_sd", false); config.sdWriteProtected = fetchVariableBool("panda3ds_write_protect_virtual_sd", false);
config.accurateShaderMul = fetchVariableBool("panda3ds_accurate_shader_mul", false); config.accurateShaderMul = fetchVariableBool("panda3ds_accurate_shader_mul", false);