diff --git a/app/src/main/cpp/pcsx2/Host/AudioStream.cpp b/app/src/main/cpp/pcsx2/Host/AudioStream.cpp
index ab13a15..0a140c6 100644
--- a/app/src/main/cpp/pcsx2/Host/AudioStream.cpp
+++ b/app/src/main/cpp/pcsx2/Host/AudioStream.cpp
@@ -370,6 +370,9 @@ void AudioStream::StereoSampleReaderImpl(SampleType* dest, const SampleType* src
void AudioStream::InternalWriteFrames(const SampleType* data, u32 num_frames)
{
+ if (!m_buffer || m_buffer_size == 0)
+ return;
+
const u32 free = m_buffer_size - GetBufferedFramesRelaxed();
if (free <= num_frames)
{
@@ -635,6 +638,9 @@ void AudioStream::EndWrite(u32 num_frames)
void AudioStream::WriteChunk(const SampleType* chunk)
{
+ if (!m_buffer || m_buffer_size == 0)
+ return;
+
if (!IsExpansionEnabled() && !IsStretchEnabled())
{
InternalWriteFrames(chunk, CHUNK_SIZE);
diff --git a/app/src/main/cpp/pcsx2/SPU2/spu2.cpp b/app/src/main/cpp/pcsx2/SPU2/spu2.cpp
index 84b793a..8d4c388 100644
--- a/app/src/main/cpp/pcsx2/SPU2/spu2.cpp
+++ b/app/src/main/cpp/pcsx2/SPU2/spu2.cpp
@@ -444,7 +444,8 @@ __forceinline void spu2Output(StereoOut32 out)
{
s_current_chunk_pos = 0;
- s_output_stream->WriteChunk(s_current_chunk.data());
+ if (s_output_stream)
+ s_output_stream->WriteChunk(s_current_chunk.data());
if (SPU2::IsAudioCaptureActive()) [[unlikely]]
GSCapture::DeliverAudioPacket(s_current_chunk.data());
diff --git a/app/src/main/java/com/izzy2lost/psx2/GamesCoverDialogFragment.java b/app/src/main/java/com/izzy2lost/psx2/GamesCoverDialogFragment.java
index b910013..c09e5af 100644
--- a/app/src/main/java/com/izzy2lost/psx2/GamesCoverDialogFragment.java
+++ b/app/src/main/java/com/izzy2lost/psx2/GamesCoverDialogFragment.java
@@ -634,10 +634,34 @@ public class GamesCoverDialogFragment extends DialogFragment {
} catch (Throwable ignored) {}
}
- private void setupDialogDrawerSettings(View header) {
+ private void setupDialogDrawerSettings(View header) {
if (header == null) return;
android.content.SharedPreferences prefs = requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
+ MaterialButtonToggleGroup tgOrientation = header.findViewById(R.id.drawer_tg_orientation);
+ View tbOrientAuto = header.findViewById(R.id.drawer_tb_orientation_auto);
+ View tbOrientLand = header.findViewById(R.id.drawer_tb_orientation_landscape);
+ View tbOrientPort = header.findViewById(R.id.drawer_tb_orientation_portrait);
+ if (tgOrientation != null && tbOrientAuto != null && tbOrientLand != null && tbOrientPort != null) {
+ int savedOrientation = prefs.getInt("orientation_lock", MainActivity.ORIENTATION_AUTO);
+ int checkId = savedOrientation == MainActivity.ORIENTATION_LANDSCAPE ? tbOrientLand.getId()
+ : (savedOrientation == MainActivity.ORIENTATION_PORTRAIT ? tbOrientPort.getId() : tbOrientAuto.getId());
+ tgOrientation.check(checkId);
+ tgOrientation.addOnButtonCheckedListener((group, checkedId, isChecked) -> {
+ if (!isChecked) return;
+ int mode = MainActivity.ORIENTATION_AUTO;
+ if (checkedId == tbOrientLand.getId()) mode = MainActivity.ORIENTATION_LANDSCAPE;
+ else if (checkedId == tbOrientPort.getId()) mode = MainActivity.ORIENTATION_PORTRAIT;
+ try {
+ if (getActivity() instanceof MainActivity) {
+ ((MainActivity) getActivity()).setOrientationPreference(mode);
+ } else {
+ prefs.edit().putInt("orientation_lock", mode).apply();
+ }
+ } catch (Throwable ignored) {}
+ });
+ }
+
// Aspect Ratio spinner
android.widget.Spinner spAspect = header.findViewById(R.id.drawer_sp_aspect_ratio);
if (spAspect != null) {
@@ -1245,66 +1269,81 @@ public class GamesCoverDialogFragment extends DialogFragment {
try {
View root = getView();
if (root == null) return;
-
+
com.google.android.material.navigation.NavigationView nav = root.findViewById(R.id.dialog_nav_view);
- if (nav != null && nav.getHeaderCount() > 0) {
- View header = nav.getHeaderView(0);
- if (header != null) {
- android.content.SharedPreferences prefs = requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
-
- // Refresh spinner values to reflect current settings
- android.widget.Spinner spAspect = header.findViewById(R.id.drawer_sp_aspect_ratio);
- if (spAspect != null && spAspect.getAdapter() != null) {
- int savedAspect = prefs.getInt("aspect_ratio", 1);
- android.widget.ArrayAdapter> aspectAdapter = (android.widget.ArrayAdapter>) spAspect.getAdapter();
- if (savedAspect >= 0 && savedAspect < aspectAdapter.getCount()) {
- spAspect.setSelection(savedAspect);
- }
- }
+ if (nav == null || nav.getHeaderCount() == 0) return;
- android.widget.Spinner spScale = header.findViewById(R.id.drawer_sp_scale);
- if (spScale != null && spScale.getAdapter() != null) {
- float savedScale = prefs.getFloat("upscale_multiplier", 1.0f);
- android.widget.ArrayAdapter> scaleAdapter = (android.widget.ArrayAdapter>) spScale.getAdapter();
- int scaleIndex = Math.max(0, Math.min(scaleAdapter.getCount() - 1, Math.round(savedScale) - 1));
- spScale.setSelection(scaleIndex);
- }
+ View header = nav.getHeaderView(0);
+ if (header == null) return;
- android.widget.Spinner spBlending = header.findViewById(R.id.drawer_sp_blending_accuracy);
- if (spBlending != null && spBlending.getAdapter() != null) {
- int savedBlend = prefs.getInt("blending_accuracy", 1);
- android.widget.ArrayAdapter> blendAdapter = (android.widget.ArrayAdapter>) spBlending.getAdapter();
- if (savedBlend >= 0 && savedBlend < blendAdapter.getCount()) {
- spBlending.setSelection(savedBlend);
- }
- }
-
- // Refresh switch states
- com.google.android.material.materialswitch.MaterialSwitch swWide = header.findViewById(R.id.drawer_sw_widescreen);
- if (swWide != null) {
- swWide.setChecked(prefs.getBoolean("widescreen_patches", true));
- }
+ android.content.SharedPreferences prefs = requireContext().getSharedPreferences("app_prefs", Context.MODE_PRIVATE);
- com.google.android.material.materialswitch.MaterialSwitch swNoInt = header.findViewById(R.id.drawer_sw_no_interlacing);
- if (swNoInt != null) {
- swNoInt.setChecked(prefs.getBoolean("no_interlacing_patches", true));
- }
-
- com.google.android.material.materialswitch.MaterialSwitch swLoadTex = header.findViewById(R.id.drawer_sw_load_textures);
- if (swLoadTex != null) {
- swLoadTex.setChecked(prefs.getBoolean("load_textures", false));
- }
-
- com.google.android.material.materialswitch.MaterialSwitch swAsyncTex = header.findViewById(R.id.drawer_sw_async_textures);
- if (swAsyncTex != null) {
- swAsyncTex.setChecked(prefs.getBoolean("async_texture_loading", true));
- }
-
- com.google.android.material.materialswitch.MaterialSwitch swPrecache = header.findViewById(R.id.drawer_sw_precache_textures);
- if (swPrecache != null) {
- swPrecache.setChecked(prefs.getBoolean("precache_textures", false));
- }
+ try {
+ MaterialButtonToggleGroup tgOrientation = header.findViewById(R.id.drawer_tg_orientation);
+ View tbOrientAuto = header.findViewById(R.id.drawer_tb_orientation_auto);
+ View tbOrientLand = header.findViewById(R.id.drawer_tb_orientation_landscape);
+ View tbOrientPort = header.findViewById(R.id.drawer_tb_orientation_portrait);
+ if (tgOrientation != null && tbOrientAuto != null && tbOrientLand != null && tbOrientPort != null) {
+ int savedOrientation = prefs.getInt("orientation_lock", MainActivity.ORIENTATION_AUTO);
+ int checkId = savedOrientation == MainActivity.ORIENTATION_LANDSCAPE ? tbOrientLand.getId()
+ : (savedOrientation == MainActivity.ORIENTATION_PORTRAIT ? tbOrientPort.getId() : tbOrientAuto.getId());
+ tgOrientation.check(checkId);
}
+ } catch (Exception e) {
+ android.util.Log.e("GamesCoverDialog", "Error refreshing orientation toggle: " + e.getMessage());
+ }
+
+ // Refresh spinner values to reflect current settings
+ android.widget.Spinner spAspect = header.findViewById(R.id.drawer_sp_aspect_ratio);
+ if (spAspect != null && spAspect.getAdapter() != null) {
+ int savedAspect = prefs.getInt("aspect_ratio", 1);
+ android.widget.ArrayAdapter> aspectAdapter = (android.widget.ArrayAdapter>) spAspect.getAdapter();
+ if (savedAspect >= 0 && savedAspect < aspectAdapter.getCount()) {
+ spAspect.setSelection(savedAspect);
+ }
+ }
+
+ android.widget.Spinner spScale = header.findViewById(R.id.drawer_sp_scale);
+ if (spScale != null && spScale.getAdapter() != null) {
+ float savedScale = prefs.getFloat("upscale_multiplier", 1.0f);
+ android.widget.ArrayAdapter> scaleAdapter = (android.widget.ArrayAdapter>) spScale.getAdapter();
+ int scaleIndex = Math.max(0, Math.min(scaleAdapter.getCount() - 1, Math.round(savedScale) - 1));
+ spScale.setSelection(scaleIndex);
+ }
+
+ android.widget.Spinner spBlending = header.findViewById(R.id.drawer_sp_blending_accuracy);
+ if (spBlending != null && spBlending.getAdapter() != null) {
+ int savedBlend = prefs.getInt("blending_accuracy", 1);
+ android.widget.ArrayAdapter> blendAdapter = (android.widget.ArrayAdapter>) spBlending.getAdapter();
+ if (savedBlend >= 0 && savedBlend < blendAdapter.getCount()) {
+ spBlending.setSelection(savedBlend);
+ }
+ }
+
+ // Refresh switch states
+ com.google.android.material.materialswitch.MaterialSwitch swWide = header.findViewById(R.id.drawer_sw_widescreen);
+ if (swWide != null) {
+ swWide.setChecked(prefs.getBoolean("widescreen_patches", true));
+ }
+
+ com.google.android.material.materialswitch.MaterialSwitch swNoInt = header.findViewById(R.id.drawer_sw_no_interlacing);
+ if (swNoInt != null) {
+ swNoInt.setChecked(prefs.getBoolean("no_interlacing_patches", true));
+ }
+
+ com.google.android.material.materialswitch.MaterialSwitch swLoadTex = header.findViewById(R.id.drawer_sw_load_textures);
+ if (swLoadTex != null) {
+ swLoadTex.setChecked(prefs.getBoolean("load_textures", false));
+ }
+
+ com.google.android.material.materialswitch.MaterialSwitch swAsyncTex = header.findViewById(R.id.drawer_sw_async_textures);
+ if (swAsyncTex != null) {
+ swAsyncTex.setChecked(prefs.getBoolean("async_texture_loading", true));
+ }
+
+ com.google.android.material.materialswitch.MaterialSwitch swPrecache = header.findViewById(R.id.drawer_sw_precache_textures);
+ if (swPrecache != null) {
+ swPrecache.setChecked(prefs.getBoolean("precache_textures", false));
}
} catch (Throwable ignored) {}
}
diff --git a/app/src/main/java/com/izzy2lost/psx2/MainActivity.java b/app/src/main/java/com/izzy2lost/psx2/MainActivity.java
index 6b121b8..3be73c7 100644
--- a/app/src/main/java/com/izzy2lost/psx2/MainActivity.java
+++ b/app/src/main/java/com/izzy2lost/psx2/MainActivity.java
@@ -38,6 +38,7 @@ import android.app.RemoteAction;
import android.graphics.drawable.Icon;
import android.app.PendingIntent;
import android.content.pm.PackageManager;
+import android.content.pm.ActivityInfo;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
@@ -55,7 +56,6 @@ import androidx.core.view.WindowInsetsCompat;
import androidx.core.graphics.Insets;
import com.google.android.material.button.MaterialButton;
-
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -70,6 +70,10 @@ import java.util.List;
import java.util.Locale;
public class MainActivity extends AppCompatActivity implements GamesCoverDialogFragment.OnGameSelectedListener, ControllerInputHandler.ControllerInputListener {
+ public static final int ORIENTATION_AUTO = 0;
+ public static final int ORIENTATION_LANDSCAPE = 1;
+ public static final int ORIENTATION_PORTRAIT = 2;
+
private String m_szGamefile = "";
private HIDDeviceManager mHIDDeviceManager;
@@ -1942,11 +1946,67 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
}
}
+ private int normalizeOrientationPref(int value) {
+ if (value == ORIENTATION_LANDSCAPE || value == ORIENTATION_PORTRAIT) return value;
+ return ORIENTATION_AUTO;
+ }
+
+ public void setOrientationPreference(int mode) {
+ int normalized = normalizeOrientationPref(mode);
+ try {
+ SharedPreferences prefs = getSharedPreferences("app_prefs", MODE_PRIVATE);
+ prefs.edit().putInt("orientation_lock", normalized).apply();
+ } catch (Throwable ignored) {}
+ applyOrientationPreference(normalized);
+ }
+
+ public void applyOrientationPreference() {
+ int mode = ORIENTATION_AUTO;
+ try {
+ SharedPreferences prefs = getSharedPreferences("app_prefs", MODE_PRIVATE);
+ mode = normalizeOrientationPref(prefs.getInt("orientation_lock", ORIENTATION_AUTO));
+ } catch (Throwable ignored) {}
+ applyOrientationPreference(mode);
+ }
+
+ private void applyOrientationPreference(int mode) {
+ int requested = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
+ if (mode == ORIENTATION_LANDSCAPE) {
+ requested = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+ } else if (mode == ORIENTATION_PORTRAIT) {
+ requested = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
+ }
+
+ try {
+ setRequestedOrientation(requested);
+ } catch (Throwable e) {
+ android.util.Log.e("MainActivity", "Failed to apply orientation preference: " + e.getMessage());
+ }
+ }
+
private void setupDrawerSettings(View header) {
if (header == null) return;
SharedPreferences prefs = getSharedPreferences("app_prefs", MODE_PRIVATE);
+ MaterialButtonToggleGroup tgOrientation = header.findViewById(R.id.drawer_tg_orientation);
+ View tbOrientAuto = header.findViewById(R.id.drawer_tb_orientation_auto);
+ View tbOrientLand = header.findViewById(R.id.drawer_tb_orientation_landscape);
+ View tbOrientPort = header.findViewById(R.id.drawer_tb_orientation_portrait);
+ if (tgOrientation != null && tbOrientAuto != null && tbOrientLand != null && tbOrientPort != null) {
+ int savedOrientation = normalizeOrientationPref(prefs.getInt("orientation_lock", ORIENTATION_AUTO));
+ int checkId = savedOrientation == ORIENTATION_LANDSCAPE ? tbOrientLand.getId()
+ : (savedOrientation == ORIENTATION_PORTRAIT ? tbOrientPort.getId() : tbOrientAuto.getId());
+ tgOrientation.check(checkId);
+ tgOrientation.addOnButtonCheckedListener((group, checkedId, isChecked) -> {
+ if (!isChecked) return;
+ int mode = ORIENTATION_AUTO;
+ if (checkedId == tbOrientLand.getId()) mode = ORIENTATION_LANDSCAPE;
+ else if (checkedId == tbOrientPort.getId()) mode = ORIENTATION_PORTRAIT;
+ setOrientationPreference(mode);
+ });
+ }
+
// Aspect Ratio spinner - setup like QuickActions
Spinner spAspect = header.findViewById(R.id.drawer_sp_aspect_ratio);
if (spAspect != null) {
@@ -2118,7 +2178,22 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
android.util.Log.e("MainActivity", "SharedPreferences is null during refreshDrawerSettings");
return;
}
-
+
+ try {
+ MaterialButtonToggleGroup tgOrientation = header.findViewById(R.id.drawer_tg_orientation);
+ View tbOrientAuto = header.findViewById(R.id.drawer_tb_orientation_auto);
+ View tbOrientLand = header.findViewById(R.id.drawer_tb_orientation_landscape);
+ View tbOrientPort = header.findViewById(R.id.drawer_tb_orientation_portrait);
+ if (tgOrientation != null && tbOrientAuto != null && tbOrientLand != null && tbOrientPort != null) {
+ int savedOrientation = normalizeOrientationPref(prefs.getInt("orientation_lock", ORIENTATION_AUTO));
+ int checkId = savedOrientation == ORIENTATION_LANDSCAPE ? tbOrientLand.getId()
+ : (savedOrientation == ORIENTATION_PORTRAIT ? tbOrientPort.getId() : tbOrientAuto.getId());
+ tgOrientation.check(checkId);
+ }
+ } catch (Exception e) {
+ android.util.Log.e("MainActivity", "Error refreshing orientation toggle: " + e.getMessage());
+ }
+
// Refresh spinner values to reflect current settings
try {
Spinner spAspect = header.findViewById(R.id.drawer_sp_aspect_ratio);
@@ -2249,6 +2324,8 @@ public class MainActivity extends AppCompatActivity implements GamesCoverDialogF
// Apply renderer setting
int renderer = prefs.getInt("renderer", -1);
NativeApp.renderGpu(renderer);
+
+ applyOrientationPreference();
} catch (Throwable ignored) {}
}
diff --git a/app/src/main/res/layout/drawer_header_settings.xml b/app/src/main/res/layout/drawer_header_settings.xml
index adccd4e..3007d5f 100644
--- a/app/src/main/res/layout/drawer_header_settings.xml
+++ b/app/src/main/res/layout/drawer_header_settings.xml
@@ -104,14 +104,66 @@
android:textColor="@color/brand_primary"
android:checkable="true" />
+
+
+
+
+
+
+
+
+
+
+
+