kopia lustrzana https://github.com/jameshball/osci-render
Remove requirement for a render lock by making listener queue thread-safe
rodzic
42c018c422
commit
7dda40130b
|
@ -4,8 +4,7 @@ import sh.ball.audio.effect.Effect;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.BlockingQueue;
|
|
||||||
|
|
||||||
import sh.ball.audio.engine.AudioDevice;
|
import sh.ball.audio.engine.AudioDevice;
|
||||||
import sh.ball.audio.engine.AudioEngine;
|
import sh.ball.audio.engine.AudioEngine;
|
||||||
|
@ -14,8 +13,7 @@ import sh.ball.shapes.Vector2;
|
||||||
|
|
||||||
import javax.sound.sampled.AudioFormat;
|
import javax.sound.sampled.AudioFormat;
|
||||||
import javax.sound.sampled.AudioInputStream;
|
import javax.sound.sampled.AudioInputStream;
|
||||||
import java.util.concurrent.Callable;
|
import javax.sound.sampled.LineUnavailableException;
|
||||||
import java.util.concurrent.Semaphore;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
||||||
|
@ -33,8 +31,7 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
||||||
private final Callable<AudioEngine> audioEngineBuilder;
|
private final Callable<AudioEngine> audioEngineBuilder;
|
||||||
private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
|
private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
|
||||||
private final Map<Object, Effect> effects = new HashMap<>();
|
private final Map<Object, Effect> effects = new HashMap<>();
|
||||||
private final ReentrantLock renderLock = new ReentrantLock();
|
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
|
||||||
private final List<Listener> listeners = new ArrayList<>();
|
|
||||||
|
|
||||||
private AudioEngine audioEngine;
|
private AudioEngine audioEngine;
|
||||||
private ByteArrayOutputStream outputStream;
|
private ByteArrayOutputStream outputStream;
|
||||||
|
@ -83,13 +80,13 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeChannels(float leftChannel, float rightChannel) {
|
private void writeChannels(float leftChannel, float rightChannel) {
|
||||||
int left = (int)(leftChannel * Short.MAX_VALUE);
|
int left = (int) (leftChannel * Short.MAX_VALUE);
|
||||||
int right = (int)(rightChannel * Short.MAX_VALUE);
|
int right = (int) (rightChannel * Short.MAX_VALUE);
|
||||||
|
|
||||||
byte b0 = (byte) left;
|
byte b0 = (byte) left;
|
||||||
byte b1 = (byte)(left >> 8);
|
byte b1 = (byte) (left >> 8);
|
||||||
byte b2 = (byte) right;
|
byte b2 = (byte) right;
|
||||||
byte b3 = (byte)(right >> 8);
|
byte b3 = (byte) (right >> 8);
|
||||||
|
|
||||||
if (recording) {
|
if (recording) {
|
||||||
outputStream.write(b0);
|
outputStream.write(b0);
|
||||||
|
@ -155,7 +152,11 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
||||||
throw new IllegalArgumentException("No AudioDevice provided");
|
throw new IllegalArgumentException("No AudioDevice provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
audioEngine.play(this::generateChannels, renderLock, device);
|
try {
|
||||||
|
audioEngine.play(this::generateChannels, device);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -200,19 +201,9 @@ public class ShapeAudioPlayer implements AudioPlayer<List<Shape>> {
|
||||||
@Override
|
@Override
|
||||||
public void read(byte[] buffer) throws InterruptedException {
|
public void read(byte[] buffer) throws InterruptedException {
|
||||||
Listener listener = new Listener(buffer);
|
Listener listener = new Listener(buffer);
|
||||||
try {
|
listeners.add(listener);
|
||||||
renderLock.lock();
|
|
||||||
listeners.add(listener);
|
|
||||||
} finally {
|
|
||||||
renderLock.unlock();
|
|
||||||
}
|
|
||||||
listener.waitUntilFull();
|
listener.waitUntilFull();
|
||||||
try {
|
listeners.remove(listener);
|
||||||
renderLock.lock();
|
|
||||||
listeners.remove(listener);
|
|
||||||
} finally {
|
|
||||||
renderLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,12 +4,11 @@ import sh.ball.shapes.Vector2;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
public interface AudioEngine {
|
public interface AudioEngine {
|
||||||
boolean isPlaying();
|
boolean isPlaying();
|
||||||
|
|
||||||
void play(Callable<Vector2> channelGenerator, ReentrantLock renderLock, AudioDevice device);
|
void play(Callable<Vector2> channelGenerator, AudioDevice device) throws Exception;
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
public class XtAudioEngine implements AudioEngine {
|
public class XtAudioEngine implements AudioEngine {
|
||||||
|
|
||||||
|
@ -19,7 +18,6 @@ public class XtAudioEngine implements AudioEngine {
|
||||||
|
|
||||||
private AudioDevice device;
|
private AudioDevice device;
|
||||||
private boolean playing = false;
|
private boolean playing = false;
|
||||||
private ReentrantLock renderLock;
|
|
||||||
private Callable<Vector2> channelGenerator;
|
private Callable<Vector2> channelGenerator;
|
||||||
|
|
||||||
public XtAudioEngine() {}
|
public XtAudioEngine() {}
|
||||||
|
@ -27,9 +25,6 @@ public class XtAudioEngine implements AudioEngine {
|
||||||
private int render(XtStream stream, Structs.XtBuffer buffer, Object user) throws Exception {
|
private int render(XtStream stream, Structs.XtBuffer buffer, Object user) throws Exception {
|
||||||
XtSafeBuffer safe = XtSafeBuffer.get(stream);
|
XtSafeBuffer safe = XtSafeBuffer.get(stream);
|
||||||
safe.lock(buffer);
|
safe.lock(buffer);
|
||||||
if (renderLock != null) {
|
|
||||||
renderLock.lock();
|
|
||||||
}
|
|
||||||
Object output = safe.getOutput();
|
Object output = safe.getOutput();
|
||||||
|
|
||||||
for (int f = 0; f < buffer.frames; f++) {
|
for (int f = 0; f < buffer.frames; f++) {
|
||||||
|
@ -37,9 +32,6 @@ public class XtAudioEngine implements AudioEngine {
|
||||||
writeChannels(channels, output, f);
|
writeChannels(channels, output, f);
|
||||||
}
|
}
|
||||||
safe.unlock(buffer);
|
safe.unlock(buffer);
|
||||||
if (renderLock != null) {
|
|
||||||
renderLock.unlock();
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,11 +89,10 @@ public class XtAudioEngine implements AudioEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void play(Callable<Vector2> channelGenerator, ReentrantLock renderLock, AudioDevice device) {
|
public void play(Callable<Vector2> channelGenerator, AudioDevice device) {
|
||||||
this.playing = true;
|
this.playing = true;
|
||||||
this.device = device;
|
this.device = device;
|
||||||
this.channelGenerator = channelGenerator;
|
this.channelGenerator = channelGenerator;
|
||||||
this.renderLock = renderLock;
|
|
||||||
try (XtPlatform platform = XtAudio.init(null, null)) {
|
try (XtPlatform platform = XtAudio.init(null, null)) {
|
||||||
XtService service = getService(platform);
|
XtService service = getService(platform);
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue