From 22cb116b4dc7a5f871ce7c36fe8f4b577c6da461 Mon Sep 17 00:00:00 2001
From: tobias <tobias.ullerich@icloud.com>
Date: Thu, 8 Sep 2016 10:10:52 +0200
Subject: [PATCH] Start adding peak meter

---
 .../playpad/action/cartaction/CartAction.java |  4 +-
 .../playpad/pad/content/AudioContent.java     |  4 +
 .../pad/content/AudioContentConnect.java      | 17 +++-
 .../src/de/tobias/playpad/audio/Peakable.java | 15 ++++
 .../de/tobias/playpad/pad/view/PeakMeter.java | 45 ++++++++++
 .../src/de/tobias/playpad/NativeAudio.java    | 16 ++++
 .../tobias/playpad/NativeAudioMacHandler.java | 86 ++++++-------------
 .../playpad/NativeAudioMacHandlerConnect.java | 19 ++++
 8 files changed, 142 insertions(+), 64 deletions(-)
 create mode 100644 PlayWallCore/src/de/tobias/playpad/audio/Peakable.java
 create mode 100644 PlayWallCore/src/de/tobias/playpad/pad/view/PeakMeter.java

diff --git a/PlayWall/src/de/tobias/playpad/action/cartaction/CartAction.java b/PlayWall/src/de/tobias/playpad/action/cartaction/CartAction.java
index b6cc56cd..15796b6f 100644
--- a/PlayWall/src/de/tobias/playpad/action/cartaction/CartAction.java
+++ b/PlayWall/src/de/tobias/playpad/action/cartaction/CartAction.java
@@ -22,9 +22,7 @@ import javafx.beans.property.StringProperty;
 public class CartAction extends Action implements ColorAdjustable {
 
 	public enum ControlMode {
-		PLAY_PAUSE,
-		PLAY_STOP,
-		PLAY_HOLD;
+		PLAY_PAUSE, PLAY_STOP, PLAY_HOLD;
 	}
 
 	private int x;
diff --git a/PlayWall/src/de/tobias/playpad/pad/content/AudioContent.java b/PlayWall/src/de/tobias/playpad/pad/content/AudioContent.java
index 2d9b2200..24b4e838 100644
--- a/PlayWall/src/de/tobias/playpad/pad/content/AudioContent.java
+++ b/PlayWall/src/de/tobias/playpad/pad/content/AudioContent.java
@@ -63,6 +63,10 @@ public class AudioContent extends PadContent implements Pauseable, Durationable,
 		};
 	}
 
