Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metronome implementation #94

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>11</maven.compiler.release>
<javafx.version>15</javafx.version>
<javafx.version>17-ea+8</javafx.version>
</properties>

<dependencies>
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/com/utsusynth/utsu/UtsuModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,13 @@ private PreferencesManager providePreferencesManager(
defaultBuilder.put("resampler", assetManager.getResamplerFile().getAbsolutePath());
defaultBuilder.put("wavtool", assetManager.getWavtoolFile().getAbsolutePath());
defaultBuilder.put("voicebank", assetManager.getVoicePath().getAbsolutePath());
defaultBuilder.put("metronome", assetManager.getMetronomeFile().getAbsolutePath());
return new PreferencesManager(
settingsPath,
documentBuilderFactory,
TransformerFactory.newDefaultInstance(),
defaultBuilder.build());
defaultBuilder.build()
);
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import javafx.scene.layout.Pane;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.SVGPath;

/** Singleton class, supplier of icon shapes and settings. */
public class IconManager {
Expand Down Expand Up @@ -51,6 +52,14 @@ public void setStopIcon(Pane parent) {
parent.getChildren().add(stopIcon);
}

public void setMetronomeIcon(Pane parent) {
SVGPath metronomeIcon = new SVGPath();
metronomeIcon.setContent("M7 25C7 25 10.662 7.0634 14.2803 7.0634C17.8986 7.0634 14.013 7 17.3848 7C20.7567 7 25 24.8431 25 24.8431L7 25Z");
metronomeIcon.getStyleClass().addAll("playback-icon", "not-selected");
parent.getChildren().clear();
parent.getChildren().add(metronomeIcon);
}

public void selectIcon(Pane selectMe) {
Node child = selectMe.getChildren().get(0);
if (child instanceof Group) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,7 @@
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.shape.Rectangle;
Expand Down Expand Up @@ -124,6 +121,9 @@ public class SongController implements EditorController, Localizable {
@FXML // fx:id="stopIcon"
private AnchorPane stopIcon; // Value injected by FXMLLoader

@FXML // fx:id="metronomeIcon"
private AnchorPane metronomeIcon;

@FXML // fx:id="quantizeChoiceBox"
private ChoiceBox<String> quantizeChoiceBox; // Value injected by FXMLLoader

Expand Down Expand Up @@ -349,6 +349,14 @@ public List<String> getVoicebankSuffixes() {
iconManager.setStopIcon(stopIcon);
stopIcon.setOnMousePressed(event -> iconManager.selectIcon(stopIcon));
stopIcon.setOnMouseReleased(event -> iconManager.deselectIcon(stopIcon));
iconManager.setMetronomeIcon(metronomeIcon);
preferencesManager.getMetronomeEnabled().addListener(((observable, oldValue, newValue) -> {
if (newValue == true) {
iconManager.selectIcon(metronomeIcon);
} else {
iconManager.deselectIcon(metronomeIcon);
}
}));

refreshView();

Expand Down Expand Up @@ -1370,4 +1378,8 @@ public void invokePlugin(File plugin) {
}
}
}

public void toggleMetronome(MouseEvent mouseEvent) {
preferencesManager.getMetronomeEnabled().set(!preferencesManager.getMetronomeEnabled().getValue());
}
}
12 changes: 11 additions & 1 deletion src/main/java/com/utsusynth/utsu/engine/Engine.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.utsusynth.utsu.engine;

import com.google.common.base.Function;
import com.utsusynth.utsu.common.utils.RegionBounds;
import com.utsusynth.utsu.common.StatusBar;
import com.utsusynth.utsu.common.data.LyricConfigData;
import com.utsusynth.utsu.common.exception.ErrorLogger;
import com.utsusynth.utsu.common.quantize.Quantizer;
import com.utsusynth.utsu.common.utils.PitchUtils;
import com.utsusynth.utsu.common.utils.RegionBounds;
import com.utsusynth.utsu.engine.wavtool.UtsuWavtool;
import com.utsusynth.utsu.engine.wavtool.Wavtool;
import com.utsusynth.utsu.files.CacheManager;
Expand Down Expand Up @@ -142,6 +142,16 @@ public boolean startPlayback(
instrumentalPlayer.dispose();
}
});

new Metronome(
mediaPlayer,
song.getTempo(),
String.format("file:%s", this.preferencesManager.getMetronomeFile().getAbsolutePath()),
this.preferencesManager.getMetronomeEnabled()
);



mediaPlayer.play();
}
return finalSong.isPresent();
Expand Down
86 changes: 86 additions & 0 deletions src/main/java/com/utsusynth/utsu/engine/Metronome.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.utsusynth.utsu.engine;

