mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 23:25:40 +12:00
Merge pull request #649 from wheremyfoodat/volume
Audio: Add more settings
This commit is contained in:
commit
547d47d9dc
16 changed files with 119 additions and 48 deletions
|
@ -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 = true);
|
||||||
~Decoder();
|
~Decoder();
|
||||||
};
|
};
|
||||||
} // namespace Audio::AAC
|
} // namespace Audio::AAC
|
|
@ -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
|
|
@ -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;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
#include "miniaudio.h"
|
#include "miniaudio.h"
|
||||||
#include "ring_buffer.hpp"
|
#include "ring_buffer.hpp"
|
||||||
|
@ -12,12 +13,13 @@ class MiniAudioDevice {
|
||||||
static constexpr ma_uint32 sampleRate = 32768; // 3DS sample rate
|
static constexpr ma_uint32 sampleRate = 32768; // 3DS sample rate
|
||||||
static constexpr ma_uint32 channelCount = 2; // Audio output is stereo
|
static constexpr ma_uint32 channelCount = 2; // Audio output is stereo
|
||||||
|
|
||||||
|
ma_device device;
|
||||||
ma_context context;
|
ma_context context;
|
||||||
ma_device_config deviceConfig;
|
ma_device_config deviceConfig;
|
||||||
ma_device device;
|
|
||||||
ma_resampler resampler;
|
|
||||||
Samples* samples = nullptr;
|
Samples* samples = nullptr;
|
||||||
|
|
||||||
|
const AudioDeviceConfig& audioSettings;
|
||||||
|
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
bool running = false;
|
bool running = false;
|
||||||
|
|
||||||
|
@ -26,7 +28,8 @@ class MiniAudioDevice {
|
||||||
std::vector<std::string> audioDevices;
|
std::vector<std::string> audioDevices;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MiniAudioDevice();
|
MiniAudioDevice(const AudioDeviceConfig& audioSettings);
|
||||||
|
|
||||||
// If safe is on, we create a null audio device
|
// If safe is on, we create a null audio device
|
||||||
void init(Samples& samples, bool safe = false);
|
void init(Samples& samples, bool safe = false);
|
||||||
void close();
|
void close();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -4,6 +4,19 @@
|
||||||
#include "audio/dsp_core.hpp"
|
#include "audio/dsp_core.hpp"
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
|
|
||||||
|
struct AudioDeviceConfig {
|
||||||
|
float volumeRaw = 1.0f;
|
||||||
|
bool muteAudio = false;
|
||||||
|
|
||||||
|
float getVolume() const {
|
||||||
|
if (muteAudio) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return volumeRaw;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Remember to initialize every field here to its default value otherwise bad things will happen
|
// Remember to initialize every field here to its default value otherwise bad things will happen
|
||||||
struct EmulatorConfig {
|
struct EmulatorConfig {
|
||||||
// Only enable the shader JIT by default on platforms where it's completely tested
|
// Only enable the shader JIT by default on platforms where it's completely tested
|
||||||
|
@ -41,6 +54,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;
|
||||||
|
@ -70,6 +84,7 @@ struct EmulatorConfig {
|
||||||
};
|
};
|
||||||
|
|
||||||
WindowSettings windowSettings;
|
WindowSettings windowSettings;
|
||||||
|
AudioDeviceConfig audioDeviceConfig;
|
||||||
|
|
||||||
EmulatorConfig(const std::filesystem::path& path);
|
EmulatorConfig(const std::filesystem::path& path);
|
||||||
void load();
|
void load();
|
||||||
|
|
|
@ -96,7 +96,14 @@ 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);
|
||||||
|
|
||||||
|
audioDeviceConfig.muteAudio = toml::find_or<toml::boolean>(audio, "MuteAudio", false);
|
||||||
|
// Our volume ranges from 0.0 (muted) to 2.0 (boosted, using a logarithmic scale). 1.0 is the "default" volume, ie we don't adjust the PCM
|
||||||
|
// samples at all.
|
||||||
|
audioDeviceConfig.volumeRaw = float(std::clamp(toml::find_or<toml::floating>(audio, "AudioVolume", 1.0), 0.0, 2.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +174,9 @@ 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["Audio"]["MuteAudio"] = audioDeviceConfig.muteAudio;
|
||||||
|
data["Audio"]["AudioVolume"] = double(audioDeviceConfig.volumeRaw);
|
||||||
|
|
||||||
data["Battery"]["ChargerPlugged"] = chargerPlugged;
|
data["Battery"]["ChargerPlugged"] = chargerPlugged;
|
||||||
data["Battery"]["BatteryPercentage"] = batteryPercentage;
|
data["Battery"]["BatteryPercentage"] = batteryPercentage;
|
||||||
|
|
|
@ -370,12 +370,11 @@ void ShaderEmitter::storeRegister(Xmm source, const PICAShader& shader, u32 dest
|
||||||
} else if (haveSSE4_1) {
|
} else if (haveSSE4_1) {
|
||||||
// Bit reverse the write mask because that is what blendps expects
|
// Bit reverse the write mask because that is what blendps expects
|
||||||
u32 adjustedMask = ((writeMask >> 3) & 0b1) | ((writeMask >> 1) & 0b10) | ((writeMask << 1) & 0b100) | ((writeMask << 3) & 0b1000);
|
u32 adjustedMask = ((writeMask >> 3) & 0b1) | ((writeMask >> 1) & 0b10) | ((writeMask << 1) & 0b100) | ((writeMask << 3) & 0b1000);
|
||||||
// Don't accidentally overwrite scratch1 if that is what we're writing derp
|
|
||||||
Xmm temp = (source == scratch1) ? scratch2 : scratch1;
|
|
||||||
|
|
||||||
movaps(temp, xword[statePointer + offset]); // Read current value of dest
|
// Blend current value of dest with source. We have to invert the bits of the mask, as we do blendps source, dest instead of dest, source
|
||||||
blendps(temp, source, adjustedMask); // Blend with source
|
// Note: This destroys source
|
||||||
movaps(xword[statePointer + offset], temp); // Write back
|
blendps(source, xword[statePointer + offset], adjustedMask ^ 0xF);
|
||||||
|
movaps(xword[statePointer + offset], source); // Write back
|
||||||
} else {
|
} else {
|
||||||
// Blend algo referenced from Citra
|
// Blend algo referenced from Citra
|
||||||
const u8 selector = (((writeMask & 0b1000) ? 1 : 0) << 0) |
|
const u8 selector = (((writeMask & 0b1000) ? 1 : 0) << 0) |
|
||||||
|
|
|
@ -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,16 @@ void AAC::Decoder::decode(AAC::Message& response, const AAC::Message& request, A
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int sample = 0; sample < info->frameSize; sample++) {
|
if (enableAudio) {
|
||||||
|
for (int sample = 0; sample < info->frameSize; sample++) {
|
||||||
|
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 stream = 0; stream < channels; stream++) {
|
for (int stream = 0; stream < channels; stream++) {
|
||||||
audioStreams[stream].push_back(frame[(sample * channels) + stream]);
|
audioStreams[stream].resize(audioStreams[stream].size() + info->frameSize, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -702,24 +704,9 @@ namespace Audio {
|
||||||
AAC::Message response;
|
AAC::Message response;
|
||||||
|
|
||||||
switch (request.command) {
|
switch (request.command) {
|
||||||
case AAC::Command::EncodeDecode: {
|
case AAC::Command::EncodeDecode:
|
||||||
// Dummy response to stop games from hanging
|
aacDecoder->decode(response, request, [this](u32 paddr) { return getPointerPhys<u8>(paddr); }, settings.aacEnabled);
|
||||||
response.resultCode = AAC::ResultCode::Success;
|
|
||||||
response.decodeResponse.channelCount = 2;
|
|
||||||
response.decodeResponse.sampleCount = 1024;
|
|
||||||
response.decodeResponse.size = 0;
|
|
||||||
response.decodeResponse.sampleRate = AAC::SampleRate::Rate48000;
|
|
||||||
|
|
||||||
response.command = request.command;
|
|
||||||
response.mode = request.mode;
|
|
||||||
|
|
||||||
// TODO: Make this a toggle in config.toml. Currently we have it on by default.
|
|
||||||
constexpr bool enableAAC = true;
|
|
||||||
if (enableAAC) {
|
|
||||||
aacDecoder->decode(response, request, [this](u32 paddr) { return getPointerPhys<u8>(paddr); });
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case AAC::Command::Init:
|
case AAC::Command::Init:
|
||||||
case AAC::Command::Shutdown:
|
case AAC::Command::Shutdown:
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
#include "audio/miniaudio_device.hpp"
|
#include "audio/miniaudio_device.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
|
||||||
MiniAudioDevice::MiniAudioDevice() : initialized(false), running(false), samples(nullptr) {}
|
MiniAudioDevice::MiniAudioDevice(const AudioDeviceConfig& audioSettings)
|
||||||
|
: initialized(false), running(false), samples(nullptr), audioSettings(audioSettings) {}
|
||||||
|
|
||||||
void MiniAudioDevice::init(Samples& samples, bool safe) {
|
void MiniAudioDevice::init(Samples& samples, bool safe) {
|
||||||
this->samples = &samples;
|
this->samples = &samples;
|
||||||
|
@ -106,6 +110,40 @@ void MiniAudioDevice::init(Samples& samples, bool safe) {
|
||||||
std::memcpy(&self->lastStereoSample[0], &output[(samplesWritten - 1) * 2], sizeof(lastStereoSample));
|
std::memcpy(&self->lastStereoSample[0], &output[(samplesWritten - 1) * 2], sizeof(lastStereoSample));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adjust the volume of our samples based on the emulator's volume slider
|
||||||
|
float audioVolume = self->audioSettings.getVolume();
|
||||||
|
// If volume is 1.0 we don't need to do anything
|
||||||
|
if (audioVolume != 1.0f) {
|
||||||
|
s16* sample = output;
|
||||||
|
|
||||||
|
// If our volume is > 1.0 then we boost samples using a logarithmic scale,
|
||||||
|
// In this case we also have to clamp samples to make sure they don't wrap around
|
||||||
|
if (audioVolume > 1.0f) {
|
||||||
|
audioVolume = 0.6 + 20 * std::log10(audioVolume);
|
||||||
|
|
||||||
|
constexpr s32 min = s32(std::numeric_limits<s16>::min());
|
||||||
|
constexpr s32 max = s32(std::numeric_limits<s16>::max());
|
||||||
|
|
||||||
|
for (usize i = 0; i < samplesWritten; i += 2) {
|
||||||
|
s16 l = s16(std::clamp<s32>(s32(float(sample[0]) * audioVolume), min, max));
|
||||||
|
s16 r = s16(std::clamp<s32>(s32(float(sample[1]) * audioVolume), min, max));
|
||||||
|
|
||||||
|
*sample++ = l;
|
||||||
|
*sample++ = r;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If our volume is in [0.0, 1.0) then just multiply by the volume. No need to clamp, since there is no danger of our samples wrapping
|
||||||
|
// around due to overflow
|
||||||
|
for (usize i = 0; i < samplesWritten; i += 2) {
|
||||||
|
s16 l = s16(float(sample[0]) * audioVolume);
|
||||||
|
s16 r = s16(float(sample[1]) * audioVolume);
|
||||||
|
|
||||||
|
*sample++ = l;
|
||||||
|
*sample++ = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If underruning, copy the last output sample
|
// If underruning, copy the last output sample
|
||||||
{
|
{
|
||||||
s16* pointer = &output[samplesWritten * 2];
|
s16* pointer = &output[samplesWritten * 2];
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1;
|
||||||
|
|
||||||
Emulator::Emulator()
|
Emulator::Emulator()
|
||||||
: config(getConfigPath()), kernel(cpu, memory, gpu, config), cpu(memory, kernel, *this), gpu(memory, config), memory(cpu.getTicksRef(), config),
|
: config(getConfigPath()), kernel(cpu, memory, gpu, config), cpu(memory, kernel, *this), gpu(memory, config), memory(cpu.getTicksRef(), config),
|
||||||
cheats(memory, kernel.getServiceManager().getHID()), lua(*this), running(false)
|
cheats(memory, kernel.getServiceManager().getHID()), audioDevice(config.audioDeviceConfig), lua(*this), running(false)
|
||||||
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
|
#ifdef PANDA3DS_ENABLE_HTTP_SERVER
|
||||||
,
|
,
|
||||||
httpServer(this)
|
httpServer(this)
|
||||||
|
@ -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());
|
||||||
|
|
|
@ -172,12 +172,16 @@ 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_audio_volume", "Audio volume; 100|0|10|20|40|60|80|90|100|120|140|150|180|200"},
|
||||||
|
{"panda3ds_mute_audio", "Mute audio; disabled|enabled"},
|
||||||
|
{"panda3ds_enable_aac", "Enable AAC audio; enabled|disabled"},
|
||||||
|
|
||||||
|
{"panda3ds_ubershader_lighting_override", "Force shadergen when rendering lights; enabled|disabled"},
|
||||||
|
{"panda3ds_ubershader_lighting_override_threshold", "Light threshold for forcing shadergen; 1|2|3|4|5|6|7|8"},
|
||||||
{"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"},
|
||||||
{"panda3ds_use_charger", "Charger plugged; enabled|disabled"},
|
{"panda3ds_use_charger", "Charger plugged; enabled|disabled"},
|
||||||
{"panda3ds_ubershader_lighting_override", "Force shadergen when rendering lights; enabled|disabled"},
|
|
||||||
{"panda3ds_ubershader_lighting_override_threshold", "Light threshold for forcing shadergen; 1|2|3|4|5|6|7|8"},
|
|
||||||
{nullptr, nullptr},
|
{nullptr, nullptr},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -194,6 +198,10 @@ 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.audioDeviceConfig.muteAudio = fetchVariableBool("panda3ds_mute_audio", false);
|
||||||
|
config.audioDeviceConfig.volumeRaw = float(fetchVariableRange("panda3ds_audio_volume", 0, 200)) / 100.0f;
|
||||||
|
|
||||||
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);
|
||||||
|
|
Loading…
Add table
Reference in a new issue