+	public AudioHandler getAudioHandler() {
+		return audioHandler;
+	}
+
 	@Override
 	public Path getPath() {
 		return path;
diff --git a/PlayWall/src/de/tobias/playpad/pad/content/AudioContentConnect.java b/PlayWall/src/de/tobias/playpad/pad/content/AudioContentConnect.java
index 538d4d41..ae3ea494 100644
--- a/PlayWall/src/de/tobias/playpad/pad/content/AudioContentConnect.java
+++ b/PlayWall/src/de/tobias/playpad/pad/content/AudioContentConnect.java
@@ -1,10 +1,12 @@
 package de.tobias.playpad.pad.content;
 
 import de.tobias.playpad.Strings;
+import de.tobias.playpad.audio.Peakable;
 import de.tobias.playpad.pad.Pad;
 import de.tobias.playpad.pad.conntent.PadContent;
 import de.tobias.playpad.pad.conntent.PadContentConnect;
 import de.tobias.playpad.pad.view.IPadContentView;
+import de.tobias.playpad.pad.view.PeakMeter;
 import de.tobias.playpad.viewcontroller.option.ProfileSettingsTabViewController;
 import de.tobias.playpad.viewcontroller.option.profile.AudioTabViewController;
 import de.tobias.utils.ui.icon.FontAwesomeType;
@@ -66,15 +68,22 @@ public class AudioContentConnect extends PadContentConnect {
 	private class AudioContentView implements IPadContentView {
 
 		private Label nameLabel;
+		private PeakMeter meter;
 
 		public AudioContentView(Pad pad, Pane parentNode) {
 			nameLabel = new Label();
 			nameLabel.textProperty().bind(pad.nameProperty());
-			
+
 			nameLabel.setWrapText(true);
 			nameLabel.setAlignment(Pos.CENTER);
 			nameLabel.setTextAlignment(TextAlignment.CENTER);
 
+			AudioContent content = (AudioContent) pad.getContent();
+			if (content.getAudioHandler() instanceof Peakable) {
+				Peakable peakable = (Peakable) content.getAudioHandler();
+				meter = new PeakMeter(peakable);
+			}
+
 			nameLabel.prefWidthProperty().bind(parentNode.widthProperty());
 			nameLabel.setMaxHeight(Double.MAX_VALUE);
 			VBox.setVgrow(nameLabel, Priority.ALWAYS);
@@ -82,7 +91,11 @@ public class AudioContentConnect extends PadContentConnect {
 
 		@Override
 		public Node getNode() {
-			return nameLabel;
+			if (meter != null) {
+				return new VBox(7, nameLabel, meter);
+			} else {
+				return new VBox(7, nameLabel);
+			}
 		}
 
 		@Override
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 00000000..c4633e92
--- /dev/null
+++ b/PlayWallCore/src/de/tobias/playpad/audio/Peakable.java
@@ -0,0 +1,15 @@
+package de.tobias.playpad.audio;
+
+import javafx.beans.property.DoubleProperty;
+
+public interface Peakable {
+
+	public enum Channel {
+		LEFT,
+		RIGHT;
+	}
+	
+	public double getAudioLevel(Channel channel);
+	
+	public DoubleProperty audioLevelProperty(Channel channel);
+}
diff --git a/PlayWallCore/src/de/tobias/playpad/pad/view/PeakMeter.java b/PlayWallCore/src/de/tobias/playpad/pad/view/PeakMeter.java
new file mode 100644
index 00000000..01f694bb
--- /dev/null
+++ b/PlayWallCore/src/de/tobias/playpad/pad/view/PeakMeter.java
@@ -0,0 +1,45 @@
+package de.tobias.playpad.pad.view;
+
+import de.tobias.playpad.audio.Peakable;
+import de.tobias.playpad.audio.Peakable.Channel;
+import javafx.beans.value.ChangeListener;
+import javafx.scene.control.ProgressBar;
+import javafx.scene.layout.VBox;
+
+public class PeakMeter extends VBox {
+
+	private ProgressBar progressbarLeft;
+	private ProgressBar progressbarRight;
+
+	private ChangeListener<Number> leftListener;
+	private ChangeListener<Number> rightListener;
+
+	public PeakMeter(Peakable peakable) {
+		progressbarLeft = new ProgressBar(0);
+		progressbarRight = new ProgressBar(0);
+
+		leftListener = (a, b, c) -> {
+			double value = (c.doubleValue() + 60) * 1 / 60;
+			if (value < 0)
+				value = 0;
+			progressbarLeft.setProgress(value);
+		};
+		rightListener = (a, b, c) -> {
+			double value = (c.doubleValue() + 60) * 1 / 60;
+			if (value < 0)
+				value = 0;
+			progressbarRight.setProgress(value);
+		};
+
+		progressbarLeft.getStyleClass().add("pad-playbar");
+		progressbarRight.getStyleClass().add("pad-playbar");
+
+		progressbarLeft.prefWidthProperty().bind(widthProperty());
+		progressbarRight.prefWidthProperty().bind(widthProperty());
+
+		peakable.audioLevelProperty(Channel.LEFT).addListener(leftListener);
+		peakable.audioLevelProperty(Channel.RIGHT).addListener(rightListener);
+
+		getChildren().addAll(progressbarLeft, progressbarRight);
+	}
+}
\ No newline at end of file
diff --git a/PlayWallNative/src/de/tobias/playpad/NativeAudio.java b/PlayWallNative/src/de/tobias/playpad/NativeAudio.java
index ae297856..cee1d727 100644
--- a/PlayWallNative/src/de/tobias/playpad/NativeAudio.java
+++ b/PlayWallNative/src/de/tobias/playpad/NativeAudio.java
@@ -23,7 +23,19 @@ public class NativeAudio {
 	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);
@@ -38,5 +50,9 @@ public class NativeAudio {
 
 	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
index 2ff8be3a..d418b132 100644
--- a/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandler.java
+++ b/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandler.java
@@ -1,73 +1,43 @@
 package de.tobias.playpad;
 
 import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.List;
 
 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 {
-
-	private static final int SLEEP_TIME_POSITION = 100;
+public class NativeAudioMacHandler extends AudioHandler implements Peakable {
 
 	private static int counter = 0;
 
 	private final int id;
-	private ObjectProperty<Duration> positionProperty;
+	ObjectProperty<Duration> positionProperty;
 	private ObjectProperty<Duration> durationProperty;
 	private boolean isLoaded;
 
-	private static Thread positionThread;
-	private static List<NativeAudioMacHandler> playedHandlers = new ArrayList<>();
-
-	static {
-		positionThread = new Thread(() ->
-		{
-			while (true) {
-				try {
-					if (playedHandlers.isEmpty()) {
-						synchronized (positionThread) {
-							positionThread.wait();
-						}
-					}
-
-					for (Iterator<NativeAudioMacHandler> iterator = playedHandlers.iterator(); iterator.hasNext();) {
-						NativeAudioMacHandler handler = iterator.next();
-						Duration seconds = Duration.seconds(NativeAudio.getPosition(handler.id));
-
-						Platform.runLater(() -> handler.positionProperty.set(seconds));
-					}
+	private DoubleProperty leftPeak;
+	private DoubleProperty rightPeak;
 
-					Thread.sleep(SLEEP_TIME_POSITION);
-				} catch (InterruptedException e) {
-				} catch (ConcurrentModificationException e) {
-				} catch (Exception e) {
-					e.printStackTrace();
-				}
-			}
-		});
-
-		positionThread.start();
-	}
-	
 	public NativeAudioMacHandler(PadContent content) {
 		super(content);
 
 		id = counter++;
 		positionProperty = new SimpleObjectProperty<>();
-		durationProperty = new SimpleObjectProperty<>();		
+		durationProperty = new SimpleObjectProperty<>();
+
+		leftPeak = new SimpleDoubleProperty();
+		rightPeak = new SimpleDoubleProperty();
 	}
-	
+
 	protected int getId() {
 		return id;
 	}
@@ -76,33 +46,16 @@ public class NativeAudioMacHandler extends AudioHandler {
 	public void play() {
 		NativeAudio.setLoop(id, getContent().getPad().getPadSettings().isLoop());
 		NativeAudio.play(id);
-
-		boolean start = false;
-		if (playedHandlers.isEmpty()) {
-			start = true;
-		}
-
-		if (!playedHandlers.contains(this))
-			playedHandlers.add(this);
-		if (start) {
-			synchronized (positionThread) {
-				positionThread.notify();
-			}
-		}
 	}
 
 	@Override
 	public void pause() {
 		NativeAudio.pause(id);
-		if (playedHandlers.contains(this))
-			playedHandlers.remove(this);
 	}
 
 	@Override
 	public void stop() {
 		NativeAudio.stop(id);
-		if (playedHandlers.contains(this))
-			playedHandlers.remove(this);
 	}
 
 	@Override
@@ -165,4 +118,19 @@ public class NativeAudioMacHandler extends AudioHandler {
 	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
index 6b70456a..077eb06e 100644
--- a/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandlerConnect.java
+++ b/PlayWallNative/src/de/tobias/playpad/NativeAudioMacHandlerConnect.java
@@ -5,9 +5,11 @@ import java.util.HashMap;
 import de.tobias.playpad.NativeAudio.NativeAudioDelegate;
 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 {
 
@@ -45,4 +47,21 @@ public class NativeAudioMacHandlerConnect extends AudioHandlerConnect implements
 			}
 		}
 	}
+	
+	@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);
+		}
+	}
 }
-- 
GitLab