import javafx.beans.property.BooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableBooleanValue;
import javafx.collections.ObservableMap;
import javafx.scene.media.Media;
import javafx.scene.media.MediaMarkerEvent;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;

import java.util.ArrayList;
import java.util.List;

public class Metronome {
public Metronome(
MediaPlayer songPlayer,
Double t,
String clickUri,
BooleanProperty enabled
) {
attach(
songPlayer,
new MediaPlayer(new Media(
clickUri
)),
generateMarkers(songPlayer.getTotalDuration().toSeconds(), t),
enabled
);
}

void attach(
MediaPlayer songPlayer,
MediaPlayer metronomePlayer,
List<Duration> intervals,
ObservableBooleanValue enabled
) {
ObservableMap<String, Duration> mediaMarkers = songPlayer.getMedia().getMarkers();
ThreadLocal<Integer> key = new ThreadLocal<>();
key.set(0);

intervals.forEach(mme -> {
key.set(key.get() + 1);
mediaMarkers.put(
String.valueOf(key.get()),
mme
);
});

ChangeListener<Boolean> enabledListener = (observable, oldValue, newValue) -> {
metronomePlayer.stop();
};
enabled.addListener(enabledListener);
songPlayer.setOnMarker((MediaMarkerEvent mme) -> {
if (enabled.get()) {
metronomePlayer.stop();
metronomePlayer.play();
}
});

Runnable onStop = songPlayer.getOnStopped();
songPlayer.setOnStopped(() -> {
metronomePlayer.stop();
metronomePlayer.dispose();

enabled.removeListener(enabledListener);
onStop.run();
});
}

List<Duration> generateMarkers(
double seconds,
double bpm
) {

ArrayList<Duration> events = new ArrayList<>();
double bps = bpm * (1.0 / 60.0);
double ms_beat = (1.0 / bps) * (1000.0);

for (int i = 0; i < seconds * 1000; i+=ms_beat) {
events.add(new Duration(i));
}

return events;
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/utsusynth/utsu/files/AssetManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public boolean initializeAssets() throws IOException, SecurityException, URISynt
}
copyFile(SOUNDS_SOURCE, soundsPath, "silence.wav", "SILENCE_WAV");
copyFile(SOUNDS_SOURCE, soundsPath, "piano.wav", "PIANO_WAV");
copyFile(SOUNDS_SOURCE, soundsPath, "metronome.wav", "METRONOME_WAV");
initializeVoicebank();

// Initialize executables.
Expand Down Expand Up @@ -140,6 +141,10 @@ public File getPianoFile() {
return new File(soundsPath, "piano.wav");
}

public File getMetronomeFile() {
return new File(soundsPath, "metronome.wav");
}

public File getVoicePath() {
return voicePath;
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/utsusynth/utsu/files/PreferencesManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public class PreferencesManager {
private BooleanProperty showVoicebankFaceTemp;
private BooleanProperty showVoicebankBodyTemp;

private BooleanProperty isMetronomeEnabled;

public PreferencesManager(
@SettingsPath File settingsPath,
DocumentBuilderFactory documentBuilderFactory,
Expand Down Expand Up @@ -325,4 +327,18 @@ public File getVoicebankDefault() {
public void setVoicebank(File voicebank) {
preferences.put("voicebank", voicebank.getAbsolutePath());
}

public File getMetronomeFile() {
return preferences.containsKey("metronome")
? new File(preferences.get("metronome"))
: new File(defaultPreferences.get("metronome"));
}

public BooleanProperty getMetronomeEnabled() {
if (isMetronomeEnabled == null) {
isMetronomeEnabled = new SimpleBooleanProperty();
isMetronomeEnabled.setValue(false);
}
return isMetronomeEnabled;
}
}
Binary file added src/main/resources/assets/sounds/metronome.wav
Binary file not shown.
5 changes: 5 additions & 0 deletions src/main/resources/css/metronome.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/main/resources/fxml/SongScene.fxml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<AnchorPane fx:id="rewindIcon" prefHeight="27.0" prefWidth="27.0" onMouseClicked="#rewindPlayback" />
<AnchorPane fx:id="playPauseIcon" prefHeight="27.0" prefWidth="27.0" onMouseClicked="#playOrPause" />
<AnchorPane fx:id="stopIcon" prefHeight="27.0" prefWidth="27.0" onMouseClicked="#stopPlayback" />
<AnchorPane fx:id="metronomeIcon" prefHeight="27.0" prefWidth="27.0" onMouseClicked="#toggleMetronome" />
</children>
</HBox>
</children>
Expand Down