Improve stability with js oscilloscope

pull/60/head
James Ball 2022-05-09 21:18:42 +01:00
rodzic 7a778112ee
commit ade45fa9e6
5 zmienionych plików z 100 dodań i 90 usunięć

10
pom.xml
Wyświetl plik

@ -181,6 +181,16 @@
<artifactId>Java-WebSocket</artifactId>
<version>1.5.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
</dependencies>
<profiles>
<profile>

Wyświetl plik

@ -90,6 +90,7 @@ public class Gui extends Application {
stage.show();
stage.setOnCloseRequest(t -> {
controller.shutdown();
Platform.exit();
System.exit(0);
});

Wyświetl plik

@ -51,7 +51,7 @@ import sh.ball.audio.midi.MidiNote;
import sh.ball.engine.ObjectServer;
import sh.ball.engine.ObjectSet;
import sh.ball.gui.Gui;
import sh.ball.oscilloscope.OscilloscopeServer;
import sh.ball.oscilloscope.ByteWebSocketServer;
import sh.ball.parser.obj.ObjFrameSettings;
import sh.ball.parser.obj.ObjParser;
import sh.ball.parser.ParserFactory;
@ -73,7 +73,7 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
private String openProjectPath;
private final FileChooser wavFileChooser = new FileChooser();
private ObjectServer server;
private ObjectServer objectServer;
// audio
private int sampleRate;
@ -106,6 +106,13 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
private final FileChooser osciFileChooser = new FileChooser();
private Stage stage;
// software oscilloscope
private static final int SOSCI_NUM_VERTICES = 4096;
private static final int SOSCI_VERTEX_SIZE = 2;
private static final int FRAME_SIZE = 2;
private byte[] buffer;
private ByteWebSocketServer webSocketServer;
@FXML
private EffectsController effectsController;
@FXML
@ -206,6 +213,10 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
channelClosestToZero.put(slider, closestToZero);
}
public void shutdown() {
webSocketServer.shutdown();
}
// alternates between recording and not recording when called.
// If it is a non-timed recording, it is saved when this is called and
// recording is stopped. If it is a time recording, this function will cancel
@ -457,15 +468,30 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
}
}
server = new ObjectServer(this::enableObjectServerRendering, this::disableObjectServerRendering);
new Thread(server).start();
new OscilloscopeServer<>(audioPlayer, 2).start();
objectServer = new ObjectServer(this::enableObjectServerRendering, this::disableObjectServerRendering);
new Thread(objectServer).start();
webSocketServer = new ByteWebSocketServer();
webSocketServer.start();
this.buffer = new byte[FRAME_SIZE * SOSCI_NUM_VERTICES * SOSCI_VERTEX_SIZE];
new Thread(() -> sendAudioDataToWebSocket(webSocketServer)).start();
}
private void sendAudioDataToWebSocket(ByteWebSocketServer server) {
while (true) {
try {
audioPlayer.read(buffer);
server.send(buffer);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void enableObjectServerRendering() {
Platform.runLater(() -> {
objectServerRendering = true;
ObjectSet set = server.getObjectSet();
ObjectSet set = objectServer.getObjectSet();
frameSources.forEach(FrameSource::disable);
set.enable();
@ -483,7 +509,7 @@ public class MainController implements Initializable, FrequencyListener, MidiLis
private void disableObjectServerRendering() {
Platform.runLater(() -> {
server.getObjectSet().disable();
objectServer.getObjectSet().disable();
objectServerRendering = false;
changeFrameSource(currentFrameSource);
});

Wyświetl plik

@ -0,0 +1,56 @@
package sh.ball.oscilloscope;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Set;
public class ByteWebSocketServer extends WebSocketServer {
private static final int TCP_PORT = 42988;
private final Set<WebSocket> conns;
public ByteWebSocketServer() {
super(new InetSocketAddress(TCP_PORT));
this.conns = new HashSet<>();
}
public synchronized void send(byte[] bytes) {
for (WebSocket sock : conns) {
sock.send(bytes);
}
}
@Override
public synchronized void onOpen(WebSocket conn, ClientHandshake handshake) {
conns.add(conn);
}
@Override
public synchronized void onClose(WebSocket conn, int code, String reason, boolean remote) {
conns.remove(conn);
}
@Override
public synchronized void onMessage(WebSocket conn, String message) {}
@Override
public synchronized void onError(WebSocket conn, Exception ex) {
ex.printStackTrace();
if (conn != null) {
conns.remove(conn);
}
}
public synchronized void shutdown() {
conns.forEach(WebSocket::close);
conns.clear();
}
@Override
public void onStart() {}
}

Wyświetl plik

@ -1,83 +0,0 @@
package sh.ball.oscilloscope;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import sh.ball.audio.AudioPlayer;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import java.util.HashSet;
import java.util.Set;
public class OscilloscopeServer<S> extends WebSocketServer {
private static final int TCP_PORT = 4444;
private static final int NUM_VERTICES = 2048;
private static final int VERTEX_SIZE = 2;
private final Set<WebSocket> conns;
private final AudioPlayer<S> audioPlayer;
private final int frameSize;
private final byte[] buffer;
public OscilloscopeServer(AudioPlayer<S> audioPlayer, int frameSize) {
super(new InetSocketAddress(TCP_PORT));
this.conns = new HashSet<>();
this.audioPlayer = audioPlayer;
this.frameSize = frameSize;
this.buffer = new byte[frameSize * NUM_VERTICES * VERTEX_SIZE];
}
public void send(byte[] bytes) {
for (WebSocket sock : conns) {
sock.send(bytes);
}
}
@Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
conns.add(conn);
System.out.println("New connection from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
conns.remove(conn);
System.out.println("Closed connection to " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
@Override
public void onMessage(WebSocket conn, String message) {
System.out.println("Message from client: " + message);
for (WebSocket sock : conns) {
sock.send(message);
}
}
@Override
public void onError(WebSocket conn, Exception ex) {
//ex.printStackTrace();
if (conn != null) {
conns.remove(conn);
// do some thing if required
}
System.out.println("ERROR from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
@Override
public void onStart() {
new Thread(() -> {
while (true) {
try {
audioPlayer.read(buffer);
send(buffer);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}