From 86725121304d0b3977b20344354143a7c336a965 Mon Sep 17 00:00:00 2001 From: David Day Date: Tue, 7 Jul 2020 21:59:24 +0800 Subject: [PATCH] Update score calculate method improve code quality --- README.md | 6 +- .../gamemode/AbstractModeController.java | 17 +++-- .../midimug/gamemode/FluidModeController.java | 75 ++++++++++++------- .../midimug/gamemode/RealModeController.java | 69 ++++++++++------- .../midimug/gamemode/ShowModeController.java | 49 +++++++----- .../midimug/render/LoadFileRenderer.java | 1 - .../david/midimug/render/SheetRenderer.java | 16 ++-- 7 files changed, 142 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index 26d09f6..cb0960e 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,9 @@ Extract the zip fie, go to `bin` folder, and execute `MIDI_MUG`! In `File` -> `Open...` select a MIDI file you want to play with. You can use your MIDI file or download it in the following site! -- [BitMidi](https://bitmidi.com/) -- [midiworld.com](https://www.midiworld.com/) -- [MIDI DB](https://www.mididb.com/) + - [BitMidi](https://bitmidi.com/) + - [midiworld.com](https://www.midiworld.com/) + - [MIDI DB](https://www.mididb.com/) ![Screenshot](https://github.com/dj6082013/MIDI-MUG/raw/master/screenshot.png?raw=true "Screenshot") diff --git a/src/main/java/com/david/midimug/gamemode/AbstractModeController.java b/src/main/java/com/david/midimug/gamemode/AbstractModeController.java index 746c8c7..f1606f5 100644 --- a/src/main/java/com/david/midimug/gamemode/AbstractModeController.java +++ b/src/main/java/com/david/midimug/gamemode/AbstractModeController.java @@ -17,10 +17,9 @@ package com.david.midimug.gamemode; import com.david.midimug.handler.Note; -import javafx.animation.KeyFrame; +import javafx.animation.Timeline; import javafx.scene.layout.Pane; import javafx.scene.shape.Rectangle; -import javafx.util.Duration; import javax.sound.midi.MidiMessage; import javax.sound.midi.Receiver; import javax.sound.midi.ShortMessage; @@ -34,11 +33,15 @@ public abstract class AbstractModeController implements Receiver { private static final int NOTE_ON = 0x90; private static final int NOTE_OFF = 0x80; - public abstract KeyFrame onNoteShow(Duration time, Pane pane, Rectangle bar, Note note); - - public abstract KeyFrame onNoteStart(Duration time, Pane pane, Rectangle bar, Note note); - - public abstract KeyFrame onNoteEnd(Duration time, Pane pane, Rectangle bar, Note note); + public abstract void setupNote( + Pane pane, + Rectangle bar, + Timeline timeline, + Note note, + double show_t, + double start_t, + double end_t + ); public abstract void onUserPress(int key); diff --git a/src/main/java/com/david/midimug/gamemode/FluidModeController.java b/src/main/java/com/david/midimug/gamemode/FluidModeController.java index e3d0457..94be411 100644 --- a/src/main/java/com/david/midimug/gamemode/FluidModeController.java +++ b/src/main/java/com/david/midimug/gamemode/FluidModeController.java @@ -24,6 +24,8 @@ import java.util.Arrays; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.beans.property.Property; import javafx.event.ActionEvent; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; @@ -36,46 +38,64 @@ */ public class FluidModeController extends AbstractModeController { - private long[] note_status; + private static final int NOTE_OFF = -1; + private static final int NOTE_RANGE = 200; + + private final double[] note_start; + private final double[] note_end; public FluidModeController() { super(); - note_status = new long[200]; - Arrays.fill(note_status, -1); + note_start = new double[NOTE_RANGE]; + note_end = new double[NOTE_RANGE]; + Arrays.fill(note_start, NOTE_OFF); } @Override - public KeyFrame onNoteShow(Duration time, Pane pane, Rectangle bar, Note note) { - KeyValue barY = new KeyValue(bar.layoutYProperty(), -bar.getHeight()); - return new KeyFrame(time, barY); - } + public void setupNote(Pane pane, Rectangle bar, Timeline timeline, Note note, double show_t, double start_t, double end_t) { + Property YProperty = bar.layoutYProperty(); + double barHeight = bar.getHeight(); + double paneHeight = pane.getHeight(); + int key = note.getKey(); - @Override - public KeyFrame onNoteStart(Duration time, Pane pane, Rectangle bar, Note note) { - KeyValue barY = new KeyValue(bar.layoutYProperty(), pane.getHeight() - bar.getHeight()); - return new KeyFrame(time, (ActionEvent t) -> { - MidiInstruments.noteOn(note.getKey()); - note_status[note.getKey()] = Math.round(time.toMillis()); - }, barY); - } + KeyFrame show = new KeyFrame( + Duration.millis(show_t), + new KeyValue(YProperty, -barHeight) + ); - @Override - public KeyFrame onNoteEnd(Duration time, Pane pane, Rectangle bar, Note note) { - KeyValue barY = new KeyValue(bar.layoutYProperty(), pane.getHeight()); - return new KeyFrame(time, (ActionEvent t) -> { - MidiInstruments.noteOff(note.getKey()); - note_status[note.getKey()] = -1; - }, barY); + KeyFrame start = new KeyFrame( + Duration.millis(start_t), + (ActionEvent t) -> { + MidiInstruments.noteOn(key); + note_start[key] = start_t; + note_end[key] = end_t; + }, + new KeyValue(YProperty, paneHeight - barHeight) + ); + + KeyFrame end = new KeyFrame( + Duration.millis(end_t), + (ActionEvent t) -> { + MidiInstruments.noteOff(key); + note_start[key] = NOTE_OFF; + note_end[key] = NOTE_OFF; + }, + new KeyValue(YProperty, paneHeight) + ); + + timeline.getKeyFrames().addAll(show, start, end); } @Override public void onUserPress(int key) { - if (note_status[key] != -1) { - long currentMillis = Math.round(SheetUtils.getCurrentTime().toMillis()); - long score = Math.max(0, 1000 - (currentMillis - note_status[key])); - SheetRenderer.renderCombo(Long.toString(score), Color.CORAL); + if (note_start[key] != NOTE_OFF) { + double currentMillis = SheetUtils.getCurrentTime().toMillis(); + double length = note_end[key] - note_start[key]; + double accuracy = length - (currentMillis - note_start[key]); + int score = (int) Math.round(1000 * accuracy / length); + SheetRenderer.renderCombo(Integer.toString(score), Color.CORAL); - note_status[key] = -1; + note_start[key] = NOTE_OFF; } KeyboardRenderer.pressKey(key); } @@ -89,5 +109,4 @@ public void onUserRelease(int key) { public long getScore() { throw new UnsupportedOperationException("Not supported yet."); } - } diff --git a/src/main/java/com/david/midimug/gamemode/RealModeController.java b/src/main/java/com/david/midimug/gamemode/RealModeController.java index 46cad7a..e4a4bf7 100644 --- a/src/main/java/com/david/midimug/gamemode/RealModeController.java +++ b/src/main/java/com/david/midimug/gamemode/RealModeController.java @@ -24,6 +24,8 @@ import java.util.Arrays; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.beans.property.Property; import javafx.event.ActionEvent; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; @@ -36,44 +38,60 @@ */ public class RealModeController extends AbstractModeController { - private long[] note_status; + private static final int NOTE_OFF = -1; + private static final int NOTE_RANGE = 200; + + private final double[] note_start; + private final double[] note_end; public RealModeController() { super(); - note_status = new long[200]; - Arrays.fill(note_status, -1); + note_start = new double[NOTE_RANGE]; + note_end = new double[NOTE_RANGE]; + Arrays.fill(note_start, NOTE_OFF); } @Override - public KeyFrame onNoteShow(Duration time, Pane pane, Rectangle bar, Note note) { - KeyValue barY = new KeyValue(bar.layoutYProperty(), -bar.getHeight()); - return new KeyFrame(time, barY); - } + public void setupNote(Pane pane, Rectangle bar, Timeline timeline, Note note, double show_t, double start_t, double end_t) { + Property YProperty = bar.layoutYProperty(); + double barHeight = bar.getHeight(); + double paneHeight = pane.getHeight(); + int key = note.getKey(); - @Override - public KeyFrame onNoteStart(Duration time, Pane pane, Rectangle bar, Note note) { - KeyValue barY = new KeyValue(bar.layoutYProperty(), pane.getHeight() - bar.getHeight()); - return new KeyFrame(time, (ActionEvent t) -> { - note_status[note.getKey()] = Math.round(time.toMillis()); - }, barY); - } + KeyFrame show = new KeyFrame( + Duration.millis(show_t), + new KeyValue(YProperty, -barHeight) + ); - @Override - public KeyFrame onNoteEnd(Duration time, Pane pane, Rectangle bar, Note note) { - KeyValue barY = new KeyValue(bar.layoutYProperty(), pane.getHeight()); - return new KeyFrame(time, (ActionEvent t) -> { - note_status[note.getKey()] = -1; - }, barY); + KeyFrame start = new KeyFrame( + Duration.millis(start_t), + (ActionEvent t) -> { + note_start[key] = start_t; + }, + new KeyValue(YProperty, paneHeight - barHeight) + ); + + KeyFrame end = new KeyFrame( + Duration.millis(end_t), + (ActionEvent t) -> { + note_start[note.getKey()] = NOTE_OFF; + }, + new KeyValue(YProperty, paneHeight) + ); + + timeline.getKeyFrames().addAll(show, start, end); } @Override public void onUserPress(int key) { - if (note_status[key] != -1) { - long currentMillis = Math.round(SheetUtils.getCurrentTime().toMillis()); - long score = Math.max(0, 1000 - (currentMillis - note_status[key])); - SheetRenderer.renderCombo(Long.toString(score), Color.CORAL); + if (note_start[key] != NOTE_OFF) { + double currentMillis = SheetUtils.getCurrentTime().toMillis(); + double length = note_end[key] - note_start[key]; + double accuracy = length - (currentMillis - note_start[key]); + int score = (int) Math.round(1000 * accuracy / length); + SheetRenderer.renderCombo(Integer.toString(score), Color.CORAL); - note_status[key] = -1; + note_start[key] = NOTE_OFF; } KeyboardRenderer.pressKey(key); MidiInstruments.noteOn(key); @@ -89,5 +107,4 @@ public void onUserRelease(int key) { public long getScore() { throw new UnsupportedOperationException("Not supported yet."); } - } diff --git a/src/main/java/com/david/midimug/gamemode/ShowModeController.java b/src/main/java/com/david/midimug/gamemode/ShowModeController.java index bc5ee85..c87cab9 100644 --- a/src/main/java/com/david/midimug/gamemode/ShowModeController.java +++ b/src/main/java/com/david/midimug/gamemode/ShowModeController.java @@ -21,6 +21,8 @@ import com.david.midimug.render.KeyboardRenderer; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.beans.property.Property; import javafx.event.ActionEvent; import javafx.scene.layout.Pane; import javafx.scene.shape.Rectangle; @@ -33,27 +35,36 @@ public class ShowModeController extends AbstractModeController { @Override - public KeyFrame onNoteShow(Duration time, Pane pane, Rectangle bar, Note note) { - KeyValue barY = new KeyValue(bar.layoutYProperty(), -bar.getHeight()); - return new KeyFrame(time, barY); - } + public void setupNote(Pane pane, Rectangle bar, Timeline timeline, Note note, double show_t, double start_t, double end_t) { + Property YProperty = bar.layoutYProperty(); + double barHeight = bar.getHeight(); + double paneHeight = pane.getHeight(); + int key = note.getKey(); - @Override - public KeyFrame onNoteStart(Duration time, Pane pane, Rectangle bar, Note note) { - KeyValue barY = new KeyValue(bar.layoutYProperty(), pane.getHeight() - bar.getHeight()); - return new KeyFrame(time, (ActionEvent t) -> { - KeyboardRenderer.pressKey(note.getKey()); - MidiInstruments.noteOn(note.getKey()); - }, barY); - } + KeyFrame show = new KeyFrame( + Duration.millis(show_t), + new KeyValue(YProperty, -barHeight) + ); - @Override - public KeyFrame onNoteEnd(Duration time, Pane pane, Rectangle bar, Note note) { - KeyValue barY = new KeyValue(bar.layoutYProperty(), pane.getHeight()); - return new KeyFrame(time, (ActionEvent t) -> { - KeyboardRenderer.releaseKey(note.getKey()); - MidiInstruments.noteOff(note.getKey()); - }, barY); + KeyFrame start = new KeyFrame( + Duration.millis(start_t), + (ActionEvent t) -> { + KeyboardRenderer.pressKey(key); + MidiInstruments.noteOn(key); + }, + new KeyValue(YProperty, paneHeight - barHeight) + ); + + KeyFrame end = new KeyFrame( + Duration.millis(end_t), + (ActionEvent t) -> { + MidiInstruments.noteOff(key); + KeyboardRenderer.releaseKey(key); + }, + new KeyValue(YProperty, paneHeight) + ); + + timeline.getKeyFrames().addAll(show, start, end); } @Override diff --git a/src/main/java/com/david/midimug/render/LoadFileRenderer.java b/src/main/java/com/david/midimug/render/LoadFileRenderer.java index f67507c..0846848 100644 --- a/src/main/java/com/david/midimug/render/LoadFileRenderer.java +++ b/src/main/java/com/david/midimug/render/LoadFileRenderer.java @@ -21,7 +21,6 @@ import com.david.midimug.gamemode.FluidModeController; import com.david.midimug.gamemode.RealModeController; import com.david.midimug.gamemode.ShowModeController; -import com.david.midimug.handler.SheetUtils; import java.io.File; import java.util.NoSuchElementException; import java.util.Optional; diff --git a/src/main/java/com/david/midimug/render/SheetRenderer.java b/src/main/java/com/david/midimug/render/SheetRenderer.java index effaf1c..265a0ca 100644 --- a/src/main/java/com/david/midimug/render/SheetRenderer.java +++ b/src/main/java/com/david/midimug/render/SheetRenderer.java @@ -23,14 +23,12 @@ import com.david.midimug.handler.Sheet; import java.util.Timer; import java.util.TimerTask; -import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.text.Font; import javafx.scene.text.Text; -import javafx.util.Duration; /** * @@ -84,11 +82,15 @@ public static void renderBarSheet(Pane target, Sheet sheet, Timeline timeline) { double start_time = show_time + shift; double end_time = computeTick(i.getTimeStamp() + i.getLength(), sheet) + shift; - KeyFrame show = controller.onNoteShow(Duration.millis(show_time), target, bar, i); - KeyFrame start = controller.onNoteStart(Duration.millis(start_time), target, bar, i); - KeyFrame end = controller.onNoteEnd(Duration.millis(end_time), target, bar, i); - - timeline.getKeyFrames().addAll(show, start, end); + controller.setupNote( + target, + bar, + timeline, + i, + show_time, + start_time, + end_time + ); target.getChildren().add(bar); }