kopia lustrzana https://github.com/jameshball/osci-render
Update xt-audio to 1.9, remove xt-audio jar and update pom.xml
rodzic
934e14c7ac
commit
d40f359a01
|
@ -1,8 +1,9 @@
|
||||||
/target
|
/target
|
||||||
/.idea
|
/.idea
|
||||||
|
|
||||||
# Ignore all models (excluding cube and machine)
|
# Ignore all models and files, (excluding defaults)
|
||||||
/src/main/resources/models/*
|
/src/main/resources/models/*
|
||||||
|
/src/main/resources/images/*
|
||||||
|
|
||||||
# ignore temporary files
|
# ignore temporary files
|
||||||
*~
|
*~
|
||||||
|
|
|
@ -48,9 +48,7 @@ There are some additional controls for `.obj` files:
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
All dependencies are specified in the `pom.xml` file. Cloning this repo and using IntelliJ should make building a painless process.
|
All dependencies are specified in the `pom.xml` file. Cloning this repo and using IntelliJ with Maven should make building a painless process.
|
||||||
|
|
||||||
[`xtaudio`](https://sjoerdvankreel.github.io/xt-audio/) is the only library that is not on Maven central, and so it is provided in the `lib` folder and a system dependency is given in `pom.xml`.
|
|
||||||
|
|
||||||
## Contact
|
## Contact
|
||||||
|
|
||||||
|
|
Plik binarny nie jest wyświetlany.
10
pom.xml
10
pom.xml
|
@ -37,13 +37,11 @@
|
||||||
</repositories>
|
</repositories>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
<!-- XT-Audio required. This is not on maven central. https://sjoerdvankreel.github.io/xt-audio/ -->
|
<!-- https://sjoerdvankreel.github.io/xt-audio/ -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.xtaudio.xt</groupId>
|
<groupId>com.github.sjoerdvankreel</groupId>
|
||||||
<artifactId>xtaudio</artifactId>
|
<artifactId>xt.audio</artifactId>
|
||||||
<version>1.0.6</version>
|
<version>1.9</version>
|
||||||
<scope>system</scope>
|
|
||||||
<systemPath>${basedir}/lib/com.xt-audio.xt-1.0.6.jar</systemPath>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -2,7 +2,7 @@ module sh.ball {
|
||||||
requires javafx.controls;
|
requires javafx.controls;
|
||||||
requires javafx.graphics;
|
requires javafx.graphics;
|
||||||
requires javafx.fxml;
|
requires javafx.fxml;
|
||||||
requires com.xtaudio.xt;
|
requires xt.audio;
|
||||||
requires java.xml;
|
requires java.xml;
|
||||||
requires org.jsoup;
|
requires org.jsoup;
|
||||||
requires java.data.front;
|
requires java.data.front;
|
||||||
|
|
|
@ -1,16 +1,25 @@
|
||||||
package sh.ball.audio;
|
package sh.ball.audio;
|
||||||
|
|
||||||
import com.xtaudio.xt.XtAudio;
|
import xt.audio.Enums.XtSample;
|
||||||
import com.xtaudio.xt.XtBuffer;
|
import xt.audio.Enums.XtSetup;
|
||||||
import com.xtaudio.xt.XtDevice;
|
import xt.audio.Enums.XtSystem;
|
||||||
import com.xtaudio.xt.XtFormat;
|
import xt.audio.Structs.XtBuffer;
|
||||||
import com.xtaudio.xt.XtMix;
|
import xt.audio.Structs.XtBufferSize;
|
||||||
import com.xtaudio.xt.XtSample;
|
import xt.audio.Structs.XtChannels;
|
||||||
import com.xtaudio.xt.XtService;
|
import xt.audio.Structs.XtDeviceStreamParams;
|
||||||
import com.xtaudio.xt.XtSetup;
|
import xt.audio.Structs.XtFormat;
|
||||||
import com.xtaudio.xt.XtStream;
|
import xt.audio.Structs.XtMix;
|
||||||
|
import xt.audio.Structs.XtStreamParams;
|
||||||
|
import xt.audio.XtAudio;
|
||||||
|
import xt.audio.XtDevice;
|
||||||
|
import xt.audio.XtPlatform;
|
||||||
|
import xt.audio.XtSafeBuffer;
|
||||||
|
import xt.audio.XtService;
|
||||||
|
import xt.audio.XtStream;
|
||||||
|
|
||||||
import java.util.concurrent.ArrayBlockingQueue;
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
|
||||||
import sh.ball.shapes.Shape;
|
import sh.ball.shapes.Shape;
|
||||||
import sh.ball.shapes.Vector2;
|
import sh.ball.shapes.Vector2;
|
||||||
|
|
||||||
|
@ -18,7 +27,11 @@ import java.util.List;
|
||||||
|
|
||||||
public class AudioPlayer implements Runnable {
|
public class AudioPlayer implements Runnable {
|
||||||
|
|
||||||
private final XtFormat FORMAT;
|
private static final int SAMPLE_RATE = 192000;
|
||||||
|
|
||||||
|
private final XtMix MIX = new XtMix(SAMPLE_RATE, XtSample.FLOAT32);
|
||||||
|
private final XtChannels CHANNELS = new XtChannels(0, 0, 2, 0);
|
||||||
|
private final XtFormat FORMAT = new XtFormat(MIX, CHANNELS);
|
||||||
private final BlockingQueue<List<Shape>> frameQueue;
|
private final BlockingQueue<List<Shape>> frameQueue;
|
||||||
|
|
||||||
private List<Shape> frame;
|
private List<Shape> frame;
|
||||||
|
@ -35,14 +48,13 @@ public class AudioPlayer implements Runnable {
|
||||||
|
|
||||||
private volatile boolean stopped;
|
private volatile boolean stopped;
|
||||||
|
|
||||||
public AudioPlayer(int sampleRate, BlockingQueue<List<Shape>> frameQueue) {
|
public AudioPlayer(BlockingQueue<List<Shape>> frameQueue) {
|
||||||
this.FORMAT = new XtFormat(new XtMix(sampleRate, XtSample.FLOAT32), 0, 0, 2, 0);
|
|
||||||
this.frameQueue = frameQueue;
|
this.frameQueue = frameQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AudioPlayer(int sampleRate, ArrayBlockingQueue<List<Shape>> frameQueue, double rotateSpeed,
|
public AudioPlayer(ArrayBlockingQueue<List<Shape>> frameQueue, double rotateSpeed,
|
||||||
double translateSpeed, Vector2 translateVector, double scale, double weight) {
|
double translateSpeed, Vector2 translateVector, double scale, double weight) {
|
||||||
this(sampleRate, frameQueue);
|
this(frameQueue);
|
||||||
setRotateSpeed(rotateSpeed);
|
setRotateSpeed(rotateSpeed);
|
||||||
setTranslationSpeed(translateSpeed);
|
setTranslationSpeed(translateSpeed);
|
||||||
setTranslation(translateVector);
|
setTranslation(translateVector);
|
||||||
|
@ -50,10 +62,12 @@ public class AudioPlayer implements Runnable {
|
||||||
setWeight(weight);
|
setWeight(weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void render(XtStream stream, Object input, Object output, int audioFrames,
|
private int render(XtStream stream, XtBuffer buffer, Object user) throws InterruptedException {
|
||||||
double time, long position, boolean timeValid, long error, Object user)
|
XtSafeBuffer safe = XtSafeBuffer.get(stream);
|
||||||
throws InterruptedException {
|
safe.lock(buffer);
|
||||||
for (int f = 0; f < audioFrames; f++) {
|
float[] output = (float[]) safe.getOutput();
|
||||||
|
|
||||||
|
for (int f = 0; f < buffer.frames; f++) {
|
||||||
Shape shape = getCurrentShape();
|
Shape shape = getCurrentShape();
|
||||||
|
|
||||||
shape = shape.setWeight(weight);
|
shape = shape.setWeight(weight);
|
||||||
|
@ -65,8 +79,8 @@ public class AudioPlayer implements Runnable {
|
||||||
double drawingProgress = totalAudioFrames == 0 ? 1 : audioFramesDrawn / totalAudioFrames;
|
double drawingProgress = totalAudioFrames == 0 ? 1 : audioFramesDrawn / totalAudioFrames;
|
||||||
Vector2 nextVector = shape.nextVector(drawingProgress);
|
Vector2 nextVector = shape.nextVector(drawingProgress);
|
||||||
|
|
||||||
((float[]) output)[f * FORMAT.outputs] = (float) nextVector.getX();
|
output[f * FORMAT.channels.outputs] = (float) nextVector.getX();
|
||||||
((float[]) output)[f * FORMAT.outputs + 1] = (float) nextVector.getY();
|
output[f * FORMAT.channels.outputs + 1] = (float) nextVector.getY();
|
||||||
|
|
||||||
audioFramesDrawn++;
|
audioFramesDrawn++;
|
||||||
|
|
||||||
|
@ -80,12 +94,14 @@ public class AudioPlayer implements Runnable {
|
||||||
frame = frameQueue.take();
|
frame = frameQueue.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
safe.unlock(buffer);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Shape rotate(Shape shape, double sampleRate) {
|
private Shape rotate(Shape shape, double sampleRate) {
|
||||||
if (rotateSpeed != 0) {
|
if (rotateSpeed != 0) {
|
||||||
shape = shape.rotate(
|
shape = shape.rotate(
|
||||||
nextTheta(sampleRate, rotateSpeed, translatePhase)
|
nextTheta(sampleRate, rotateSpeed, translatePhase)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +111,7 @@ public class AudioPlayer implements Runnable {
|
||||||
private Shape translate(Shape shape, double sampleRate) {
|
private Shape translate(Shape shape, double sampleRate) {
|
||||||
if (translateSpeed != 0 && !translateVector.equals(new Vector2())) {
|
if (translateSpeed != 0 && !translateVector.equals(new Vector2())) {
|
||||||
return shape.translate(translateVector.scale(
|
return shape.translate(translateVector.scale(
|
||||||
Math.sin(nextTheta(sampleRate, translateSpeed, rotatePhase))
|
Math.sin(nextTheta(sampleRate, translateSpeed, rotatePhase))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,14 +168,22 @@ public class AudioPlayer implements Runnable {
|
||||||
throw new RuntimeException("Initial frame not found. Cannot continue.");
|
throw new RuntimeException("Initial frame not found. Cannot continue.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try (XtAudio audio = new XtAudio(null, null, null, null)) {
|
try (XtPlatform platform = XtAudio.init(null, null)) {
|
||||||
XtService service = XtAudio.getServiceBySetup(XtSetup.CONSUMER_AUDIO);
|
XtSystem system = platform.setupToSystem(XtSetup.CONSUMER_AUDIO);
|
||||||
try (XtDevice device = service.openDefaultDevice(true)) {
|
XtService service = platform.getService(system);
|
||||||
if (device != null && device.supportsFormat(FORMAT)) {
|
if (service == null) return;
|
||||||
XtBuffer buffer = device.getBuffer(FORMAT);
|
|
||||||
|
|
||||||
try (XtStream stream = device.openStream(FORMAT, true, false,
|
String defaultOutput = service.getDefaultDeviceId(true);
|
||||||
buffer.current, this::render, null, null)) {
|
if (defaultOutput == null) return;
|
||||||
|
|
||||||
|
try (XtDevice device = service.openDevice(defaultOutput)) {
|
||||||
|
if (device.supportsFormat(FORMAT)) {
|
||||||
|
|
||||||
|
XtBufferSize size = device.getBufferSize(FORMAT);
|
||||||
|
XtStreamParams streamParams = new XtStreamParams(true, this::render, null, null);
|
||||||
|
XtDeviceStreamParams deviceParams = new XtDeviceStreamParams(streamParams, FORMAT, size.current);
|
||||||
|
try (XtStream stream = device.openStream(deviceParams, null);
|
||||||
|
XtSafeBuffer safe = XtSafeBuffer.register(stream, true)) {
|
||||||
stream.start();
|
stream.start();
|
||||||
while (!stopped) {
|
while (!stopped) {
|
||||||
Thread.onSpinWait();
|
Thread.onSpinWait();
|
||||||
|
|
|
@ -30,12 +30,11 @@ import sh.ball.shapes.Vector2;
|
||||||
public class Controller implements Initializable {
|
public class Controller implements Initializable {
|
||||||
|
|
||||||
private static final int BUFFER_SIZE = 20;
|
private static final int BUFFER_SIZE = 20;
|
||||||
private static final int SAMPLE_RATE = 192000;
|
|
||||||
private static final String DEFAULT_FILE = "src/main/resources/models/cube.obj";
|
private static final String DEFAULT_FILE = "src/main/resources/models/cube.obj";
|
||||||
|
|
||||||
private final FileChooser fileChooser = new FileChooser();
|
private final FileChooser fileChooser = new FileChooser();
|
||||||
private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
|
private final BlockingQueue<List<Shape>> frameQueue = new ArrayBlockingQueue<>(BUFFER_SIZE);
|
||||||
private final AudioPlayer player = new AudioPlayer(SAMPLE_RATE, frameQueue);
|
private final AudioPlayer player = new AudioPlayer(frameQueue);
|
||||||
private final FrameProducer producer = new FrameProducer(frameQueue);
|
private final FrameProducer producer = new FrameProducer(frameQueue);
|
||||||
|
|
||||||
private Stage stage;
|
private Stage stage;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import sh.ball.parser.svg.SvgParser;
|
import sh.ball.parser.svg.SvgParser;
|
||||||
import sh.ball.shapes.Shape;
|
import sh.ball.shapes.Shape;
|
||||||
|
@ -18,7 +19,7 @@ public class TextParser extends FileParser {
|
||||||
|
|
||||||
private static final char WIDE_CHAR = 'W';
|
private static final char WIDE_CHAR = 'W';
|
||||||
private static final double HEIGHT_SCALAR = 1.6;
|
private static final double HEIGHT_SCALAR = 1.6;
|
||||||
private static final String DEFAULT_FONT = "fonts/SourceCodePro-ExtraLight.svg";
|
private static final String DEFAULT_FONT = TextParser.class.getResource("/fonts/SourceCodePro-ExtraLight.svg").getPath();
|
||||||
|
|
||||||
private final Map<Character, List<Shape>> charToShape;
|
private final Map<Character, List<Shape>> charToShape;
|
||||||
private final List<String> text;
|
private final List<String> text;
|
||||||
|
@ -27,7 +28,7 @@ public class TextParser extends FileParser {
|
||||||
private List<Shape> shapes;
|
private List<Shape> shapes;
|
||||||
|
|
||||||
public TextParser(String path, String font)
|
public TextParser(String path, String font)
|
||||||
throws IOException, SAXException, ParserConfigurationException {
|
throws IOException, SAXException, ParserConfigurationException {
|
||||||
checkFileExtension(path);
|
checkFileExtension(path);
|
||||||
this.filePath = path;
|
this.filePath = path;
|
||||||
this.charToShape = new HashMap<>();
|
this.charToShape = new HashMap<>();
|
||||||
|
@ -37,7 +38,7 @@ public class TextParser extends FileParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextParser(String path)
|
public TextParser(String path)
|
||||||
throws IOException, SAXException, ParserConfigurationException {
|
throws IOException, SAXException, ParserConfigurationException {
|
||||||
this(path, DEFAULT_FONT);
|
this(path, DEFAULT_FONT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ public class TextParser extends FileParser {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void parseFile(String path)
|
protected void parseFile(String path)
|
||||||
throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException {
|
throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException {
|
||||||
SvgParser parser = new SvgParser(path);
|
SvgParser parser = new SvgParser(path);
|
||||||
|
|
||||||
/* WIDE_CHAR used as an example character that will be wide in most languages.
|
/* WIDE_CHAR used as an example character that will be wide in most languages.
|
||||||
|
@ -71,8 +72,8 @@ public class TextParser extends FileParser {
|
||||||
char[] lineChars = text.get(i).toCharArray();
|
char[] lineChars = text.get(i).toCharArray();
|
||||||
for (int j = 0; j < lineChars.length; j++) {
|
for (int j = 0; j < lineChars.length; j++) {
|
||||||
shapes.addAll(Shape.translate(
|
shapes.addAll(Shape.translate(
|
||||||
charToShape.get(lineChars[j]),
|
charToShape.get(lineChars[j]),
|
||||||
new Vector2(j * width, -i * height)
|
new Vector2(j * width, -i * height)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue