diff --git a/PlayWallCore/src/de/tobias/playpad/audio/Peakable.java b/PlayWallCore/src/de/tobias/playpad/audio/Peakable.java new file mode 100644 index 0000000000000000000000000000000000000000..29f41ebc7f6ec0c0f2f756600773662934e7526d --- /dev/null +++ b/PlayWallCore/src/de/tobias/playpad/audio/Peakable.java @@ -0,0 +1,16 @@ +package de.tobias.playpad.audio; + +import javafx.beans.property.DoubleProperty; + +public interface Peakable { + + public enum Channel { + + LEFT, + RIGHT; + } + + public DoubleProperty audioLevelProperty(Channel channel); + + public double getAudioLevel(Channel channel); +} diff --git a/PlayWallNative/.classpath b/PlayWallNative/.classpath new file mode 100644 index 0000000000000000000000000000000000000000..7d03288488cf3143f0a6a22231d22bac9bde9d1b --- /dev/null +++ b/PlayWallNative/.classpath @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="test"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry combineaccessrules="false" kind="src" path="/PlayWallCore"/> + <classpathentry combineaccessrules="false" kind="src" path="/libUtils"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/PlayWallNative/.gitignore b/PlayWallNative/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ae3c1726048cd06b9a143e0376ed46dd9b9a8d53 --- /dev/null +++ b/PlayWallNative/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/PlayWallNative/.project b/PlayWallNative/.project new file mode 100644 index 0000000000000000000000000000000000000000..68507fdf0080728bcd1335ddb47c9170aeb3a493 --- /dev/null +++ b/PlayWallNative/.project @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>PlayWallNative</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/PlayWallNative/.settings/org.eclipse.jdt.core.prefs b/PlayWallNative/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000000000000000000000000000000000..3a21537071bf4118b9e1ee864cb4bc258aa48211 --- /dev/null +++ b/PlayWallNative/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/PlayWallNative/libNativeAudio.dylib b/PlayWallNative/libNativeAudio.dylib new file mode 100644 index 0000000000000000000000000000000000000000..14afa4716652379483939e006f1d32ba3adde6bb Binary files /dev/null and b/PlayWallNative/libNativeAudio.dylib differ diff --git a/PlayWallNative/src/de/tobias/playpad/NativeAudio.java b/PlayWallNative/src/de/tobias/playpad/NativeAudio.java new file mode 100644 index 0000000000000000000000000000000000000000..cee1d7277008783ef91cb119ce8b389791e4540e --- /dev/null +++ b/PlayWallNative/src/de/tobias/playpad/NativeAudio.java @@ -0,0 +1,58 @@ +package de.tobias.playpad; + +public class NativeAudio { + + public static native void initialize(); + + public static native void play(int id); + + public static native void pause(int id); + + public static native void stop(int id); + + public static native void setLoop(int id, boolean loop); + + public static native double getVolume(int id); + + public static native void setVolume(int id, double volume); + + public static native boolean load(int id, String path); + + public static native void dispose(int id); + + public static native double getDuration(int id); + + public static native double getPosition(int id); + + public static void onPeakMeter(int id, float left, float right) { + if (delegate != null) { + delegate.onPeakMeter(id, left, right); + } + } + + public static void onPositionChanged(int id, double position) { + if (delegate != null) { + delegate.onPositionChanged(id, position); + } + } + + public static void onFinish(int id) { + if (delegate != null) { + delegate.onFinish(id); + } + } + + private static NativeAudioDelegate delegate; + + public static void setDelegate(NativeAudioDelegate delegate) { + NativeAudio.delegate = delegate; + } + + public interface NativeAudioDelegate { + public void onFinish(int id); + + public void onPeakMeter(int id, float left, float right); + + public void onPositionChanged(int id, double position); + } +} diff --git a/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandler.java b/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..066831def36afb550506bafaa2629c9e6e8f39dd --- /dev/null +++ b/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandler.java @@ -0,0 +1,135 @@ +package de.tobias.playpad; + +import java.nio.file.Path; + +import de.tobias.playpad.audio.AudioHandler; +import de.tobias.playpad.audio.Peakable; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.utils.util.Worker; +import javafx.application.Platform; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.util.Duration; + +public class NativeAudioMacHandler extends AudioHandler implements Peakable { + + private static int counter = 0; + + private final int id; + ObjectProperty<Duration> positionProperty; + private ObjectProperty<Duration> durationProperty; + private boolean isLoaded; + + private DoubleProperty leftPeak; + private DoubleProperty rightPeak; + + public NativeAudioMacHandler(PadContent content) { + super(content); + + id = counter++; + positionProperty = new SimpleObjectProperty<>(); + durationProperty = new SimpleObjectProperty<>(); + + leftPeak = new SimpleDoubleProperty(); + rightPeak = new SimpleDoubleProperty(); + } + + protected int getId() { + return id; + } + + @Override + public void play() { + NativeAudio.setLoop(id, getContent().getPad().getPadSettings().isLoop()); + NativeAudio.play(id); + } + + @Override + public void pause() { + NativeAudio.pause(id); + } + + @Override + public void stop() { + NativeAudio.stop(id); + } + + @Override + public Duration getPosition() { + return positionProperty.get(); + } + + @Override + public ReadOnlyObjectProperty<Duration> positionProperty() { + return positionProperty; + } + + @Override + public Duration getDuration() { + return durationProperty.get(); + } + + @Override + public ReadOnlyObjectProperty<Duration> durationProperty() { + return durationProperty; + } + + @Override + public void setVolume(double volume) { + NativeAudio.setVolume(id, volume); + + } + + @Override + public boolean isMediaLoaded() { + return isLoaded; + } + + @Override + public void loadMedia(Path[] paths) { + Platform.runLater(() -> + { + if (getContent().getPad().isPadVisible()) { + getContent().getPad().getController().getView().showBusyView(true); + } + }); + Worker.runLater(() -> + { + isLoaded = NativeAudio.load(id, paths[0].toString()); + if (isLoaded) { + Platform.runLater(() -> + { + durationProperty.set(Duration.seconds(NativeAudio.getDuration(id))); + getContent().getPad().setStatus(PadStatus.READY); + if (getContent().getPad().isPadVisible()) { + getContent().getPad().getController().getView().showBusyView(false); + } + }); + } + }); + } + + @Override + public void unloadMedia() { + NativeAudio.dispose(id); + } + + @Override + public DoubleProperty audioLevelProperty(Channel channel) { + if (channel == Channel.LEFT) { + return leftPeak; + } else if (channel == Channel.RIGHT) { + return rightPeak; + } + return null; + } + + @Override + public double getAudioLevel(Channel channel) { + return audioLevelProperty(channel).get(); + } +} diff --git a/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandlerConnect.java b/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandlerConnect.java new file mode 100644 index 0000000000000000000000000000000000000000..66245637d4cd9adcaee4cab2710107f6fa924809 --- /dev/null +++ b/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandlerConnect.java @@ -0,0 +1,78 @@ +package de.tobias.playpad; + +import java.util.HashMap; + +import de.tobias.playpad.NativeAudio.NativeAudioDelegate; +import de.tobias.playpad.audio.AudioCapability; +import de.tobias.playpad.audio.AudioHandler; +import de.tobias.playpad.audio.AudioHandlerConnect; +import de.tobias.playpad.audio.Peakable.Channel; +import de.tobias.playpad.pad.PadStatus; +import de.tobias.playpad.pad.conntent.PadContent; +import de.tobias.playpad.viewcontroller.AudioHandlerViewController; +import javafx.util.Duration; + +public class NativeAudioMacHandlerConnect extends AudioHandlerConnect implements NativeAudioDelegate { + + private static final HashMap<Integer, NativeAudioMacHandler> handlers = new HashMap<>(); + + public NativeAudioMacHandlerConnect() { + NativeAudio.initialize(); + NativeAudio.setDelegate(this); + } + + @Override + public AudioHandler createAudioHandler(PadContent content) { + NativeAudioMacHandler nativeAudioMacHandler = new NativeAudioMacHandler(content); + handlers.put(nativeAudioMacHandler.getId(), nativeAudioMacHandler); + return nativeAudioMacHandler; + } + + @Override + public AudioHandlerViewController getAudioHandlerSettingsViewController() { + return null; + } + + @Override + public String getType() { + return "Native"; + } + + @Override + public void onFinish(int id) { + NativeAudioMacHandler nativeAudioMacHandler = handlers.get(id); + if (nativeAudioMacHandler != null) { + PadContent content = nativeAudioMacHandler.getContent(); + if (content != null) { + content.getPad().setStatus(PadStatus.STOP); + } + } + } + + @Override + public void onPositionChanged(int id, double position) { + NativeAudioMacHandler nativeAudioMacHandler = handlers.get(id); + if (nativeAudioMacHandler != null) { + nativeAudioMacHandler.positionProperty.set(Duration.seconds(position)); + } + } + + @Override + public void onPeakMeter(int id, float left, float right) { + NativeAudioMacHandler nativeAudioMacHandler = handlers.get(id); + if (nativeAudioMacHandler != null) { + nativeAudioMacHandler.audioLevelProperty(Channel.LEFT).set(left); + nativeAudioMacHandler.audioLevelProperty(Channel.RIGHT).set(right); + } + } + + @Override + public boolean isFeatureAvaiable(AudioCapability audioCapability) { + return false; + } + + @Override + public AudioHandlerViewController getAudioFeatureSettings(AudioCapability audioCapablility) { + return null; + } +} diff --git a/PlayWallNative/src/de/tobias/playpad/Waveform.java b/PlayWallNative/src/de/tobias/playpad/Waveform.java new file mode 100644 index 0000000000000000000000000000000000000000..f01873a01df7c0f3e1eb998941e3bd73b63519f6 --- /dev/null +++ b/PlayWallNative/src/de/tobias/playpad/Waveform.java @@ -0,0 +1,7 @@ +package de.tobias.playpad; + +public class Waveform { + + public static native float[] createWaveform(String path); + +} diff --git a/PlayWallNative/src/de/tobias/playpad/view/WaveformView.java b/PlayWallNative/src/de/tobias/playpad/view/WaveformView.java new file mode 100644 index 0000000000000000000000000000000000000000..25029d49df5806ebd6ac9bbeba23d7941aeb091c --- /dev/null +++ b/PlayWallNative/src/de/tobias/playpad/view/WaveformView.java @@ -0,0 +1,39 @@ +package de.tobias.playpad.view; + +import javafx.scene.paint.Color; +import javafx.scene.shape.LineTo; +import javafx.scene.shape.MoveTo; +import javafx.scene.shape.Path; + +public class WaveformView extends Path { + + public WaveformView(float[] data) { + getElements().add(new MoveTo(0, 0)); + + double width2 = data.length / 1200.0; + int width = data.length / 10000; + System.out.println(data.length); + System.out.println(width); + + int i = 0; + for (i = 0; i < data.length; i += width) { + if (i < data.length) { + LineTo lineTo = new LineTo(i / width2, data[i] * 50.0); + MoveTo moveTo = new MoveTo(i / width2, data[i] * 50.0); + + getElements().addAll(lineTo, moveTo); + } + } + for (; i >= 0; i -= width) { + if (i >= 0 && i < data.length) { + LineTo lineTo = new LineTo(i / width2, -data[i] * 50.0); + MoveTo moveTo = new MoveTo(i / width2, -data[i] * 50.0); + + getElements().addAll(lineTo, moveTo); + } + } + getElements().add(new LineTo(0, 0)); + getElements().add(new MoveTo(0, 0)); + setFill(Color.BLACK); + } +} diff --git a/PlayWallNative/src/de_tobias_playpad_NativeAudio.h b/PlayWallNative/src/de_tobias_playpad_NativeAudio.h new file mode 100644 index 0000000000000000000000000000000000000000..4bd710308b879f953bd90b3e96a9aa1ec1e2ef92 --- /dev/null +++ b/PlayWallNative/src/de_tobias_playpad_NativeAudio.h @@ -0,0 +1,85 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class de_tobias_playpad_NativeAudio */ + +#ifndef _Included_de_tobias_playpad_NativeAudio +#define _Included_de_tobias_playpad_NativeAudio +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: de_tobias_playpad_NativeAudio + * Method: play + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_de_tobias_playpad_NativeAudio_play + (JNIEnv *, jclass, jint); + +/* + * Class: de_tobias_playpad_NativeAudio + * Method: pause + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_de_tobias_playpad_NativeAudio_pause + (JNIEnv *, jclass, jint); + +/* + * Class: de_tobias_playpad_NativeAudio + * Method: stop + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_de_tobias_playpad_NativeAudio_stop + (JNIEnv *, jclass, jint); + +/* + * Class: de_tobias_playpad_NativeAudio + * Method: getVolume + * Signature: (I)D + */ +JNIEXPORT jdouble JNICALL Java_de_tobias_playpad_NativeAudio_getVolume + (JNIEnv *, jclass, jint); + +/* + * Class: de_tobias_playpad_NativeAudio + * Method: setVolume + * Signature: (ID)V + */ +JNIEXPORT void JNICALL Java_de_tobias_playpad_NativeAudio_setVolume + (JNIEnv *, jclass, jint, jdouble); + +/* + * Class: de_tobias_playpad_NativeAudio + * Method: load + * Signature: (ILjava/lang/String;)Z + */ +JNIEXPORT jboolean JNICALL Java_de_tobias_playpad_NativeAudio_load + (JNIEnv *, jclass, jint, jstring); + +/* + * Class: de_tobias_playpad_NativeAudio + * Method: dispose + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_de_tobias_playpad_NativeAudio_dispose + (JNIEnv *, jclass, jint); + +/* + * Class: de_tobias_playpad_NativeAudio + * Method: getDuration + * Signature: (I)D + */ +JNIEXPORT jdouble JNICALL Java_de_tobias_playpad_NativeAudio_getDuration + (JNIEnv *, jclass, jint); + +/* + * Class: de_tobias_playpad_NativeAudio + * Method: getPosition + * Signature: (I)D + */ +JNIEXPORT jdouble JNICALL Java_de_tobias_playpad_NativeAudio_getPosition + (JNIEnv *, jclass, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/PlayWallNative/src/de_tobias_playpad_Waveform.h b/PlayWallNative/src/de_tobias_playpad_Waveform.h new file mode 100644 index 0000000000000000000000000000000000000000..9d0e45dcb853ff654b6c6e50ca73a8d9fc6ac183 --- /dev/null +++ b/PlayWallNative/src/de_tobias_playpad_Waveform.h @@ -0,0 +1,29 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class de_tobias_playpad_Waveform */ + +#ifndef _Included_de_tobias_playpad_Waveform +#define _Included_de_tobias_playpad_Waveform +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: de_tobias_playpad_Waveform + * Method: initialize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_de_tobias_playpad_Waveform_initialize + (JNIEnv *, jclass); + +/* + * Class: de_tobias_playpad_Waveform + * Method: createWaveform + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_de_tobias_playpad_Waveform_createWaveform + (JNIEnv *, jclass, jstring); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/PlayWallNative/test/de/tobias/playpad/NativeAudioTest.java b/PlayWallNative/test/de/tobias/playpad/NativeAudioTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0fe58a6cf60fba757ed8d1a7938d11149af87b5c --- /dev/null +++ b/PlayWallNative/test/de/tobias/playpad/NativeAudioTest.java @@ -0,0 +1,20 @@ +package de.tobias.playpad; + +public class NativeAudioTest { + + public static void main(String[] args) { + System.load("/Users/tobias/Documents/Programmieren/Java/git/PlayWall/PlayWallNative/libNativeAudio.dylib"); + + NativeAudio.load(0, "/Users/tobias/Downloads/03%20Hymn%20For%20The%20Weekend.mp3.wav"); + System.out.println(NativeAudio.getDuration(0)); + NativeAudio.play(0); + + while (true) { + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/PlayWallNative/test/de/tobias/playpad/WaveformTest.java b/PlayWallNative/test/de/tobias/playpad/WaveformTest.java new file mode 100644 index 0000000000000000000000000000000000000000..704d8b6eb7971ccaf75343790d49ffb86f45199f --- /dev/null +++ b/PlayWallNative/test/de/tobias/playpad/WaveformTest.java @@ -0,0 +1,38 @@ +package de.tobias.playpad; + +import de.tobias.playpad.view.WaveformView; +import javafx.application.Application; +import javafx.scene.Scene; +import javafx.scene.image.ImageView; +import javafx.scene.image.WritableImage; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + +public class WaveformTest extends Application { + + public static void main(String[] args) { + System.load("/Users/tobias/Documents/Programmieren/Java/git/PlayWall/PlayWallNative/libNativeAudio.dylib"); + + launch(args); + } + + @Override + public void start(Stage primaryStage) throws Exception { + float[] data = Waveform.createWaveform("/Users/tobias/Music/iTunes/iTunes Media/Music/Coldplay/Mylo Xyloto/04 Charlie Brown.mp3"); + float[] data2 = Waveform.createWaveform("/Users/tobias/Downloads/TNT-Loop.wav"); + WaveformView view = new WaveformView(data); + WaveformView view2 = new WaveformView(data2); + + WritableImage image = new WritableImage(1200, 150); + view.snapshot(null, image); + WritableImage image2 = new WritableImage(1200, 150); + view2.snapshot(null, image2); + + VBox root = new VBox(new ImageView(image), new ImageView(image2)); + Scene scene = new Scene(root); + + primaryStage.setScene(scene); + primaryStage.show(); + } + +}