diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AudioSettingsMenu.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AudioSettingsMenu.java
index 1da8ee55..ab493479 100644
--- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AudioSettingsMenu.java
+++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2AudioSettingsMenu.java
@@ -165,6 +165,65 @@ public class Apple2AudioSettingsMenu implements Apple2MenuView {
seekBarValue.setText("" + vol);
return convertView;
}
+ },
+ ADVANCED_SEPARATOR {
+ @Override public String getTitle(Apple2Activity activity) {
+ return activity.getResources().getString(R.string.settings_advanced);
+ }
+ @Override public String getSummary(Apple2Activity activity) {
+ return activity.getResources().getString(R.string.settings_advanced_summary);
+ }
+ },
+ AUDIO_LATENCY {
+ @Override public String getTitle(Apple2Activity activity) {
+ return activity.getResources().getString(R.string.audio_latency);
+ }
+ @Override public String getSummary(Apple2Activity activity) {
+ return activity.getResources().getString(R.string.audio_latency_summary);
+ }
+ @Override public View getView(final Apple2Activity activity, View convertView) {
+ LayoutInflater inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ convertView = inflater.inflate(R.layout.a2preference_slider, null, false);
+
+ TextView tv = (TextView)convertView.findViewById(R.id.a2preference_slider_summary);
+ tv.setText(getSummary(activity));
+
+ final TextView seekBarValue = (TextView)convertView.findViewById(R.id.a2preference_slider_seekBarValue);
+
+ final SeekBar sb = (SeekBar)convertView.findViewById(R.id.a2preference_slider_seekBar);
+ sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ if (!fromUser) {
+ return;
+ }
+ if (progress <= 0) {
+ // buffer size cannot be zero
+ progress = 1;
+ sb.setProgress(progress);
+ }
+ float latencySecs = (float)progress / Apple2Preferences.AUDIO_LATENCY_NUM_CHOICES;
+ seekBarValue.setText("" + latencySecs);
+ Apple2Preferences.AUDIO_LATENCY.saveFloat(activity, latencySecs);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+
+ sb.setMax(0); // http://stackoverflow.com/questions/10278467/seekbar-not-setting-actual-progress-setprogress-not-working-on-early-android
+ sb.setMax(Apple2Preferences.AUDIO_LATENCY_NUM_CHOICES);
+ float latencySecs = Apple2Preferences.AUDIO_LATENCY.floatValue(activity);
+ seekBarValue.setText("" + latencySecs);
+ int tick = (int) (latencySecs * (float) Apple2Preferences.AUDIO_LATENCY_NUM_CHOICES);
+ sb.setProgress(tick);
+ return convertView;
+ }
};
private static View _basicView(Apple2Activity activity, SETTINGS setting, View convertView) {
diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java
index c5186107..970f4f1c 100644
--- a/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java
+++ b/Android/app/src/main/java/org/deadc0de/apple2ix/Apple2Preferences.java
@@ -71,6 +71,27 @@ public enum Apple2Preferences {
@Override public int intValue(Apple2Activity activity) {
return activity.getPreferences(Context.MODE_PRIVATE).getInt(toString(), Volume.MEDIUM.ordinal());
}
+ },
+ AUDIO_LATENCY {
+ @Override public void load(Apple2Activity activity) {
+ nativeSetAudioLatency(floatValue(activity));
+ }
+ @Override public float floatValue(Apple2Activity activity) {
+
+ float defaultLatency = 0.f;
+ if (defaultLatency == 0.f) {
+ int sampleRateCanary = DevicePropertyCalculator.getRecommendedSampleRate(activity);
+ if (sampleRateCanary == DevicePropertyCalculator.defaultSampleRate) {
+ // quite possibly an audio-challenged device
+ defaultLatency = 0.4f;
+ } else {
+ // reasonable default for high-end devices
+ defaultLatency = 0.25f;
+ }
+ }
+
+ return activity.getPreferences(Context.MODE_PRIVATE).getFloat(toString(), defaultLatency);
+ }
};
public enum HiresColor {
@@ -111,16 +132,21 @@ public enum Apple2Preferences {
dialog.show();
}
+ public final static int AUDIO_LATENCY_NUM_CHOICES = 20;
public final static String TAG = "Apple2Preferences";
// set and apply
+ public void saveBoolean(Apple2Activity activity, boolean value) {
+ activity.getPreferences(Context.MODE_PRIVATE).edit().putBoolean(toString(), value).apply();
+ load(activity);
+ }
public void saveInt(Apple2Activity activity, int value) {
activity.getPreferences(Context.MODE_PRIVATE).edit().putInt(toString(), value).apply();
load(activity);
}
- public void saveBoolean(Apple2Activity activity, boolean value) {
- activity.getPreferences(Context.MODE_PRIVATE).edit().putBoolean(toString(), value).apply();
+ public void saveFloat(Apple2Activity activity, float value) {
+ activity.getPreferences(Context.MODE_PRIVATE).edit().putFloat(toString(), value).apply();
load(activity);
}
public void saveHiresColor(Apple2Activity activity, HiresColor value) {
@@ -142,12 +168,21 @@ public enum Apple2Preferences {
return activity.getPreferences(Context.MODE_PRIVATE).getInt(toString(), 0);
}
+ public float floatValue(Apple2Activity activity) {
+ return activity.getPreferences(Context.MODE_PRIVATE).getFloat(toString(), 0.0f);
+ }
+
public static void loadPreferences(Apple2Activity activity) {
for (Apple2Preferences pref : Apple2Preferences.values()) {
pref.load(activity);
}
}
+ public static void resetPreferences(Apple2Activity activity) {
+ activity.getPreferences(Context.MODE_PRIVATE).edit().clear().commit();
+ loadPreferences(activity);
+ }
+
private static native void nativeEnableTouchJoystick(boolean enabled);
private static native void nativeEnableTiltJoystick(boolean enabled);
private static native void nativeSetColor(int color);
@@ -155,4 +190,5 @@ public enum Apple2Preferences {
private static native void nativeSetSpeakerVolume(int volume);
private static native boolean nativeSetMockingboardEnabled(boolean enabled);
private static native void nativeSetMockingboardVolume(int volume);
+ private static native void nativeSetAudioLatency(float latencySecs);
}
diff --git a/Android/app/src/main/java/org/deadc0de/apple2ix/DevicePropertyCalculator.java b/Android/app/src/main/java/org/deadc0de/apple2ix/DevicePropertyCalculator.java
index 8f9d6af0..de4e742e 100644
--- a/Android/app/src/main/java/org/deadc0de/apple2ix/DevicePropertyCalculator.java
+++ b/Android/app/src/main/java/org/deadc0de/apple2ix/DevicePropertyCalculator.java
@@ -38,6 +38,8 @@ import android.os.Build;
*/
public final class DevicePropertyCalculator
{
+ public final static int defaultSampleRate = 22050;
+
public static boolean detectLowLatency( Context aContext )
{
// check for low latency audio
@@ -84,7 +86,6 @@ public final class DevicePropertyCalculator
SR_CHECK = am.getProperty( AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE );
}
- final int defaultSampleRate = 22050;
return ( SR_CHECK != null ) ? Integer.parseInt( SR_CHECK ) : defaultSampleRate;
}
diff --git a/Android/app/src/main/res/values/strings.xml b/Android/app/src/main/res/values/strings.xml
index aad258d6..868dd911 100644
--- a/Android/app/src/main/res/values/strings.xml
+++ b/Android/app/src/main/res/values/strings.xml
@@ -9,7 +9,9 @@
Settings
Apple2ix
Configure audio…
- Volume, mockingboard, etc
+ Speaker volume, Mockingboard, etc
+ Audio latency
+ Audio latency in secs
Cancel
Black/white
Color
@@ -63,6 +65,8 @@
Left/right swiping decreases/increases emulation speed
Apple2ix emulator settings
Apple2ix audio settings
+ Advanced settings
+ Warning: these settings may potentially degrade emulation performance
General
Joystick
SecondActivity