mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-07 22:55:40 +12:00
Merge branch 'master' into fastmem
This commit is contained in:
commit
57433bb9eb
11 changed files with 67 additions and 10 deletions
|
@ -708,7 +708,7 @@ if(NOT BUILD_HYDRA_CORE AND NOT BUILD_LIBRETRO_CORE)
|
||||||
docs/img/rsob_icon.png docs/img/rstarstruck_icon.png docs/img/rpog_icon.png docs/img/rsyn_icon.png
|
docs/img/rsob_icon.png docs/img/rstarstruck_icon.png docs/img/rpog_icon.png docs/img/rsyn_icon.png
|
||||||
docs/img/settings_icon.png docs/img/display_icon.png docs/img/speaker_icon.png
|
docs/img/settings_icon.png docs/img/display_icon.png docs/img/speaker_icon.png
|
||||||
docs/img/sparkling_icon.png docs/img/battery_icon.png docs/img/sdcard_icon.png
|
docs/img/sparkling_icon.png docs/img/battery_icon.png docs/img/sdcard_icon.png
|
||||||
docs/img/rnap_icon.png docs/img/rcow_icon.png
|
docs/img/rnap_icon.png docs/img/rcow_icon.png docs/img/skyemu_icon.png
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
set(FRONTEND_SOURCE_FILES src/panda_sdl/main.cpp src/panda_sdl/frontend_sdl.cpp src/panda_sdl/mappings.cpp)
|
set(FRONTEND_SOURCE_FILES src/panda_sdl/main.cpp src/panda_sdl/frontend_sdl.cpp src/panda_sdl/mappings.cpp)
|
||||||
|
|
BIN
docs/img/skyemu_icon.png
Normal file
BIN
docs/img/skyemu_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -1,12 +1,21 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "audio/dsp_core.hpp"
|
#include "audio/dsp_core.hpp"
|
||||||
#include "renderer.hpp"
|
|
||||||
#include "frontend_settings.hpp"
|
#include "frontend_settings.hpp"
|
||||||
|
#include "renderer.hpp"
|
||||||
|
|
||||||
struct AudioDeviceConfig {
|
struct AudioDeviceConfig {
|
||||||
|
// Audio curve to use for volumes between 0-100
|
||||||
|
enum class VolumeCurve : int {
|
||||||
|
Cubic = 0, // Samples are scaled by volume ^ 3
|
||||||
|
Linear = 1, // Samples are scaled by volume
|
||||||
|
};
|
||||||
|
|
||||||
float volumeRaw = 1.0f;
|
float volumeRaw = 1.0f;
|
||||||
|
VolumeCurve volumeCurve = VolumeCurve::Cubic;
|
||||||
|
|
||||||
bool muteAudio = false;
|
bool muteAudio = false;
|
||||||
|
|
||||||
float getVolume() const {
|
float getVolume() const {
|
||||||
|
@ -16,6 +25,9 @@ struct AudioDeviceConfig {
|
||||||
|
|
||||||
return volumeRaw;
|
return volumeRaw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VolumeCurve volumeCurveFromString(std::string inString);
|
||||||
|
static const char* volumeCurveToString(VolumeCurve curve);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct FrontendSettings {
|
||||||
Rsyn = 1,
|
Rsyn = 1,
|
||||||
Rnap = 2,
|
Rnap = 2,
|
||||||
Rcow = 3,
|
Rcow = 3,
|
||||||
|
SkyEmu = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
Theme theme = Theme::Dark;
|
Theme theme = Theme::Dark;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -105,6 +107,7 @@ void EmulatorConfig::load() {
|
||||||
// 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
|
// 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.
|
// samples at all.
|
||||||
audioDeviceConfig.volumeRaw = float(std::clamp(toml::find_or<toml::floating>(audio, "AudioVolume", 1.0), 0.0, 2.0));
|
audioDeviceConfig.volumeRaw = float(std::clamp(toml::find_or<toml::floating>(audio, "AudioVolume", 1.0), 0.0, 2.0));
|
||||||
|
audioDeviceConfig.volumeCurve = AudioDeviceConfig::volumeCurveFromString(toml::find_or<std::string>(audio, "VolumeCurve", "cubic"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,6 +191,7 @@ void EmulatorConfig::save() {
|
||||||
data["Audio"]["EnableAACAudio"] = aacEnabled;
|
data["Audio"]["EnableAACAudio"] = aacEnabled;
|
||||||
data["Audio"]["MuteAudio"] = audioDeviceConfig.muteAudio;
|
data["Audio"]["MuteAudio"] = audioDeviceConfig.muteAudio;
|
||||||
data["Audio"]["AudioVolume"] = double(audioDeviceConfig.volumeRaw);
|
data["Audio"]["AudioVolume"] = double(audioDeviceConfig.volumeRaw);
|
||||||
|
data["Audio"]["VolumeCurve"] = std::string(AudioDeviceConfig::volumeCurveToString(audioDeviceConfig.volumeCurve));
|
||||||
data["Audio"]["PrintDSPFirmware"] = printDSPFirmware;
|
data["Audio"]["PrintDSPFirmware"] = printDSPFirmware;
|
||||||
|
|
||||||
data["Battery"]["ChargerPlugged"] = chargerPlugged;
|
data["Battery"]["ChargerPlugged"] = chargerPlugged;
|
||||||
|
@ -203,3 +207,26 @@ void EmulatorConfig::save() {
|
||||||
file << data;
|
file << data;
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioDeviceConfig::VolumeCurve AudioDeviceConfig::volumeCurveFromString(std::string inString) {
|
||||||
|
// Transform to lower-case to make the setting case-insensitive
|
||||||
|
std::transform(inString.begin(), inString.end(), inString.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||||
|
|
||||||
|
if (inString == "cubic") {
|
||||||
|
return VolumeCurve::Cubic;
|
||||||
|
} else if (inString == "linear") {
|
||||||
|
return VolumeCurve::Linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to cubic curve
|
||||||
|
return VolumeCurve::Cubic;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* AudioDeviceConfig::volumeCurveToString(AudioDeviceConfig::VolumeCurve curve) {
|
||||||
|
switch (curve) {
|
||||||
|
case VolumeCurve::Linear: return "linear";
|
||||||
|
|
||||||
|
case VolumeCurve::Cubic:
|
||||||
|
default: return "cubic";
|
||||||
|
}
|
||||||
|
}
|
|
@ -134,6 +134,12 @@ void MiniAudioDevice::init(Samples& samples, bool safe) {
|
||||||
} else {
|
} 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
|
// 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
|
// around due to overflow
|
||||||
|
|
||||||
|
// If we're applying cubic volume curve, raise volume to the power of 3
|
||||||
|
if (self->audioSettings.volumeCurve == AudioDeviceConfig::VolumeCurve::Cubic) {
|
||||||
|
audioVolume = audioVolume * audioVolume * audioVolume;
|
||||||
|
}
|
||||||
|
|
||||||
for (usize i = 0; i < samplesWritten; i += 2) {
|
for (usize i = 0; i < samplesWritten; i += 2) {
|
||||||
s16 l = s16(float(sample[0]) * audioVolume);
|
s16 l = s16(float(sample[0]) * audioVolume);
|
||||||
s16 r = s16(float(sample[1]) * audioVolume);
|
s16 r = s16(float(sample[1]) * audioVolume);
|
||||||
|
|
|
@ -38,10 +38,8 @@ FrontendSettings::WindowIcon FrontendSettings::iconFromString(std::string inStri
|
||||||
std::transform(inString.begin(), inString.end(), inString.begin(), [](unsigned char c) { return std::tolower(c); });
|
std::transform(inString.begin(), inString.end(), inString.begin(), [](unsigned char c) { return std::tolower(c); });
|
||||||
|
|
||||||
static const std::unordered_map<std::string, WindowIcon> map = {
|
static const std::unordered_map<std::string, WindowIcon> map = {
|
||||||
{"rpog", WindowIcon::Rpog},
|
{"rpog", WindowIcon::Rpog}, {"rsyn", WindowIcon::Rsyn}, {"rcow", WindowIcon::Rcow},
|
||||||
{"rsyn", WindowIcon::Rsyn},
|
{"rnap", WindowIcon::Rnap}, {"skyemu", WindowIcon::SkyEmu},
|
||||||
{"rcow", WindowIcon::Rcow},
|
|
||||||
{"rnap", WindowIcon::Rnap},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto search = map.find(inString); search != map.end()) {
|
if (auto search = map.find(inString); search != map.end()) {
|
||||||
|
@ -57,6 +55,7 @@ const char* FrontendSettings::iconToString(WindowIcon icon) {
|
||||||
case WindowIcon::Rsyn: return "rsyn";
|
case WindowIcon::Rsyn: return "rsyn";
|
||||||
case WindowIcon::Rcow: return "rcow";
|
case WindowIcon::Rcow: return "rcow";
|
||||||
case WindowIcon::Rnap: return "rnap";
|
case WindowIcon::Rnap: return "rnap";
|
||||||
|
case WindowIcon::SkyEmu: return "skyemu";
|
||||||
|
|
||||||
case WindowIcon::Rpog:
|
case WindowIcon::Rpog:
|
||||||
default: return "rpog";
|
default: return "rpog";
|
||||||
|
|
|
@ -69,7 +69,7 @@ void CheatEntryWidget::editClicked() {
|
||||||
}
|
}
|
||||||
|
|
||||||
CheatEditDialog::CheatEditDialog(Emulator* emu, CheatEntryWidget& cheatEntry) : QDialog(), emu(emu), cheatEntry(cheatEntry) {
|
CheatEditDialog::CheatEditDialog(Emulator* emu, CheatEntryWidget& cheatEntry) : QDialog(), emu(emu), cheatEntry(cheatEntry) {
|
||||||
setWindowTitle("Edit Cheat");
|
setWindowTitle(tr("Edit Cheat"));
|
||||||
|
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
setModal(true);
|
setModal(true);
|
||||||
|
@ -161,7 +161,7 @@ void CheatEditDialog::rejected() {
|
||||||
|
|
||||||
CheatsWindow::CheatsWindow(Emulator* emu, const std::filesystem::path& cheatPath, QWidget* parent)
|
CheatsWindow::CheatsWindow(Emulator* emu, const std::filesystem::path& cheatPath, QWidget* parent)
|
||||||
: QWidget(parent, Qt::Window), emu(emu), cheatPath(cheatPath) {
|
: QWidget(parent, Qt::Window), emu(emu), cheatPath(cheatPath) {
|
||||||
setWindowTitle("Cheats");
|
setWindowTitle(tr("Cheats"));
|
||||||
mainWindow = static_cast<MainWindow*>(parent);
|
mainWindow = static_cast<MainWindow*>(parent);
|
||||||
|
|
||||||
QVBoxLayout* layout = new QVBoxLayout;
|
QVBoxLayout* layout = new QVBoxLayout;
|
||||||
|
|
|
@ -85,6 +85,7 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win
|
||||||
iconSelect->addItem(tr("Happy panda (colourful)"));
|
iconSelect->addItem(tr("Happy panda (colourful)"));
|
||||||
iconSelect->addItem(tr("Sleepy panda"));
|
iconSelect->addItem(tr("Sleepy panda"));
|
||||||
iconSelect->addItem(tr("Cow panda"));
|
iconSelect->addItem(tr("Cow panda"));
|
||||||
|
iconSelect->addItem(tr("The penguin from SkyEmu"));
|
||||||
iconSelect->setCurrentIndex(static_cast<int>(config.frontendSettings.icon));
|
iconSelect->setCurrentIndex(static_cast<int>(config.frontendSettings.icon));
|
||||||
|
|
||||||
connect(iconSelect, &QComboBox::currentIndexChanged, this, [&](int index) {
|
connect(iconSelect, &QComboBox::currentIndexChanged, this, [&](int index) {
|
||||||
|
@ -239,6 +240,16 @@ ConfigWindow::ConfigWindow(ConfigCallback configCallback, MainWindowCallback win
|
||||||
connectCheckbox(muteAudio, config.audioDeviceConfig.muteAudio);
|
connectCheckbox(muteAudio, config.audioDeviceConfig.muteAudio);
|
||||||
audioLayout->addRow(muteAudio);
|
audioLayout->addRow(muteAudio);
|
||||||
|
|
||||||
|
QComboBox* volumeCurveType = new QComboBox;
|
||||||
|
volumeCurveType->addItem(tr("Cubic"));
|
||||||
|
volumeCurveType->addItem(tr("Linear"));
|
||||||
|
volumeCurveType->setCurrentIndex(static_cast<int>(config.audioDeviceConfig.volumeCurve));
|
||||||
|
connect(volumeCurveType, &QComboBox::currentIndexChanged, this, [&](int index) {
|
||||||
|
config.audioDeviceConfig.volumeCurve = static_cast<AudioDeviceConfig::VolumeCurve>(index);
|
||||||
|
updateConfig();
|
||||||
|
});
|
||||||
|
audioLayout->addRow(tr("Volume curve"), volumeCurveType);
|
||||||
|
|
||||||
QSpinBox* volumeRaw = new QSpinBox();
|
QSpinBox* volumeRaw = new QSpinBox();
|
||||||
volumeRaw->setRange(0, 200);
|
volumeRaw->setRange(0, 200);
|
||||||
volumeRaw->setValue(config.audioDeviceConfig.volumeRaw * 100);
|
volumeRaw->setValue(config.audioDeviceConfig.volumeRaw * 100);
|
||||||
|
@ -398,6 +409,7 @@ void ConfigWindow::setIcon(WindowIcon icon) {
|
||||||
case WindowIcon::Rsyn: updateIcon(":/docs/img/rsyn_icon.png"); break;
|
case WindowIcon::Rsyn: updateIcon(":/docs/img/rsyn_icon.png"); break;
|
||||||
case WindowIcon::Rnap: updateIcon(":/docs/img/rnap_icon.png"); break;
|
case WindowIcon::Rnap: updateIcon(":/docs/img/rnap_icon.png"); break;
|
||||||
case WindowIcon::Rcow: updateIcon(":/docs/img/rcow_icon.png"); break;
|
case WindowIcon::Rcow: updateIcon(":/docs/img/rcow_icon.png"); break;
|
||||||
|
case WindowIcon::SkyEmu: updateIcon(":/docs/img/skyemu_icon.png"); break;
|
||||||
|
|
||||||
case WindowIcon::Rpog:
|
case WindowIcon::Rpog:
|
||||||
default: updateIcon(":/docs/img/rpog_icon.png"); break;
|
default: updateIcon(":/docs/img/rpog_icon.png"); break;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "io_file.hpp"
|
#include "io_file.hpp"
|
||||||
|
|
||||||
PatchWindow::PatchWindow(QWidget* parent) : QWidget(parent, Qt::Window) {
|
PatchWindow::PatchWindow(QWidget* parent) : QWidget(parent, Qt::Window) {
|
||||||
setWindowTitle("ROM patcher");
|
setWindowTitle(tr("ROM patcher"));
|
||||||
|
|
||||||
QVBoxLayout* layout = new QVBoxLayout;
|
QVBoxLayout* layout = new QVBoxLayout;
|
||||||
layout->setContentsMargins(6, 6, 6, 6);
|
layout->setContentsMargins(6, 6, 6, 6);
|
||||||
|
|
|
@ -9,7 +9,7 @@ using namespace Zep;
|
||||||
|
|
||||||
TextEditorWindow::TextEditorWindow(QWidget* parent, const std::string& filename, const std::string& initialText)
|
TextEditorWindow::TextEditorWindow(QWidget* parent, const std::string& filename, const std::string& initialText)
|
||||||
: QDialog(parent), zepWidget(this, qApp->applicationDirPath().toStdString(), fontSize) {
|
: QDialog(parent), zepWidget(this, qApp->applicationDirPath().toStdString(), fontSize) {
|
||||||
setWindowTitle("Lua Editor");
|
setWindowTitle(tr("Lua Editor"));
|
||||||
resize(600, 600);
|
resize(600, 600);
|
||||||
|
|
||||||
// Register our extensions
|
// Register our extensions
|
||||||
|
|
Loading…
Add table
Reference in a new issue