aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--src/DSi_I2C.cpp318
-rw-r--r--src/DSi_I2C.h50
-rw-r--r--src/NDS.h2
-rw-r--r--src/frontend/qt_sdl/AudioSettingsDialog.cpp65
-rw-r--r--src/frontend/qt_sdl/AudioSettingsDialog.h11
-rw-r--r--src/frontend/qt_sdl/AudioSettingsDialog.ui10
-rw-r--r--src/frontend/qt_sdl/Config.cpp8
-rw-r--r--src/frontend/qt_sdl/Config.h4
-rw-r--r--src/frontend/qt_sdl/InputConfig/InputConfigDialog.h10
-rw-r--r--src/frontend/qt_sdl/main.cpp71
-rw-r--r--src/frontend/qt_sdl/main.h2
12 files changed, 534 insertions, 22 deletions
diff --git a/.gitignore b/.gitignore
index 7bbb40a..e76a094 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,8 @@ compile_commands.json
*.exe
.DS_Store
+
+.vs
+.vscode
+CMakeFiles
+CMakeCache.txt
diff --git a/src/DSi_I2C.cpp b/src/DSi_I2C.cpp
index b4cfa89..7bb7e1d 100644
--- a/src/DSi_I2C.cpp
+++ b/src/DSi_I2C.cpp
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <string.h>
+#include <math.h>
#include "DSi.h"
#include "DSi_I2C.h"
#include "DSi_Camera.h"
@@ -31,6 +32,38 @@ using Platform::LogLevel;
namespace DSi_BPTWL
{
+// TODO: These are purely approximations
+const double PowerButtonShutdownTime = 0.5;
+const double PowerButtonForcedShutdownTime = 5.0;
+const double VolumeSwitchRepeatStart = 0.5;
+const double VolumeSwitchRepeatRate = 1.0 / 6;
+
+// Could not find a pattern or a decent formula for these,
+// regardless, they're only 64 bytes in size
+const u8 VolumeDownTable[32] =
+{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x09, 0x0A,
+ 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A,
+};
+
+const u8 VolumeUpTable[32] =
+{
+ 0x02, 0x03, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0C,
+ 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
+ 0x1D, 0x1E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+};
+
+double PowerButtonTime = 0.0;
+bool PowerButtonDownFlag = false;
+bool PowerButtonShutdownFlag = false;
+double VolumeSwitchTime = 0.0;
+double VolumeSwitchRepeatTime = 0.0;
+bool VolumeSwitchDownFlag = false;
+u32 VolumeSwitchKeysDown = 0;
+
u8 Registers[0x100];
u32 CurPos;
@@ -51,9 +84,9 @@ void Reset()
Registers[0x00] = 0x33; // TODO: support others??
Registers[0x01] = 0x00;
Registers[0x02] = 0x50;
- Registers[0x10] = 0x00; // power btn
+ Registers[0x10] = 0x00; // irq flag
Registers[0x11] = 0x00; // reset
- Registers[0x12] = 0x00; // power btn tap
+ Registers[0x12] = 0x00; // irq mode
Registers[0x20] = 0x8F; // battery
Registers[0x21] = 0x07;
Registers[0x30] = 0x13;
@@ -74,6 +107,15 @@ void Reset()
Registers[0x77] = 0x00;
Registers[0x80] = 0x10;
Registers[0x81] = 0x64;
+
+ // Ideally these should be replaced by a proper BPTWL core emulator
+ PowerButtonTime = 0.0;
+ PowerButtonDownFlag = false;
+ PowerButtonShutdownFlag = false;
+ VolumeSwitchTime = 0.0;
+ VolumeSwitchRepeatTime = 0.0;
+ VolumeSwitchKeysDown = 0;
+
}
void DoSavestate(Savestate* file)
@@ -84,6 +126,12 @@ void DoSavestate(Savestate* file)
file->Var32(&CurPos);
}
+// TODO: Needs more investigation on the other bits
+inline bool GetIRQMode()
+{
+ return Registers[0x12] & 0x01;
+}
+
u8 GetBootFlag() { return Registers[0x70]; }
bool GetBatteryCharging() { return Registers[0x20] >> 7; }
@@ -97,6 +145,242 @@ void SetBatteryLevel(u8 batteryLevel)
{
Registers[0x20] = ((Registers[0x20] & 0xF0) | (batteryLevel & 0x0F));
SPI_Powerman::SetBatteryLevelOkay(batteryLevel > batteryLevel_Low ? true : false);
+
+ if (batteryLevel <= 1)
+ {
+ SetIRQ(batteryLevel ? IRQ_BatteryLow : IRQ_BatteryEmpty);
+ }
+
+}
+
+u8 GetVolumeLevel() { return Registers[0x40]; }
+void SetVolumeLevel(u8 volume)
+{
+ Registers[0x40] = volume & 0x1F;
+}
+
+u8 GetBacklightLevel() { return Registers[0x41]; }
+void SetBacklightLevel(u8 backlight)
+{
+ Registers[0x41] = backlight > 4 ? 4 : backlight;
+}
+
+
+void ResetButtonState()
+{
+ PowerButtonTime = 0.0;
+ PowerButtonDownFlag = false;
+ PowerButtonShutdownFlag = false;
+
+ VolumeSwitchKeysDown = 0;
+ VolumeSwitchDownFlag = false;
+ VolumeSwitchTime = 0.0;
+ VolumeSwitchRepeatTime = 0.0;
+}
+
+void DoHardwareReset(bool direct)
+{
+ ResetButtonState();
+
+ Log(LogLevel::Debug, "BPTWL: soft-reset\n");
+
+ if (direct)
+ {
+ // TODO: This doesn't seem to stop the SPU
+ DSi::SoftReset();
+ return;
+ }
+
+ // TODO: soft-reset might need to be scheduled later!
+ // TODO: this has been moved for the JIT to work, nothing is confirmed here
+ NDS::ARM7->Halt(4);
+}
+
+void DoShutdown()
+{
+ ResetButtonState();
+ NDS::Stop();
+}
+
+
+void SetPowerButtonHeld(double time)
+{
+ if (!PowerButtonDownFlag)
+ {
+ PowerButtonDownFlag = true;
+ PowerButtonTime = time;
+ DoPowerButtonPress();
+ return;
+ }
+
+ double elapsed = time - PowerButtonTime;
+ if (elapsed < 0)
+ return;
+
+ if (elapsed >= PowerButtonForcedShutdownTime)
+ {
+ Log(LogLevel::Debug, "Force power off via DSi power button\n");
+ DoPowerButtonForceShutdown();
+ return;
+ }
+
+ if (elapsed >= PowerButtonShutdownTime)
+ {
+ DoPowerButtonShutdown();
+ }
+}
+
+void SetPowerButtonReleased(double time)
+{
+ double elapsed = time - PowerButtonTime;
+ if (elapsed >= 0 && elapsed < PowerButtonShutdownTime)
+ {
+ DoPowerButtonReset();
+ }
+
+ PowerButtonTime = 0.0;
+ PowerButtonDownFlag = false;
+ PowerButtonShutdownFlag = false;
+}
+
+void SetVolumeSwitchHeld(u32 key)
+{
+ VolumeSwitchKeysDown |= (1 << key);
+}
+
+void SetVolumeSwitchReleased(u32 key)
+{
+ VolumeSwitchKeysDown &= ~(1 << key);
+ VolumeSwitchDownFlag = false;
+ VolumeSwitchTime = 0.0;
+ VolumeSwitchRepeatTime = 0.0;
+}
+
+inline bool CheckVolumeSwitchKeysValid()
+{
+ bool up = VolumeSwitchKeysDown & (1 << volumeKey_Up);
+ bool down = VolumeSwitchKeysDown & (1 << volumeKey_Down);
+
+ return up != down;
+}
+
+s32 ProcessVolumeSwitchInput(double time)
+{
+ if (!CheckVolumeSwitchKeysValid())
+ return -1;
+
+ s32 key = VolumeSwitchKeysDown & (1 << volumeKey_Up) ? volumeKey_Up : volumeKey_Down;
+
+ // Always fire an IRQ when first pressed
+ if (!VolumeSwitchDownFlag)
+ {
+ VolumeSwitchDownFlag = true;
+ VolumeSwitchTime = time;
+ DoVolumeSwitchPress(key);
+ return key;
+ }
+
+ // Handle key repetition mechanic
+ if (VolumeSwitchRepeatTime == 0)
+ {
+ double elapsed = time - VolumeSwitchTime;
+ if (elapsed < VolumeSwitchRepeatStart)
+ return -1;
+
+ VolumeSwitchRepeatTime = time;
+ DoVolumeSwitchPress(key);
+ return key;
+ }
+
+ double elapsed = time - VolumeSwitchRepeatTime;
+ if (elapsed < VolumeSwitchRepeatRate)
+ return -1;
+
+ double rem = fmod(elapsed, VolumeSwitchRepeatRate);
+ VolumeSwitchRepeatTime = time - rem;
+ DoVolumeSwitchPress(key);
+ return key;
+}
+
+
+void DoPowerButtonPress()
+{
+ // Set button pressed IRQ
+ SetIRQ(IRQ_PowerButtonPressed);
+
+ // There is no default hardware behavior for pressing the power button
+}
+
+void DoPowerButtonReset()
+{
+ // Reset via IRQ, handled by software
+ SetIRQ(IRQ_PowerButtonReset);
+
+ // Reset automatically via hardware
+ if (!GetIRQMode())
+ {
+ // Assumes this isn't called during normal CPU execution
+ DoHardwareReset(true);
+ }
+}
+
+void DoPowerButtonShutdown()
+{
+ // Shutdown via IRQ, handled by software
+ if (!PowerButtonShutdownFlag)
+ {
+ SetIRQ(IRQ_PowerButtonShutdown);
+ }
+
+ PowerButtonShutdownFlag = true;
+
+ // Shutdown automatically via hardware
+ if (!GetIRQMode())
+ {
+ DoShutdown();
+ }
+
+ // The IRQ is only fired once (hence the need for an if guard),
+ // but the hardware shutdown is continuously triggered.
+ // That way when switching the IRQ mode while holding
+ // down the power button, the DSi will still shut down
+}
+
+void DoPowerButtonForceShutdown()
+{
+ DoShutdown();
+}
+
+void DoVolumeSwitchPress(u32 key)
+{
+ u8 volume = Registers[0x40];
+
+ switch (key)
+ {
+
+ case volumeKey_Up:
+ volume = VolumeUpTable[volume];
+ break;
+
+ case volumeKey_Down:
+ volume = VolumeDownTable[volume];
+ break;
+
+ }
+
+ Registers[0x40] = volume;
+
+ SetIRQ(IRQ_VolumeSwitchPressed);
+}
+
+void SetIRQ(u8 irqFlag)
+{
+ Registers[0x10] |= irqFlag & IRQ_ValidMask;
+
+ if (GetIRQMode())
+ {
+ NDS::SetIRQ2(NDS::IRQ2_DSi_BPTWL);
+ }
}
void Start()
@@ -107,7 +391,15 @@ void Start()
u8 Read(bool last)
{
//printf("BPTWL: read %02X -> %02X @ %08X\n", CurPos, Registers[CurPos], NDS::GetPC(1));
- u8 ret = Registers[CurPos++];
+ u8 ret = Registers[CurPos];
+
+ // IRQ flags are automatically cleared upon read
+ if (CurPos == 0x10)
+ {
+ Registers[0x10] = 0;
+ }
+
+ CurPos++;
if (last)
{
@@ -134,19 +426,29 @@ void Write(u8 val, bool last)
if (CurPos == 0x11 && val == 0x01)
{
- Log(LogLevel::Debug, "BPTWL: soft-reset\n");
+ // Assumes this is called during normal CPU execution
+ DoHardwareReset(false);
val = 0; // checkme
- // TODO: soft-reset might need to be scheduled later!
- // TODO: this has been moved for the JIT to work, nothing is confirmed here
- NDS::ARM7->Halt(4);
CurPos = -1;
return;
}
+ // Mask volume level
+ if (CurPos == 0x40)
+ {
+ val &= 0x1F;
+ }
+
+ // Clamp backlight level
+ if (CurPos == 0x41)
+ {
+ val = val > 4 ? 4 : val;
+ }
+
if (CurPos == 0x11 || CurPos == 0x12 ||
CurPos == 0x21 ||
CurPos == 0x30 || CurPos == 0x31 ||
- CurPos == 0x40 || CurPos == 0x31 ||
+ CurPos == 0x40 || CurPos == 0x41 ||
CurPos == 0x60 || CurPos == 0x63 ||
(CurPos >= 0x70 && CurPos <= 0x77) ||
CurPos == 0x80 || CurPos == 0x81)
diff --git a/src/DSi_I2C.h b/src/DSi_I2C.h
index 48c8e88..8a54a2c 100644
--- a/src/DSi_I2C.h
+++ b/src/DSi_I2C.h
@@ -42,6 +42,56 @@ enum
u8 GetBatteryLevel();
void SetBatteryLevel(u8 batteryLevel);
+
+// 0-31
+u8 GetVolumeLevel();
+void SetVolumeLevel(u8 volume);
+
+// 0-4
+u8 GetBacklightLevel();
+void SetBacklightLevel(u8 backlight);
+
+void DoHardwareReset(bool direct);
+void DoShutdown();
+
+enum
+{
+ volumeKey_Up,
+ volumeKey_Down,
+};
+
+// Used by hotkeys
+void SetPowerButtonHeld(double time);
+void SetPowerButtonReleased(double time);
+void SetVolumeSwitchHeld(u32 key);
+void SetVolumeSwitchReleased(u32 key);
+s32 ProcessVolumeSwitchInput(double time);
+
+void DoPowerButtonPress();
+void DoPowerButtonReset();
+void DoPowerButtonShutdown();
+void DoPowerButtonForceShutdown();
+void DoVolumeSwitchPress(u32 key);
+
+enum
+{
+ IRQ_PowerButtonReset = 0x01, // Triggered after releasing the power button quickly
+ IRQ_PowerButtonShutdown = 0x02, // Triggered after holding the power button for less than a second
+ IRQ_PowerButtonPressed = 0x08, // Triggered after pressing the power button
+ IRQ_BatteryEmpty = 0x10, //
+ IRQ_BatteryLow = 0x20, // Triggered when the battery level reaches 1
+ IRQ_VolumeSwitchPressed = 0x40, // Triggered once when the volume sliders are first pressed and repeatedly when held down
+ /*
+ Bit 2 (0x04) could be set when holding the power button for more than 5 seconds? (forced power off)
+ It is unknown whether it is set as the console powers off immediately.
+ Bit 7 (0x80) is unused?
+ Both bits are never used by the official ARM7 libraries, but could have some undocumented hardware functionality (?).
+ */
+ IRQ_ValidMask = 0x7B,
+};
+
+void SetIRQ(u8 irqFlag);
+
}
namespace DSi_I2C
diff --git a/src/NDS.h b/src/NDS.h
index 824c2bc..dc7809e 100644
--- a/src/NDS.h
+++ b/src/NDS.h
@@ -110,7 +110,7 @@ enum
IRQ2_DSi_Unused3,
IRQ2_DSi_GPIO33_0,
IRQ2_DSi_Headphone,
- IRQ2_DSi_PowerButton,
+ IRQ2_DSi_BPTWL,
IRQ2_DSi_GPIO33_3, // "sound enable input"
IRQ2_DSi_SDMMC,
IRQ2_DSi_SD_Data1,
diff --git a/src/frontend/qt_sdl/AudioSettingsDialog.cpp b/src/frontend/qt_sdl/AudioSettingsDialog.cpp
index 4beefaf..198c06b 100644
--- a/src/frontend/qt_sdl/AudioSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/AudioSettingsDialog.cpp
@@ -22,6 +22,8 @@
#include "types.h"
#include "Platform.h"
#include "Config.h"
+#include "NDS.h"
+#include "DSi_I2C.h"
#include "AudioSettingsDialog.h"
#include "ui_AudioSettingsDialog.h"
@@ -32,7 +34,7 @@ AudioSettingsDialog* AudioSettingsDialog::currentDlg = nullptr;
extern std::string EmuDirectory;
-AudioSettingsDialog::AudioSettingsDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AudioSettingsDialog)
+AudioSettingsDialog::AudioSettingsDialog(QWidget* parent, bool emuActive) : QDialog(parent), ui(new Ui::AudioSettingsDialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
@@ -40,6 +42,7 @@ AudioSettingsDialog::AudioSettingsDialog(QWidget* parent) : QDialog(parent), ui(
oldInterp = Config::AudioInterp;
oldBitrate = Config::AudioBitrate;
oldVolume = Config::AudioVolume;
+ oldDSiSync = Config::DSiVolumeSync;
ui->cbInterpolation->addItem("None");
ui->cbInterpolation->addItem("Linear");
@@ -52,7 +55,21 @@ AudioSettingsDialog::AudioSettingsDialog(QWidget* parent) : QDialog(parent), ui(
ui->cbBitrate->addItem("16-bit");
ui->cbBitrate->setCurrentIndex(Config::AudioBitrate);
+ bool state = ui->slVolume->blockSignals(true);
ui->slVolume->setValue(Config::AudioVolume);
+ ui->slVolume->blockSignals(state);
+
+ ui->chkSyncDSiVolume->setChecked(Config::DSiVolumeSync);
+
+ // Setup volume slider accordingly
+ if (emuActive && NDS::ConsoleType == 1)
+ {
+ on_chkSyncDSiVolume_clicked(Config::DSiVolumeSync);
+ }
+ else
+ {
+ ui->chkSyncDSiVolume->setEnabled(false);
+ }
grpMicMode = new QButtonGroup(this);
grpMicMode->addButton(ui->rbMicNone, 0);
@@ -88,6 +105,22 @@ AudioSettingsDialog::~AudioSettingsDialog()
delete ui;
}
+void AudioSettingsDialog::onSyncVolumeLevel()
+{
+ if (Config::DSiVolumeSync && NDS::ConsoleType == 1)
+ {
+ bool state = ui->slVolume->blockSignals(true);
+ ui->slVolume->setValue(DSi_BPTWL::GetVolumeLevel());
+ ui->slVolume->blockSignals(state);
+ }
+}
+
+void AudioSettingsDialog::onConsoleReset()
+{
+ on_chkSyncDSiVolume_clicked(Config::DSiVolumeSync);
+ ui->chkSyncDSiVolume->setEnabled(NDS::ConsoleType == 1);
+}
+
void AudioSettingsDialog::on_AudioSettingsDialog_accepted()
{
Config::MicInputType = grpMicMode->checkedId();
@@ -102,6 +135,7 @@ void AudioSettingsDialog::on_AudioSettingsDialog_rejected()
Config::AudioInterp = oldInterp;
Config::AudioBitrate = oldBitrate;
Config::AudioVolume = oldVolume;
+ Config::DSiVolumeSync = oldDSiSync;
closeDlg();
}
@@ -128,9 +162,38 @@ void AudioSettingsDialog::on_cbInterpolation_currentIndexChanged(int idx)
void AudioSettingsDialog::on_slVolume_valueChanged(int val)
{
+ if (Config::DSiVolumeSync && NDS::ConsoleType == 1)
+ {
+ DSi_BPTWL::SetVolumeLevel(val);
+ return;
+ }
+
Config::AudioVolume = val;
}
+void AudioSettingsDialog::on_chkSyncDSiVolume_clicked(bool checked)
+{
+ Config::DSiVolumeSync = checked;
+
+ bool state = ui->slVolume->blockSignals(true);
+ if (Config::DSiVolumeSync && NDS::ConsoleType == 1)
+ {
+ ui->slVolume->setMaximum(31);
+ ui->slVolume->setValue(DSi_BPTWL::GetVolumeLevel());
+ ui->slVolume->setPageStep(4);
+ ui->slVolume->setTickPosition(QSlider::TicksBelow);
+ }
+ else
+ {
+ Config::AudioVolume = oldVolume;
+ ui->slVolume->setMaximum(256);
+ ui->slVolume->setValue(Config::AudioVolume);
+ ui->slVolume->setPageStep(16);
+ ui->slVolume->setTickPosition(QSlider::NoTicks);
+ }
+ ui->slVolume->blockSignals(state);
+}
+
void AudioSettingsDialog::onChangeMicMode(int mode)
{
bool iswav = (mode == 3);
diff --git a/src/frontend/qt_sdl/AudioSettingsDialog.h b/src/frontend/qt_sdl/AudioSettingsDialog.h
index 498c152..14d1ad3 100644
--- a/src/frontend/qt_sdl/AudioSettingsDialog.h
+++ b/src/frontend/qt_sdl/AudioSettingsDialog.h
@@ -30,11 +30,11 @@ class AudioSettingsDialog : public QDialog
Q_OBJECT
public:
- explicit AudioSettingsDialog(QWidget* parent);
+ explicit AudioSettingsDialog(QWidget* parent, bool emuActive);
~AudioSettingsDialog();
static AudioSettingsDialog* currentDlg;
- static AudioSettingsDialog* openDlg(QWidget* parent)
+ static AudioSettingsDialog* openDlg(QWidget* parent, bool emuActive)
{
if (currentDlg)
{
@@ -42,7 +42,7 @@ public:
return currentDlg;
}
- currentDlg = new AudioSettingsDialog(parent);
+ currentDlg = new AudioSettingsDialog(parent, emuActive);
currentDlg->show();
return currentDlg;
}
@@ -51,6 +51,9 @@ public:
currentDlg = nullptr;
}
+ void onSyncVolumeLevel();
+ void onConsoleReset();
+
signals:
void updateAudioSettings();
@@ -61,6 +64,7 @@ private slots:
void on_cbInterpolation_currentIndexChanged(int idx);
void on_cbBitrate_currentIndexChanged(int idx);
void on_slVolume_valueChanged(int val);
+ void on_chkSyncDSiVolume_clicked(bool checked);
void onChangeMicMode(int mode);
void on_btnMicWavBrowse_clicked();
@@ -70,6 +74,7 @@ private:
int oldInterp;
int oldBitrate;
int oldVolume;
+ bool oldDSiSync;
QButtonGroup* grpMicMode;
};
diff --git a/src/frontend/qt_sdl/AudioSettingsDialog.ui b/src/frontend/qt_sdl/AudioSettingsDialog.ui
index 8fc38d9..862042f 100644
--- a/src/frontend/qt_sdl/AudioSettingsDialog.ui
+++ b/src/frontend/qt_sdl/AudioSettingsDialog.ui
@@ -59,6 +59,16 @@
</property>
</widget>
</item>
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="chkSyncDSiVolume">
+ <property name="whatsThis">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Synchronizes the output volume with the DSi hardware volume.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Sync with DSi volume</string>
+ </property>
+ </widget>
+ </item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
diff --git a/src/frontend/qt_sdl/Config.cpp b/src/frontend/qt_sdl/Config.cpp
index 4e00046..49c41a1 100644
--- a/src/frontend/qt_sdl/Config.cpp
+++ b/src/frontend/qt_sdl/Config.cpp
@@ -118,6 +118,7 @@ bool SavestateRelocSRAM;
int AudioInterp;
int AudioBitrate;
int AudioVolume;
+bool DSiVolumeSync;
int MicInputType;
std::string MicWavPath;
@@ -187,6 +188,9 @@ ConfigEntry ConfigFile[] =
{"HKKey_SolarSensorDecrease", 0, &HKKeyMapping[HK_SolarSensorDecrease], -1, true},
{"HKKey_SolarSensorIncrease", 0, &HKKeyMapping[HK_SolarSensorIncrease], -1, true},
{"HKKey_FrameStep", 0, &HKKeyMapping[HK_FrameStep], -1, true},
+ {"HKKey_PowerButton", 0, &HKKeyMapping[HK_PowerButton], -1, true},
+ {"HKKey_VolumeUp", 0, &HKKeyMapping[HK_VolumeUp], -1, true},
+ {"HKKey_VolumeDown", 0, &HKKeyMapping[HK_VolumeDown], -1, true},
{"HKJoy_Lid", 0, &HKJoyMapping[HK_Lid], -1, true},
{"HKJoy_Mic", 0, &HKJoyMapping[HK_Mic], -1, true},
@@ -200,6 +204,9 @@ ConfigEntry ConfigFile[] =
{"HKJoy_SolarSensorDecrease", 0, &HKJoyMapping[HK_SolarSensorDecrease], -1, true},
{"HKJoy_SolarSensorIncrease", 0, &HKJoyMapping[HK_SolarSensorIncrease], -1, true},
{"HKJoy_FrameStep", 0, &HKJoyMapping[HK_FrameStep], -1, true},
+ {"HKJoy_PowerButton", 0, &HKJoyMapping[HK_PowerButton], -1, true},
+ {"HKJoy_VolumeUp", 0, &HKJoyMapping[HK_VolumeUp], -1, true},
+ {"HKJoy_VolumeDown", 0, &HKJoyMapping[HK_VolumeDown], -1, true},
{"JoystickID", 0, &JoystickID, 0, true},
@@ -291,6 +298,7 @@ ConfigEntry ConfigFile[] =
{"AudioInterp", 0, &AudioInterp, 0, false},
{"AudioBitrate", 0, &AudioBitrate, 0, false},
{"AudioVolume", 0, &AudioVolume, 256, true},
+ {"DSiVolumeSync", 0, &DSiVolumeSync, 0, true},
{"MicInputType", 0, &MicInputType, 1, false},
{"MicWavPath", 2, &MicWavPath, (std::string)"", false},
diff --git a/src/frontend/qt_sdl/Config.h b/src/frontend/qt_sdl/Config.h
index 42b0a6a..2d4022e 100644
--- a/src/frontend/qt_sdl/Config.h
+++ b/src/frontend/qt_sdl/Config.h
@@ -36,6 +36,9 @@ enum
HK_SolarSensorDecrease,
HK_SolarSensorIncrease,
HK_FrameStep,
+ HK_PowerButton,
+ HK_VolumeUp,
+ HK_VolumeDown,
HK_MAX
};
@@ -163,6 +166,7 @@ extern bool SavestateRelocSRAM;
extern int AudioInterp;
extern int AudioBitrate;
extern int AudioVolume;
+extern bool DSiVolumeSync;
extern int MicInputType;
extern std::string MicWavPath;
diff --git a/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h
index 76112e8..53ea876 100644
--- a/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h
+++ b/src/frontend/qt_sdl/InputConfig/InputConfigDialog.h
@@ -52,7 +52,10 @@ static constexpr std::initializer_list<int> hk_general =
HK_Lid,
HK_Mic,
HK_SwapScreens,
- HK_SwapScreenEmphasis
+ HK_SwapScreenEmphasis,
+ HK_PowerButton,
+ HK_VolumeUp,
+ HK_VolumeDown
};
static constexpr std::initializer_list<const char*> hk_general_labels =
@@ -66,7 +69,10 @@ static constexpr std::initializer_list<const char*> hk_general_labels =
"Close/open lid",
"Microphone",
"Swap screens",
- "Swap screen emphasis"
+ "Swap screen emphasis",
+ "DSi Power button",
+ "DSi Volume up",
+ "DSi Volume down"
};
static_assert(hk_general.size() == hk_general_labels.size());
diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp
index 803d1f1..7015c6d 100644
--- a/src/frontend/qt_sdl/main.cpp
+++ b/src/frontend/qt_sdl/main.cpp
@@ -88,6 +88,7 @@
#include "Platform.h"
#include "LocalMP.h"
#include "Config.h"
+#include "DSi_I2C.h"
#include "Savestate.h"
@@ -581,6 +582,7 @@ void EmuThread::run()
double lastMeasureTime = lastTime;
u32 winUpdateCount = 0, winUpdateFreq = 1;
+ u8 dsiVolumeLevel = 0x1F;
char melontitle[100];
@@ -620,6 +622,42 @@ void EmuThread::run()
}
}
+ if (NDS::ConsoleType == 1)
+ {
+ double currentTime = SDL_GetPerformanceCounter() * perfCountsSec;
+
+ // Handle power button
+ if (Input::HotkeyDown(HK_PowerButton))
+ {
+ DSi_BPTWL::SetPowerButtonHeld(currentTime);
+ }
+ else if (Input::HotkeyReleased(HK_PowerButton))
+ {
+ DSi_BPTWL::SetPowerButtonReleased(currentTime);
+ }
+
+ // Handle volume buttons
+ if (Input::HotkeyDown(HK_VolumeUp))
+ {
+ DSi_BPTWL::SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Up);
+ }
+ else if (Input::HotkeyReleased(HK_VolumeUp))
+ {
+ DSi_BPTWL::SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Up);
+ }
+
+ if (Input::HotkeyDown(HK_VolumeDown))
+ {
+ DSi_BPTWL::SetVolumeSwitchHeld(DSi_BPTWL::volumeKey_Down);
+ }
+ else if (Input::HotkeyReleased(HK_VolumeDown))
+ {
+ DSi_BPTWL::SetVolumeSwitchReleased(DSi_BPTWL::volumeKey_Down);
+ }
+
+ DSi_BPTWL::ProcessVolumeSwitchInput(currentTime);
+ }
+
if (EmuRunning == 1 || EmuRunning == 3)
{
EmuStatus = 1;
@@ -739,6 +777,18 @@ void EmuThread::run()
oglContext->SetSwapInterval(0);
}
+ if (Config::DSiVolumeSync && NDS::ConsoleType == 1)
+ {
+ u8 volumeLevel = DSi_BPTWL::GetVolumeLevel();
+ if (volumeLevel != dsiVolumeLevel)
+ {
+ dsiVolumeLevel = volumeLevel;
+ emit syncVolumeLevel();
+ }
+
+ Config::AudioVolume = volumeLevel * (256.0 / 31.0);
+ }
+
if (Config::AudioSync && !fastforward && audioDevice)
{
SDL_LockMutex(audioSyncLock);
@@ -2583,7 +2633,7 @@ void MainWindow::onBootFirmware()
}
if (!ROMManager::LoadBIOS())
-{
+ {
// TODO: better error reporting?
QMessageBox::critical(this, "melonDS", "This firmware is not bootable.");
emuThread->emuUnpause();
@@ -3027,7 +3077,9 @@ void MainWindow::onCameraSettingsFinished(int res)
void MainWindow::onOpenAudioSettings()
{
- AudioSettingsDialog* dlg = AudioSettingsDialog::openDlg(this);
+ AudioSettingsDialog* dlg = AudioSettingsDialog::openDlg(this, emuThread->emuIsActive());
+ connect(emuThread, &EmuThread::syncVolumeLevel, dlg, &AudioSettingsDialog::onSyncVolumeLevel);
+ connect(emuThread, &EmuThread::windowEmuStart, dlg, &AudioSettingsDialog::onConsoleReset);
connect(dlg, &AudioSettingsDialog::updateAudioSettings, this, &MainWindow::onUpdateAudioSettings);
connect(dlg, &AudioSettingsDialog::finished, this, &MainWindow::onAudioSettingsFinished);
}
@@ -3270,7 +3322,8 @@ void MainWindow::onTitleUpdate(QString title)
setWindowTitle(title);
}
-void ToggleFullscreen(MainWindow* mainWindow) {
+void ToggleFullscreen(MainWindow* mainWindow)
+{
if (!mainWindow->isFullScreen())
{
mainWindow->showFullScreen();
@@ -3289,11 +3342,15 @@ void MainWindow::onFullscreenToggled()
ToggleFullscreen(this);
}
-void MainWindow::onScreenEmphasisToggled() {
+void MainWindow::onScreenEmphasisToggled()
+{
int currentSizing = Config::ScreenSizing;
- if (currentSizing == screenSizing_EmphTop) {
+ if (currentSizing == screenSizing_EmphTop)
+ {
Config::ScreenSizing = screenSizing_EmphBot;
- } else if (currentSizing == screenSizing_EmphBot) {
+ }
+ else if (currentSizing == screenSizing_EmphBot)
+ {
Config::ScreenSizing = screenSizing_EmphTop;
}
@@ -3436,7 +3493,7 @@ int main(int argc, char** argv)
}
SDL_JoystickEventState(SDL_ENABLE);
-
+
SDL_InitSubSystem(SDL_INIT_VIDEO);
SDL_EnableScreenSaver(); SDL_DisableScreenSaver();
diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h
index f9baea7..8a902ee 100644
--- a/src/frontend/qt_sdl/main.h
+++ b/src/frontend/qt_sdl/main.h
@@ -87,6 +87,8 @@ signals:
void swapScreensToggle();
void screenEmphasisToggle();
+ void syncVolumeLevel();
+
private:
void drawScreenGL();
void initOpenGL();