Skip to content

Commit

Permalink
Implement audio playback.
Browse files Browse the repository at this point in the history
  • Loading branch information
wrandelshofer committed Aug 17, 2024
1 parent f77de2a commit 9f4d37b
Show file tree
Hide file tree
Showing 30 changed files with 982 additions and 282 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Line2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.IndexColorModel;
import java.io.File;
Expand Down Expand Up @@ -84,18 +84,16 @@ private static void drawAnimationFrame(BufferedImage img, Graphics2D g, double s
g.drawString("Frame " + (frameIndex + 1) + " of " + frameCount, 473, 24);
}

private static void drawClock(Graphics2D g, int cx, int cy, int radius, double seconds) {
private static void drawClock(Graphics2D g, int cx, int cy, int radius, double timeInSeconds) {
g.setPaint(Color.WHITE);
g.fillOval(cx - radius, cy - radius, radius * 2, radius * 2);


double minutes = seconds / 60.0;
double hours = minutes / 60.0;
drawClockHand(g, cx, cy, -10, radius / 2, new BasicStroke(20, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL), Color.BLACK, (hours) * (Math.PI * 2.0 / 12.0));
drawClockHand(g, cx, cy, -10, radius - 20, new BasicStroke(20, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL), new Color(0x1a1a1a), (minutes) * (Math.PI * 2.0 / 60.0));
drawClockHand(g, cx, cy, -64, radius - 1, new BasicStroke(6, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL), Color.RED, (seconds) * (Math.PI * 2.0 / +60.0));
drawClockHand(g, cx, cy, -64, radius - 1, new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL, 4f, new float[]{20f, radius * 2}, 0f), Color.RED, (seconds) * (Math.PI * 2.0 / +60.0));

double timeInMinutes = timeInSeconds / 60.0;
double timeInHours = timeInMinutes / 60.0;
drawClockHand(g, cx, cy, -10, radius / 2, new BasicStroke(20, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL), Color.BLACK, (timeInHours) * (Math.PI * 2.0 / 12.0));
drawClockHand(g, cx, cy, -10, radius - 20, new BasicStroke(20, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL), new Color(0x1a1a1a), (timeInMinutes) * (Math.PI * 2.0 / 60.0));
drawClockHand(g, cx, cy, -64, radius - 1, new BasicStroke(6, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL), Color.RED, (timeInSeconds) * (Math.PI * 2.0 / +60.0));
drawClockHand(g, cx, cy, -64, -24, new BasicStroke(20, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL), Color.RED, (timeInSeconds) * (Math.PI * 2.0 / +60.0));
// Draw plug
int plugRadius = 12;
g.setPaint(Color.WHITE);
Expand All @@ -105,13 +103,15 @@ private static void drawClock(Graphics2D g, int cx, int cy, int radius, double s
g.drawOval(cx - plugRadius, cy - plugRadius, plugRadius * 2, plugRadius * 2);
}

private static void drawClockHand(Graphics2D g, int cx, int cy, int radius1, int radius2, Stroke stroke, Color color, double angle) {
angle = angle % (Math.PI * 2);
double sin = Math.sin(angle);
double cos = Math.cos(angle);
g.setPaint(color);
private static void drawClockHand(Graphics2D g, int cx, int cy, int radius1, int radius2, Stroke stroke, Color color, double theta) {
AffineTransform tx = new AffineTransform();
tx.setToRotation(theta % (Math.PI * 2), cx, cy);
g.setTransform(tx);
g.setColor(color);
g.setStroke(stroke);
g.draw(new Line2D.Double(cx + radius1 * sin, cy - radius1 * cos, cx + radius2 * sin, cy - radius2 * cos));
g.drawLine(cx, cy - radius1, cx, cy - radius2);
tx.setToIdentity();
g.setTransform(tx);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ public void start(Stage stage) throws Exception {
MainWindowController controller = loader.getController();


stage.titleProperty().bind(controller.fileProperty().map(f ->
labels.getString("application.name") + (f == null ? "" : ": " + f.getName())
));
controller.fileProperty().addListener((o, oldv, f) ->
stage.setTitle((f == null ? labels.getString("file.noFile") : f.getName()))
);
stage.setOnHidden(event -> controller.close(null));


stage.setTitle(labels.getString("file.noFile"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("controls.css").toString());
stage.setScene(scene);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
Expand Down Expand Up @@ -49,12 +50,10 @@ enum Mode {
@FXML // URL location of the FXML file that was given to the FXMLLoader
private URL location;

@FXML
private StackPane stackPane; // Value injected by FXMLLoader


@FXML // fx:id="rootPane"
private BorderPane rootPane; // Value injected by FXMLLoader
@FXML // fx:id="rootPane"
private StackPane stackPane; // Value injected by FXMLLoader
private FileChooser fileChooser;

@FXML
Expand All @@ -71,6 +70,12 @@ void about(ActionEvent event) {

@FXML
void close(ActionEvent event) {
MediaPlayerInterface p = player.get();
if (p != null) {
p.dispose();
player.set(null);
stackPane.getChildren().clear();
}
getStage().close();
}

Expand All @@ -87,6 +92,51 @@ private Stage getStage() {
return scene == null ? null : (Stage) scene.getWindow();
}

@FXML
void zoomIn(ActionEvent event) {
zoomTo((Math.round(getZoomPower() + 1)));
}

@FXML
void zoomOut(ActionEvent event) {
zoomTo((Math.round(getZoomPower() - 1)));
}

@FXML
void zoomToActualSize(ActionEvent event) {
zoomTo(0);
}

void zoomTo(double power) {
MediaInterface media = getPlayer() instanceof MediaPlayerInterface p ? p.getMedia() : null;
if (media == null) {
return;
}
double factor = Math.pow(2, power);
stackPane.setPrefWidth(media.getWidth() * factor);
stackPane.setPrefHeight(media.getHeight() * factor);
getStage().sizeToScene();
}

private MediaPlayerInterface getPlayer() {
return player.get();
}

private double getZoomPower() {
MediaInterface media = getPlayer() instanceof MediaPlayerInterface p ? p.getMedia() : null;
if (media == null) {
return 1;
}
double factor = stackPane.getWidth() / media.getWidth();
double power = Math.log(factor) / Math.log(2);
return power;
}

@FXML
void zoomToFit(ActionEvent event) {
zoomTo(getZoomPower());
}

@FXML
// This method is called by the FXMLLoader when initialization is complete
void initialize() {
Expand Down Expand Up @@ -148,21 +198,23 @@ private void createMoviePlayer(int retries) {
};

if (player == null || player.getError() != null) {
retryCreateMoviePlayer(retries);
retryCreateMoviePlayer(retries, player == null ? null : player.getError());
} else {
player.setOnError(() -> retryCreateMoviePlayer(retries));
this.player.set(player);
player.setOnError(() -> retryCreateMoviePlayer(retries, player.getError()));
}
}

private void retryCreateMoviePlayer(int retries) {
private void retryCreateMoviePlayer(int retries, Throwable error) {
Mode[] values = Mode.values();
if (retries < values.length) {
mode.set(values[(mode.get().ordinal() + 1) % values.length]);
createMoviePlayer(retries + 1);
} else {
ObservableList<Node> c = stackPane.getChildren();
c.clear();
c.add(new Label(resources.getString("error.creatingPlayer")));
c.add(new Label(resources.getString("error.creatingPlayer") + "\n" + error));
error.printStackTrace();
}
}

Expand All @@ -174,9 +226,9 @@ private MediaPlayerInterface createMonteMediaPlayer() {
}
MonteMedia movie = new MonteMedia(mediaFile);
MonteMediaPlayer player = new MonteMediaPlayer(movie);
MonteMediaView monteMediaView = MonteMediaView.newVideoView();
MonteMediaView monteMediaView = MonteMediaView.newMonteMediaView();
monteMediaView.setMedia(movie);
ControlsController playerController = createPlayerController();
PlayerControlsController playerController = createPlayerController();
playerController.setPlayer(player);
showPlayer(monteMediaView.getRoot(), player, movie, playerController);
return player;
Expand All @@ -201,15 +253,22 @@ private MediaPlayerInterface createFXMoviePlayer() {
mediaPlayer.dispose();
return null;
}
ControlsController playerController = createPlayerController();
PlayerControlsController playerController = createPlayerController();
FXMediaPlayer p = new FXMediaPlayer(mediaPlayer);
player.set(p);
playerController.setPlayer(p);
mediaPlayer.setAutoPlay(true);
mediaView = new MediaView(mediaPlayer);


mediaView.fitWidthProperty().bind(stackPane.widthProperty());
mediaView.fitHeightProperty().bind(stackPane.heightProperty());
mediaView.setManaged(false);

mediaView.setPreserveRatio(false);


showPlayer(mediaView, p, new FXMedia(media), playerController);
//mediaView.setOnError(t -> leftStatusLabel.setText(resources.getString("error") + t.toString()));

return p;
} catch (Exception mediaException) {
Expand All @@ -218,19 +277,21 @@ private MediaPlayerInterface createFXMoviePlayer() {
return null;
}


private void showPlayer(Node mediaView, MediaPlayerInterface mediaPlayer, MediaInterface media, ControlsController playerController) {
private void showPlayer(Node mediaView, MediaPlayerInterface mediaPlayer, MediaInterface media, PlayerControlsController playerController) {
mediaPlayer.setOnReady(() -> {
stackPane.setPrefWidth(media.getWidth());
stackPane.setPrefHeight(media.getHeight());
sizeStageToScene();
});

stackPane.getChildren().addAll(mediaView, playerController.getRoot());
}

private ControlsController createPlayerController() {
private PlayerControlsController createPlayerController() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Controls.fxml"));
FXMLLoader loader = new FXMLLoader(getClass().getResource("PlayerControls.fxml"));
ResourceBundle labels = ResourceBundle.getBundle("org.monte.demo.javafx.movieplayer.Labels");
loader.setRoot(new AnchorPane());
loader.setResources(labels);
loader.load();
return loader.getController();
Expand Down
Loading

0 comments on commit 9f4d37b

Please sign in to comment.