From d40f359a01fea211a4ee5885c630d80a6d0b66df Mon Sep 17 00:00:00 2001 From: James Ball Date: Fri, 9 Apr 2021 21:43:21 +0100 Subject: [PATCH] Update xt-audio to 1.9, remove xt-audio jar and update pom.xml --- .gitignore | 3 +- README.md | 4 +- lib/com.xt-audio.xt-1.0.6.jar | Bin 31120 -> 0 bytes pom.xml | 10 +-- src/main/java/module-info.java | 2 +- src/main/java/sh/ball/audio/AudioPlayer.java | 84 ++++++++++++------- src/main/java/sh/ball/gui/Controller.java | 3 +- src/main/java/sh/ball/parser/TextParser.java | 13 +-- 8 files changed, 70 insertions(+), 49 deletions(-) delete mode 100644 lib/com.xt-audio.xt-1.0.6.jar diff --git a/.gitignore b/.gitignore index 03c05402..7b107cce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ /target /.idea -# Ignore all models (excluding cube and machine) +# Ignore all models and files, (excluding defaults) /src/main/resources/models/* +/src/main/resources/images/* # ignore temporary files *~ diff --git a/README.md b/README.md index 0d9fa6f2..e95055ce 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,7 @@ There are some additional controls for `.obj` files: ## Building -All dependencies are specified in the `pom.xml` file. Cloning this repo and using IntelliJ 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`. +All dependencies are specified in the `pom.xml` file. Cloning this repo and using IntelliJ with Maven should make building a painless process. ## Contact diff --git a/lib/com.xt-audio.xt-1.0.6.jar b/lib/com.xt-audio.xt-1.0.6.jar deleted file mode 100644 index 47b70d9314ca705181aa36986f22ef5847180fce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31120 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 diff --git a/pom.xml b/pom.xml index 975b527f..eaca776a 100644 --- a/pom.xml +++ b/pom.xml @@ -37,13 +37,11 @@ - + - com.xtaudio.xt - xtaudio - 1.0.6 - system - ${basedir}/lib/com.xt-audio.xt-1.0.6.jar + com.github.sjoerdvankreel + xt.audio + 1.9 diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 118be082..e6383266 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -2,7 +2,7 @@ module sh.ball { requires javafx.controls; requires javafx.graphics; requires javafx.fxml; - requires com.xtaudio.xt; + requires xt.audio; requires java.xml; requires org.jsoup; requires java.data.front; diff --git a/src/main/java/sh/ball/audio/AudioPlayer.java b/src/main/java/sh/ball/audio/AudioPlayer.java index cebdf220..591acf4a 100644 --- a/src/main/java/sh/ball/audio/AudioPlayer.java +++ b/src/main/java/sh/ball/audio/AudioPlayer.java @@ -1,16 +1,25 @@ package sh.ball.audio; -import com.xtaudio.xt.XtAudio; -import com.xtaudio.xt.XtBuffer; -import com.xtaudio.xt.XtDevice; -import com.xtaudio.xt.XtFormat; -import com.xtaudio.xt.XtMix; -import com.xtaudio.xt.XtSample; -import com.xtaudio.xt.XtService; -import com.xtaudio.xt.XtSetup; -import com.xtaudio.xt.XtStream; +import xt.audio.Enums.XtSample; +import xt.audio.Enums.XtSetup; +import xt.audio.Enums.XtSystem; +import xt.audio.Structs.XtBuffer; +import xt.audio.Structs.XtBufferSize; +import xt.audio.Structs.XtChannels; +import xt.audio.Structs.XtDeviceStreamParams; +import xt.audio.Structs.XtFormat; +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.BlockingQueue; + import sh.ball.shapes.Shape; import sh.ball.shapes.Vector2; @@ -18,7 +27,11 @@ import java.util.List; 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> frameQueue; private List frame; @@ -35,14 +48,13 @@ public class AudioPlayer implements Runnable { private volatile boolean stopped; - public AudioPlayer(int sampleRate, BlockingQueue> frameQueue) { - this.FORMAT = new XtFormat(new XtMix(sampleRate, XtSample.FLOAT32), 0, 0, 2, 0); + public AudioPlayer(BlockingQueue> frameQueue) { this.frameQueue = frameQueue; } - public AudioPlayer(int sampleRate, ArrayBlockingQueue> frameQueue, double rotateSpeed, - double translateSpeed, Vector2 translateVector, double scale, double weight) { - this(sampleRate, frameQueue); + public AudioPlayer(ArrayBlockingQueue> frameQueue, double rotateSpeed, + double translateSpeed, Vector2 translateVector, double scale, double weight) { + this(frameQueue); setRotateSpeed(rotateSpeed); setTranslationSpeed(translateSpeed); setTranslation(translateVector); @@ -50,10 +62,12 @@ public class AudioPlayer implements Runnable { setWeight(weight); } - private void render(XtStream stream, Object input, Object output, int audioFrames, - double time, long position, boolean timeValid, long error, Object user) - throws InterruptedException { - for (int f = 0; f < audioFrames; f++) { + private int render(XtStream stream, XtBuffer buffer, Object user) throws InterruptedException { + XtSafeBuffer safe = XtSafeBuffer.get(stream); + safe.lock(buffer); + float[] output = (float[]) safe.getOutput(); + + for (int f = 0; f < buffer.frames; f++) { Shape shape = getCurrentShape(); shape = shape.setWeight(weight); @@ -65,8 +79,8 @@ public class AudioPlayer implements Runnable { double drawingProgress = totalAudioFrames == 0 ? 1 : audioFramesDrawn / totalAudioFrames; Vector2 nextVector = shape.nextVector(drawingProgress); - ((float[]) output)[f * FORMAT.outputs] = (float) nextVector.getX(); - ((float[]) output)[f * FORMAT.outputs + 1] = (float) nextVector.getY(); + output[f * FORMAT.channels.outputs] = (float) nextVector.getX(); + output[f * FORMAT.channels.outputs + 1] = (float) nextVector.getY(); audioFramesDrawn++; @@ -80,12 +94,14 @@ public class AudioPlayer implements Runnable { frame = frameQueue.take(); } } + safe.unlock(buffer); + return 0; } private Shape rotate(Shape shape, double sampleRate) { if (rotateSpeed != 0) { 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) { if (translateSpeed != 0 && !translateVector.equals(new Vector2())) { 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."); } - try (XtAudio audio = new XtAudio(null, null, null, null)) { - XtService service = XtAudio.getServiceBySetup(XtSetup.CONSUMER_AUDIO); - try (XtDevice device = service.openDefaultDevice(true)) { - if (device != null && device.supportsFormat(FORMAT)) { - XtBuffer buffer = device.getBuffer(FORMAT); + try (XtPlatform platform = XtAudio.init(null, null)) { + XtSystem system = platform.setupToSystem(XtSetup.CONSUMER_AUDIO); + XtService service = platform.getService(system); + if (service == null) return; - try (XtStream stream = device.openStream(FORMAT, true, false, - buffer.current, this::render, null, null)) { + String defaultOutput = service.getDefaultDeviceId(true); + 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(); while (!stopped) { Thread.onSpinWait(); diff --git a/src/main/java/sh/ball/gui/Controller.java b/src/main/java/sh/ball/gui/Controller.java index 4d6520ef..e21fd571 100644 --- a/src/main/java/sh/ball/gui/Controller.java +++ b/src/main/java/sh/ball/gui/Controller.java @@ -30,12 +30,11 @@ import sh.ball.shapes.Vector2; public class Controller implements Initializable { 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 final FileChooser fileChooser = new FileChooser(); private final BlockingQueue> 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 Stage stage; diff --git a/src/main/java/sh/ball/parser/TextParser.java b/src/main/java/sh/ball/parser/TextParser.java index 5a402053..489c66b4 100644 --- a/src/main/java/sh/ball/parser/TextParser.java +++ b/src/main/java/sh/ball/parser/TextParser.java @@ -9,6 +9,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.parsers.ParserConfigurationException; + import org.xml.sax.SAXException; import sh.ball.parser.svg.SvgParser; import sh.ball.shapes.Shape; @@ -18,7 +19,7 @@ public class TextParser extends FileParser { private static final char WIDE_CHAR = 'W'; 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> charToShape; private final List text; @@ -27,7 +28,7 @@ public class TextParser extends FileParser { private List shapes; public TextParser(String path, String font) - throws IOException, SAXException, ParserConfigurationException { + throws IOException, SAXException, ParserConfigurationException { checkFileExtension(path); this.filePath = path; this.charToShape = new HashMap<>(); @@ -37,7 +38,7 @@ public class TextParser extends FileParser { } public TextParser(String path) - throws IOException, SAXException, ParserConfigurationException { + throws IOException, SAXException, ParserConfigurationException { this(path, DEFAULT_FONT); } @@ -48,7 +49,7 @@ public class TextParser extends FileParser { @Override protected void parseFile(String path) - throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException { + throws ParserConfigurationException, IOException, SAXException, IllegalArgumentException { SvgParser parser = new SvgParser(path); /* 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(); for (int j = 0; j < lineChars.length; j++) { shapes.addAll(Shape.translate( - charToShape.get(lineChars[j]), - new Vector2(j * width, -i * height) + charToShape.get(lineChars[j]), + new Vector2(j * width, -i * height) )); } }