import com.jsyn.JSyn;
This code will create a gray window on an Android device when run on Windows 11, but will not run in Android mode on MacOS (M4 Tahoe 26.5) and displays this error message:
Exception in thread "Thread-105" java.lang.NullPointerException: Cannot read the array length because "list" is null
at processing.app.Library.wrapFiles(Library.java:429)
at processing.app.Library.getApplicationExports(Library.java:439)
at processing.mode.android.AndroidBuild.copyImportedLibs(AndroidBuild.java:839)
at processing.mode.android.AndroidBuild.createAppModule(AndroidBuild.java:481)
at processing.mode.android.AndroidBuild.createProject(AndroidBuild.java:262)
at processing.mode.android.AndroidBuild.build(AndroidBuild.java:223)
at processing.mode.android.AndroidMode.handleRunDevice(AndroidMode.java:294)
at processing.mode.android.AndroidEditor$17.run(AndroidEditor.java:421)
This is the source code for class JSyn:
package com.jsyn;
import com.jsyn.devices.AudioDeviceManager;
import com.jsyn.engine.SynthesisEngine;
import java.sql.Date;
import java.util.GregorianCalendar;
public class JSyn {
private static final int VERSION_MAJOR = 17;
private static final int VERSION_MINOR = 1;
private static final int VERSION_REVISION = 0;
public static final int BUILD_NUMBER = 465;
private static final long BUILD_TIME = (new GregorianCalendar(2023, 3, 10)).getTime().getTime();
public static final String VERSION = "17.1.0";
public static final int VERSION_CODE = 1114368;
public static final String VERSION_TEXT;
public static Synthesizer createSynthesizer() {
return new SynthesisEngine();
}
public static Synthesizer createSynthesizer(AudioDeviceManager audioDeviceManager) {
return new SynthesisEngine(audioDeviceManager);
}
static {
VERSION_TEXT = "V17.1.0 (build 465, " + new Date(BUILD_TIME) + ")";
}
}
The first thing it does is import com.jsyn.devices.AudioDeviceManager; which is likely where the real problem lies.
This is the source code for class JSynAndroidAudioDeviceManager:
package processing.sound;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.AudioTrack;
import com.jsyn.devices.AudioDeviceInputStream;
import com.jsyn.devices.AudioDeviceManager;
import com.jsyn.devices.AudioDeviceOutputStream;
class JSynAndroidAudioDeviceManager implements AudioDeviceManager {
private static String[] ANDROIDDEVICENAMES = new String[]{"default", "mic", "voice uplink", "voice downlink", "voice call", "camcorder", "voice recognition", "voice communication", "remote submix", "unprocessed", "voice performance"};
private double suggestedOutputLatency = 0.1;
private double suggestedInputLatency = 0.1;
public String getName() {
return "JSyn Android Audio for Processing Sound";
}
public AudioDeviceOutputStream createOutputStream(int var1, int var2, int var3) {
return new AndroidAudioOutputStream(var1, var2, var3);
}
public AudioDeviceInputStream createInputStream(int var1, int var2, int var3) {
return new AndroidAudioInputStream(var1, var2, var3);
}
public double getDefaultHighInputLatency(int var1) {
return 0.3;
}
public double getDefaultHighOutputLatency(int var1) {
return 0.3;
}
public int getDefaultInputDeviceID() {
return 0;
}
public int getDefaultOutputDeviceID() {
return 0;
}
public double getDefaultLowInputLatency(int var1) {
return 0.1;
}
public double getDefaultLowOutputLatency(int var1) {
return 0.1;
}
public int getDeviceCount() {
return ANDROIDDEVICENAMES.length;
}
public String getDeviceName(int var1) {
return "Android " + ANDROIDDEVICENAMES[var1] + " input";
}
public int getMaxInputChannels(int var1) {
return 1;
}
public int getMaxOutputChannels(int var1) {
return 2;
}
public int setSuggestedOutputLatency(double var1) {
this.suggestedOutputLatency = var1;
return 0;
}
public int setSuggestedInputLatency(double var1) {
this.suggestedInputLatency = var1;
return 0;
}
private class AndroidAudioInputStream extends AndroidAudioStream implements AudioDeviceInputStream {
private AudioRecord audioRecord;
public AndroidAudioInputStream(int var2, int var3, int var4) {
super(var2, var3, var4);
}
public void start() {
this.minBufferSize = AudioRecord.getMinBufferSize(this.frameRate, 12, 2);
this.bufferSize = 3 * (this.minBufferSize / 2) & -4;
try {
this.audioRecord = (new AudioRecord.Builder()).setAudioSource(this.deviceID).setAudioFormat((new AudioFormat.Builder()).setChannelMask(16).setEncoding(2).setSampleRate(this.frameRate).build()).setBufferSizeInBytes(this.bufferSize).build();
this.audioRecord.startRecording();
} catch (UnsupportedOperationException var2) {
}
}
public double read() {
double[] var1 = new double[1];
this.read(var1, 0, 1);
return var1[0];
}
public int read(double[] var1) {
return this.read(var1, 0, var1.length);
}
public int read(double[] var1, int var2, int var3) {
if (this.audioRecord == null) {
return 0;
} else {
if (this.shortBuffer == null || this.shortBuffer.length < var3) {
this.shortBuffer = new short[var3];
}
int var4 = this.audioRecord.read(this.shortBuffer, 0, var3, 1);
if (var4 < 0) {
switch (var4) {
case -6:
throw new RuntimeException("AudioRecord ERROR_DEAD_OBJECT: Object must be recreated");
case -5:
case -4:
default:
break;
case -3:
throw new RuntimeException("AudioRecord ERROR_INVALID_OPERATION: Device not properly initialized");
case -2:
throw new RuntimeException("AudioRecord ERROR_BAD_VALUE: Paramters don't resolve to valid data and indices");
case -1:
throw new RuntimeException("AudioRecord ERROR: Unknown error");
}
}
for(int var5 = 0; var5 < var4; ++var5) {
var1[var5 + var2] = (double)this.shortBuffer[var5] / (double)32767.0F;
}
return var4;
}
}
public void stop() {
if (this.audioRecord != null) {
this.audioRecord.stop();
this.audioRecord.release();
}
}
public int available() {
return this.bufferSize;
}
public void close() {
}
}
private class AndroidAudioOutputStream extends AndroidAudioStream implements AudioDeviceOutputStream {
AudioTrack audioTrack;
public AndroidAudioOutputStream(int var2, int var3, int var4) {
super(var2, var3, var4);
}
public void start() {
this.minBufferSize = AudioTrack.getMinBufferSize(this.frameRate, 12, 2);
this.bufferSize = 3 * (this.minBufferSize / 2) & -4;
this.audioTrack = (new AudioTrack.Builder()).setAudioAttributes((new AudioAttributes.Builder()).setUsage(1).setContentType(2).build()).setAudioFormat((new AudioFormat.Builder()).setChannelMask(12).setEncoding(2).setSampleRate(this.frameRate).build()).setBufferSizeInBytes(this.bufferSize).setTransferMode(1).build();
this.audioTrack.play();
}
public void write(double var1) {
double[] var3 = new double[]{var1};
this.write(var3, 0, 1);
}
public void write(double[] var1) {
this.write(var1, 0, var1.length);
}
public void write(double[] var1, int var2, int var3) {
if (this.shortBuffer == null || this.shortBuffer.length < var3) {
this.shortBuffer = new short[var3];
}
for(int var4 = 0; var4 < var3; ++var4) {
int var5 = (int)((double)32767.0F * var1[var4 + var2]);
if (var5 > 32767) {
var5 = 32767;
} else if (var5 < -32768) {
var5 = -32768;
}
this.shortBuffer[var4] = (short)var5;
}
this.audioTrack.write(this.shortBuffer, 0, var3);
}
public void stop() {
if (this.audioTrack != null) {
this.audioTrack.stop();
this.audioTrack.release();
}
}
public void close() {
}
}
private class AndroidAudioStream {
protected short[] shortBuffer;
protected int frameRate;
protected int samplesPerFrame;
protected int minBufferSize;
protected int bufferSize;
protected int deviceID;
public AndroidAudioStream(int var2, int var3, int var4) {
this.deviceID = var2;
this.frameRate = var3;
this.samplesPerFrame = var4;
}
public double getLatency() {
int var1 = this.bufferSize / this.samplesPerFrame;
return (double)var1 / (double)this.frameRate;
}
}
}
I’m not sure which ‘list’ is causing the problem.







