diff --git a/CircleOfFifths/AndroidManifest.xml b/CircleOfFifths/AndroidManifest.xml
index 203ba742..41838ba5 100644
--- a/CircleOfFifths/AndroidManifest.xml
+++ b/CircleOfFifths/AndroidManifest.xml
@@ -1,5 +1,6 @@
+
mEntries = new ArrayList<>();
+ private List mValues = new ArrayList<>();
+
+ private CharSequence[] listToArray(List l) {
+ String[] array = new String[l.size()];
+ l.toArray(array);
+ return array;
+ }
+ AudioDeviceList(PreferenceFragment prefFragment, String key) {
+ mPref = (ListPreference) prefFragment.findPreference(key);
+ mEntries.add("Default");
+ mValues.add("-1");
+ }
+ public void add(AudioDeviceInfo device) {
+ String name = device.getProductName().toString() + " " + typeToString(device.getType());
+ mEntries.add(name);
+ mValues.add(Integer.toString(device.getId()));
+ mPref.setEntries(listToArray(mEntries));
+ mPref.setEntryValues(listToArray(mValues));
+ }
+ }
+
+ private AudioDeviceList mInputDevices = null;
+ private AudioDeviceList mOutputDevices = null;
+
+ /**
+ * @param context activity or service that calls this method
+ */
+ public AudioDevices(Activity context) {
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ PreferenceFragment prefFragment = (PreferenceFragment) context.getFragmentManager().findFragmentByTag("prefFragment");
+ Resources res = context.getResources();
+ mInputDevices = new AudioDeviceList(prefFragment, res.getString(R.string.pref_key_indevice));
+ mOutputDevices = new AudioDeviceList(prefFragment, res.getString(R.string.pref_key_outdevice));
+ setupAudioDeviceCallback();
+ }
+
+ /**
+ * Converts the value from {@link AudioDeviceInfo#getType()} into a human
+ * readable string
+ * @param type One of the {@link AudioDeviceInfo}.TYPE_* values
+ * e.g. AudioDeviceInfo.TYPE_BUILT_IN_SPEAKER
+ * @return string which describes the type of audio device
+ */
+ static String typeToString(int type){
+ switch (type) {
+ case AudioDeviceInfo.TYPE_AUX_LINE:
+ return "auxiliary line-level connectors";
+ case AudioDeviceInfo.TYPE_BLUETOOTH_A2DP:
+ return "Bluetooth device supporting the A2DP profile";
+ case AudioDeviceInfo.TYPE_BLUETOOTH_SCO:
+ return "Bluetooth device typically used for telephony";
+ case AudioDeviceInfo.TYPE_BUILTIN_EARPIECE:
+ return "built-in earphone speaker";
+ case AudioDeviceInfo.TYPE_BUILTIN_MIC:
+ return "built-in microphone";
+ case AudioDeviceInfo.TYPE_BUILTIN_SPEAKER:
+ return "built-in speaker";
+ case AudioDeviceInfo.TYPE_BUS:
+ return "BUS";
+ case AudioDeviceInfo.TYPE_DOCK:
+ return "DOCK";
+ case AudioDeviceInfo.TYPE_FM:
+ return "FM";
+ case AudioDeviceInfo.TYPE_FM_TUNER:
+ return "FM tuner";
+ case AudioDeviceInfo.TYPE_HDMI:
+ return "HDMI";
+ case AudioDeviceInfo.TYPE_HDMI_ARC:
+ return "HDMI audio return channel";
+ case AudioDeviceInfo.TYPE_IP:
+ return "IP";
+ case AudioDeviceInfo.TYPE_LINE_ANALOG:
+ return "line analog";
+ case AudioDeviceInfo.TYPE_LINE_DIGITAL:
+ return "line digital";
+ case AudioDeviceInfo.TYPE_TELEPHONY:
+ return "telephony";
+ case AudioDeviceInfo.TYPE_TV_TUNER:
+ return "TV tuner";
+ case AudioDeviceInfo.TYPE_USB_ACCESSORY:
+ return "USB accessory";
+ case AudioDeviceInfo.TYPE_USB_DEVICE:
+ return "USB device";
+ case AudioDeviceInfo.TYPE_WIRED_HEADPHONES:
+ return "wired headphones";
+ case AudioDeviceInfo.TYPE_WIRED_HEADSET:
+ return "wired headset";
+ default:
+ case AudioDeviceInfo.TYPE_UNKNOWN:
+ return "unknown";
+ }
+ }
+
+ private void setupAudioDeviceCallback(){
+ // Note that we will immediately receive a call to onDevicesAdded with the list of
+ // devices which are currently connected.
+ mAudioManager.registerAudioDeviceCallback(new AudioDeviceCallback() {
+ @Override
+ public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
+ for (AudioDeviceInfo device : addedDevices){
+ if (device.isSource()) mInputDevices.add(device);
+ else if (device.isSink()) mOutputDevices.add(device);
+ }
+ }
+
+ public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
+ }
+ }, null);
+ }
+}
diff --git a/PdCore/pd-core/src/main/java/org/puredata/android/io/PdAudio.java b/PdCore/pd-core/src/main/java/org/puredata/android/io/PdAudio.java
index cc577ec2..0b7f8224 100644
--- a/PdCore/pd-core/src/main/java/org/puredata/android/io/PdAudio.java
+++ b/PdCore/pd-core/src/main/java/org/puredata/android/io/PdAudio.java
@@ -26,6 +26,8 @@
public class PdAudio {
private static AudioWrapper audioWrapper = null;
+ private static int inputDeviceId = -1;
+ private static int outputDeviceId = -1;
private static final Handler handler = new Handler(Looper.getMainLooper());
private static final Runnable pollRunner = new Runnable() {
@Override
@@ -77,6 +79,17 @@ protected int process(short[] inBuffer, short[] outBuffer) {
}
}
+ /**
+ * Set the audio input and output devices Id. Call it before startAudio().
+ *
+ * @param inDeviceId id of the audio input device (-1 means the default device)
+ * @param outDeviceId id of the audio output device (-1 means the default device)
+ */
+ public synchronized static void setDevicesId(int inDeviceId, int outDeviceId) {
+ inputDeviceId = inDeviceId;
+ outputDeviceId = outDeviceId;
+ }
+
/**
* Starts the audio components.
*
@@ -85,6 +98,8 @@ protected int process(short[] inBuffer, short[] outBuffer) {
public synchronized static void startAudio(Context context) {
PdBase.computeAudio(true);
if (PdBase.implementsAudio()) {
+ PdBase.setRecordingDeviceId(inputDeviceId);
+ PdBase.setPlaybackDeviceId(outputDeviceId);
handler.post(pollRunner);
PdBase.startAudio();
} else {
diff --git a/PdCore/pd-core/src/main/java/org/puredata/android/service/PdPreferences.java b/PdCore/pd-core/src/main/java/org/puredata/android/service/PdPreferences.java
index 61991f44..319922e7 100644
--- a/PdCore/pd-core/src/main/java/org/puredata/android/service/PdPreferences.java
+++ b/PdCore/pd-core/src/main/java/org/puredata/android/service/PdPreferences.java
@@ -8,6 +8,7 @@
package org.puredata.android.service;
import org.puredata.android.io.AudioParameters;
+import org.puredata.android.io.AudioDevices;
import org.puredata.core.PdBase;
import android.content.Context;
@@ -16,6 +17,7 @@
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
+import android.preference.PreferenceFragment;
/**
*
@@ -27,13 +29,14 @@
*/
public class PdPreferences extends PreferenceActivity {
- @SuppressWarnings("deprecation")
+ public AudioDevices audioDevices = null;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AudioParameters.init(this);
initPreferences(getApplicationContext());
- addPreferencesFromResource(R.xml.preferences);
+ getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment(), "prefFragment").commit();
}
@Override
@@ -41,6 +44,18 @@ protected void onDestroy() {
super.onDestroy();
}
+ public static class MyPreferenceFragment extends PreferenceFragment
+ {
+ @Override
+ public void onCreate(final Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ Resources res = getResources();
+ addPreferencesFromResource(R.xml.preferences);
+ ((PdPreferences)getActivity()).audioDevices = new AudioDevices(getActivity());
+ }
+ }
+
/**
* If no preferences are available, initialize preferences with defaults suggested by {@link PdBase} or {@link AudioParameters}, in that order.
*
@@ -53,8 +68,10 @@ public static void initPreferences(Context context) {
SharedPreferences.Editor editor = prefs.edit();
int srate = PdBase.suggestSampleRate();
editor.putString(res.getString(R.string.pref_key_srate), "" + ((srate > 0) ? srate : AudioParameters.suggestSampleRate()));
+ editor.putString(res.getString(R.string.pref_key_indevice), res.getStringArray(R.array.indevice_values)[0]);
int nic = PdBase.suggestInputChannels();
editor.putString(res.getString(R.string.pref_key_inchannels), "" + ((nic > 0) ? nic : AudioParameters.suggestInputChannels()));
+ editor.putString(res.getString(R.string.pref_key_outdevice), res.getStringArray(R.array.outdevice_values)[0]);
int noc = PdBase.suggestOutputChannels();
editor.putString(res.getString(R.string.pref_key_outchannels), "" + ((noc > 0) ? noc : AudioParameters.suggestOutputChannels()));
editor.commit();
diff --git a/PdCore/pd-core/src/main/java/org/puredata/android/service/PdService.java b/PdCore/pd-core/src/main/java/org/puredata/android/service/PdService.java
index 18dc6c42..f4accfb3 100644
--- a/PdCore/pd-core/src/main/java/org/puredata/android/service/PdService.java
+++ b/PdCore/pd-core/src/main/java/org/puredata/android/service/PdService.java
@@ -100,6 +100,18 @@ public synchronized void initAudio(int srate, int nic, int noc, float millis) th
stopForeground();
Resources res = getResources();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ int in_id = -1;
+ int out_id = -1;
+ {
+ String s = prefs.getString(res.getString(R.string.pref_key_indevice), null);
+ if (s != null) {
+ in_id = Integer.parseInt(s);
+ }
+ s = prefs.getString(res.getString(R.string.pref_key_outdevice), null);
+ if (s != null) {
+ out_id = Integer.parseInt(s);
+ }
+ }
if (srate < 0) {
String s = prefs.getString(res.getString(R.string.pref_key_srate), null);
if (s != null) {
@@ -137,6 +149,7 @@ public synchronized void initAudio(int srate, int nic, int noc, float millis) th
millis = 50.0f; // conservative choice
}
int tpb = (int) (0.001f * millis * srate / PdBase.blockSize()) + 1;
+ PdAudio.setDevicesId(in_id, out_id);
PdAudio.initAudio(srate, nic, noc, tpb, true);
sampleRate = srate;
inputChannels = nic;
@@ -213,6 +226,7 @@ public boolean onUnbind(Intent intent) {
@Override
public void onCreate() {
super.onCreate();
+
AudioParameters.init(this);
if (!abstractionsInstalled) {
try {
diff --git a/PdCore/pd-core/src/main/jni/Application.mk b/PdCore/pd-core/src/main/jni/Application.mk
index 1d0b95ea..fb60ca30 100644
--- a/PdCore/pd-core/src/main/jni/Application.mk
+++ b/PdCore/pd-core/src/main/jni/Application.mk
@@ -1,3 +1,4 @@
APP_PLATFORM := android-28
APP_OPTIM := release
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
+APP_STL := c++_shared
diff --git a/PdCore/pd-core/src/main/jni/libpd b/PdCore/pd-core/src/main/jni/libpd
index d7d1e1ef..2ed8b39b 160000
--- a/PdCore/pd-core/src/main/jni/libpd
+++ b/PdCore/pd-core/src/main/jni/libpd
@@ -1 +1 @@
-Subproject commit d7d1e1ef6259583065d7bd0b5b37112fa29d2eb6
+Subproject commit 2ed8b39ba0a82c27b9da087dac01d8e5ff55ee85
diff --git a/PdCore/pd-core/src/main/res/values/audio.xml b/PdCore/pd-core/src/main/res/values/audio.xml
index 80aef857..7be836c8 100644
--- a/PdCore/pd-core/src/main/res/values/audio.xml
+++ b/PdCore/pd-core/src/main/res/values/audio.xml
@@ -18,6 +18,12 @@
- 44100
- 48000
+
+ - Default
+
+
+ - -1
+
- None
- Mono
@@ -28,6 +34,12 @@
- 1
- 2
+
+ - Default
+
+
+ - -1
+
- None
- Mono
diff --git a/PdCore/pd-core/src/main/res/values/strings.xml b/PdCore/pd-core/src/main/res/values/strings.xml
index 26d9d507..a808125b 100644
--- a/PdCore/pd-core/src/main/res/values/strings.xml
+++ b/PdCore/pd-core/src/main/res/values/strings.xml
@@ -5,9 +5,15 @@
SAMPLE_RATE
Sample rate
Sample rate for Pure Data
+ INPUT_DEVICE
+ Input device
+ Name of the input device
INPUT_CHANNELS
Input channels
Number of input channels
+ OUTPUT_DEVICE
+ Output device
+ Name of the output device
OUTPUT_CHANNELS
Output channels
Number of output channels
diff --git a/PdCore/pd-core/src/main/res/xml/preferences.xml b/PdCore/pd-core/src/main/res/xml/preferences.xml
index c33c0714..611484e9 100644
--- a/PdCore/pd-core/src/main/res/xml/preferences.xml
+++ b/PdCore/pd-core/src/main/res/xml/preferences.xml
@@ -5,9 +5,15 @@
android:entries="@array/srate_labels" android:key="@string/pref_key_srate"
android:title="@string/pref_title_srate" android:summary="@string/pref_sum_srate">
+
+
diff --git a/PdTest/AndroidManifest.xml b/PdTest/AndroidManifest.xml
index 5961975c..4140ee62 100644
--- a/PdTest/AndroidManifest.xml
+++ b/PdTest/AndroidManifest.xml
@@ -20,5 +20,6 @@
-
+
+
diff --git a/PdTest/jni/Application.mk b/PdTest/jni/Application.mk
index 1dfcd802..234df209 100644
--- a/PdTest/jni/Application.mk
+++ b/PdTest/jni/Application.mk
@@ -1,4 +1,4 @@
APP_OPTIM := release
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
APP_ALLOW_MISSING_DEPS=true
-
+APP_STL := c++_shared
diff --git a/README.md b/README.md
index 5d85c7e8..243a6a60 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,7 @@ allprojects {
```gradle
dependencies {
- implementation 'io.github.libpd.android:pd-core:1.3.0-SNAPSHOT'
+ implementation 'io.github.libpd.android:pd-core:1.4.0-SNAPSHOT'
}
```
diff --git a/ScenePlayer/AndroidManifest.xml b/ScenePlayer/AndroidManifest.xml
index cf6c4342..565d703c 100644
--- a/ScenePlayer/AndroidManifest.xml
+++ b/ScenePlayer/AndroidManifest.xml
@@ -10,6 +10,7 @@
+
@@ -64,4 +65,4 @@
-
\ No newline at end of file
+
diff --git a/ScenePlayer/jni/Application.mk b/ScenePlayer/jni/Application.mk
index 1dfcd802..234df209 100644
--- a/ScenePlayer/jni/Application.mk
+++ b/ScenePlayer/jni/Application.mk
@@ -1,4 +1,4 @@
APP_OPTIM := release
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
APP_ALLOW_MISSING_DEPS=true
-
+APP_STL := c++_shared
diff --git a/Voice-O-Rama/AndroidManifest.xml b/Voice-O-Rama/AndroidManifest.xml
index 75dab709..b4340e15 100644
--- a/Voice-O-Rama/AndroidManifest.xml
+++ b/Voice-O-Rama/AndroidManifest.xml
@@ -5,6 +5,7 @@
+