Add in metronome, delay testing, and bpm timing section offsets

main
Joshua Sigona 3 years ago
parent 3fd0bbb21f
commit 01583d98c6
  1. BIN
      LLSIG/se/metronome_click1.mp3
  2. BIN
      LLSIG/se/metronome_click1.wav
  3. BIN
      LLSIG/se/metronome_click2.mp3
  4. BIN
      LLSIG/se/metronome_click2.wav
  5. 12
      LLSIG/src/main/java/LLSIG/BeatTiming.java
  6. 24
      LLSIG/src/main/java/LLSIG/Canvas.java
  7. 8
      LLSIG/src/main/java/LLSIG/JLayerPlayerPausable.java
  8. 167
      LLSIG/src/main/java/LLSIG/LLSIG.java
  9. 5
      LLSIG/src/main/java/LLSIG/Lane.java
  10. 23
      LLSIG/src/main/java/LLSIG/Player.java

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,12 @@
package main.java.LLSIG;
public class BeatTiming {
long offset;
int bpm;
boolean active;
BeatTiming(long offset,int bpm) {
this.offset=offset;
this.bpm=bpm;
this.active=true;
}
}

@ -22,6 +22,7 @@ public class Canvas extends JPanel{
}
public void paintComponent(Graphics g) {
g.setFont(LLSIG.gameFont);
final int MIDDLE_X = this.getWidth()/2;
final int MIDDLE_Y = this.getHeight()-(this.getWidth()/2);
final int JUDGEMENT_LINE_WIDTH = 64;
@ -36,8 +37,25 @@ public class Canvas extends JPanel{
g.setColor(Color.BLACK);
g.fillRect(0,0,this.getWidth(),this.getHeight());
g.setColor(Color.WHITE);
g.drawString(Integer.toString(LLSIG.game.frameCount),0,16);
g.drawString(Integer.toString(LLSIG.game.musicPlayer.getPlayPosition()),0,32);
g.drawString(Integer.toString(LLSIG.game.musicPlayer.getFrameIndex()),0,64);
if (LLSIG.game.BPM_MEASURE) {
g.drawString("Average BPM: "+LLSIG.approximateBPM(),MIDDLE_X-128,MIDDLE_Y+64);
} else
if (LLSIG.game.METRONOME) {
g.drawString("Offset: "+LLSIG.testOffset,MIDDLE_X-128,MIDDLE_Y+64);
} else {
g.setColor(LLSIG.game.musicPlayer.getPlayPosition()-LLSIG.LAST_PERFECT<500?Color.WHITE:Color.DARK_GRAY);g.drawString("PERFECT: "+LLSIG.PERFECT_COUNT,MIDDLE_X-128,MIDDLE_Y-96);
g.setColor(LLSIG.game.musicPlayer.getPlayPosition()-LLSIG.LAST_EXCELLENT<500?Color.WHITE:Color.DARK_GRAY);g.drawString("EXCELLENT: "+LLSIG.EXCELLENT_COUNT,MIDDLE_X-128,MIDDLE_Y-64);
g.setColor(LLSIG.game.musicPlayer.getPlayPosition()-LLSIG.LAST_GREAT<500?Color.WHITE:Color.DARK_GRAY);g.drawString("GREAT: "+LLSIG.GREAT_COUNT,MIDDLE_X-128,MIDDLE_Y-32);
g.setColor(LLSIG.game.musicPlayer.getPlayPosition()-LLSIG.LAST_EARLY<500?Color.WHITE:Color.DARK_GRAY);g.drawString("EARLY: "+LLSIG.EARLY_COUNT,MIDDLE_X-128,MIDDLE_Y);
g.setColor(LLSIG.game.musicPlayer.getPlayPosition()-LLSIG.LAST_LATE<500?Color.WHITE:Color.DARK_GRAY);g.drawString("LATE: "+LLSIG.LATE_COUNT,MIDDLE_X-128,MIDDLE_Y+32);
g.setColor(LLSIG.game.musicPlayer.getPlayPosition()-LLSIG.LAST_MISS<500?Color.WHITE:Color.DARK_GRAY);g.drawString("MISS: "+LLSIG.MISS_COUNT,MIDDLE_X-128,MIDDLE_Y+64);
}
g.setColor(Color.WHITE);
String comboString = "x"+LLSIG.COMBO+" combo";
Rectangle2D bounds = calculateStringBoundsFont(comboString, g.getFont());
g.drawString(comboString,(int)(MIDDLE_X-bounds.getCenterX()),MIDDLE_Y+164);
for (int i=0;i<9;i++) {
int LANE_X_OFFSET = (i-5)*LANE_SPACING_X+LANE_SPACING_X/2+JUDGEMENT_LINE_WIDTH/2;
@ -50,7 +68,6 @@ public class Canvas extends JPanel{
int NOTE_X=(int)(MIDDLE_X-Math.cos(Math.toRadians(22.5*i))*NOTE_DISTANCE-NOTE_SIZE/2);
int NOTE_Y=(int)(MIDDLE_Y+Math.sin(Math.toRadians(22.5*i))*NOTE_DISTANCE-NOTE_SIZE/2);
g.fillOval(NOTE_X,NOTE_Y,NOTE_SIZE,NOTE_SIZE);
g.setColor(NOTE_COLOR);
Lane lane = LLSIG.game.lanes.get(i);
if (LLSIG.game.PLAYING) {
@ -81,6 +98,7 @@ public class Canvas extends JPanel{
g.drawString(lane.lastRating.name(),(int)(NOTE_X-textBounds.getCenterX()),(int)(NOTE_Y+textBounds.getHeight()));
}
}
g.setColor(NOTE_COLOR);
int noteCounter = 0;
while (lane.noteExists(noteCounter)) {
Note n = lane.getNote(noteCounter);

@ -86,12 +86,12 @@ public class JLayerPlayerPausable{
return this.play(0);
}
public boolean play(int frameIndexStart) throws JavaLayerException {
public boolean play(long frameIndexStart) throws JavaLayerException {
//return this.play(frameIndexStart, -1, 52); //original, mas voltava num ponto anterior ao do pause. 52 Sao os frames perdidos ao dar pause
return this.play(frameIndexStart, -1, lostFrames);
}
public boolean play(int frameIndexStart, int frameIndexFinal, int correctionFactorInFrames) throws JavaLayerException{
public boolean play(long frameIndexStart, int frameIndexFinal, int correctionFactorInFrames) throws JavaLayerException{
try {
this.bitstream = new Bitstream(this.getAudioInputStream());
}
@ -163,6 +163,10 @@ public class JLayerPlayerPausable{
return shouldContinueReadingFrames;
}
public int getFrameIndex() {
return this.frameIndexCurrent;
}
public boolean resume() throws JavaLayerException{
return this.play(this.frameIndexCurrent);

@ -1,5 +1,6 @@
package main.java.LLSIG;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
@ -10,6 +11,11 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JFrame;
import main.java.sig.utils.FileUtils;
@ -21,15 +27,27 @@ public class LLSIG implements KeyListener{
ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(1);
int frameCount;
public static LLSIG game;
int NOTE_SPEED = 850; //The note speed determines how early you see the note. So lowering this number increases the speed.
public static Font gameFont = new Font("Century Gothic",Font.BOLD,32);
public static int bpm = 120;
public static long offset = 0;
public static long testOffset = 0;
public static double beatDelay = ((1/((double)bpm/60))*1000);
public static List<Long> beats = new ArrayList<Long>();
int NOTE_SPEED = 750; //The note speed determines how early you see the note. So lowering this number increases the speed.
List<Lane> lanes = new ArrayList<Lane>();
List<BeatTiming> timings = new ArrayList<BeatTiming>();
String song = "MiChi - ONE-315959669";
final static Dimension WINDOW_SIZE = new Dimension(1280,1050);
public boolean EDITMODE = true;
public boolean PLAYING = false; //Whether or not a song is loaded and playing.
public boolean EDITMODE = false;
public boolean METRONOME = true;
public boolean BPM_MEASURE = false;
public boolean PLAYING = true; //Whether or not a song is loaded and playing.
public static int beatNumber = 0;
public static boolean[] lanePress = new boolean[9]; //A lane is being requested to being pressed.
public static boolean[] keyState = new boolean[9]; //Whether or not the key is pressed down.
@ -39,8 +57,42 @@ public class LLSIG implements KeyListener{
final static int GREAT_TIMING_WINDOW = 100;
final static int BAD_TIMING_WINDOW = 150;
public static int PERFECT_COUNT = 0;
public static int EXCELLENT_COUNT = 0;
public static int GREAT_COUNT = 0;
public static int EARLY_COUNT = 0;
public static int LATE_COUNT = 0;
public static int MISS_COUNT = 0;
public static int LAST_PERFECT = 0;
public static int LAST_EXCELLENT = 0;
public static int LAST_GREAT = 0;
public static int LAST_EARLY = 0;
public static int LAST_LATE = 0;
public static int LAST_MISS = 0;
public static int COMBO = 0;
public static Clip metronome_click1,metronome_click2;
LLSIG(JFrame f) {
this.window = f;
AudioInputStream audioInputStream;
try {
audioInputStream = AudioSystem.getAudioInputStream(new File("se/metronome_click1.wav").getAbsoluteFile());
try {
metronome_click1 = AudioSystem.getClip();
metronome_click1.open(audioInputStream);
audioInputStream = AudioSystem.getAudioInputStream(new File("se/metronome_click2.wav").getAbsoluteFile());
metronome_click2 = AudioSystem.getClip();
metronome_click2.open(audioInputStream);
} catch (LineUnavailableException e) {
e.printStackTrace();
}
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
for (int i=0;i<9;i++) {
lanes.add(new Lane(new ArrayList<Note>()));
@ -60,10 +112,35 @@ public class LLSIG implements KeyListener{
gameLoop = new Thread() {
public void run() {
frameCount++;
if (PLAYING) {
for (BeatTiming bt : timings) {
if (bt.active&&musicPlayer.getPlayPosition()>=bt.offset) {
bt.active=false;
bpm=bt.bpm;
offset=bt.offset;
beatDelay = ((1/((double)bpm/60))*1000);
System.out.println("BPM is "+bpm+". Delay is "+beatDelay);
}
}
if (METRONOME) {
if (beatNumber*beatDelay+offset<musicPlayer.getPlayPosition()) {
beatNumber++;
if (beatNumber%4==0) {
metronome_click1.setFramePosition(0);
metronome_click1.start();
} else {
metronome_click2.setFramePosition(0);
metronome_click2.start();
}
}
}
}
for (int i=0;i<9;i++) {
Lane l =lanes.get(i);
l.markMissedNotes();
l.clearOutInactiveNotes();
if (!EDITMODE) {
l.clearOutInactiveNotes();
}
}
window.repaint();
}
@ -74,22 +151,34 @@ public class LLSIG implements KeyListener{
}
private void LoadSongData(String song,List<Lane> lanes) {
lanes.clear();
for (int i=0;i<9;i++) {
lanes.add(new Lane(new ArrayList<Note>()));
}
timings.clear();
try {
String[] data = FileUtils.readFromFile("music/"+song+".sig");
for (String line : data) {
String[] split = line.split(Pattern.quote(","));
int lane = Integer.parseInt(split[0]);
NoteType noteType = NoteType.valueOf(split[1]);
int offset = Integer.parseInt(split[2]);
int offset2 = -1;
while (lanes.size()<lane) {
lanes.add(new Lane(new ArrayList<Note>()));
}
if (noteType==NoteType.HOLD) {
offset2 = Integer.parseInt(split[2]);
lanes.get(lane-1).addNote(new Note(noteType,offset,offset2));
if (split[0].equals("B")) {
offset=Integer.parseInt(split[1]);
bpm=Integer.parseInt(split[2]);
beatDelay = ((1/((double)bpm/60))*1000);
timings.add(new BeatTiming(offset,bpm));
} else {
lanes.get(lane-1).addNote(new Note(noteType,offset));
int lane = Integer.parseInt(split[0]);
NoteType noteType = NoteType.valueOf(split[1]);
int offset = (int)Math.round(Integer.parseInt(split[2])*beatDelay+LLSIG.offset);
int offset2 = -1;
while (lanes.size()<lane) {
lanes.add(new Lane(new ArrayList<Note>()));
}
if (noteType==NoteType.HOLD) {
offset2 = (int)Math.round(Integer.parseInt(split[2])*beatDelay+LLSIG.offset);
lanes.get(lane-1).addNote(new Note(noteType,offset,offset2));
} else {
lanes.get(lane-1).addNote(new Note(noteType,offset));
}
}
}
} catch (IOException e) {
@ -102,6 +191,9 @@ public class LLSIG implements KeyListener{
for (int lane=0;lane<lanes.size();lane++) {
Lane l = lanes.get(lane);
int noteCount=0;
for (Note n : l.noteChart) {
n.active=true;
}
while (l.noteExists(noteCount)) {
Note n = l.getNote(noteCount++);
data.add(new StringBuilder().append(lane+1).append(",")
@ -120,6 +212,19 @@ public class LLSIG implements KeyListener{
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game = new LLSIG(f);
}
public static double approximateBPM() {
long totalDiff = 0;
if (beats.size()>=2) {
for (int i=1;i<beats.size();i++) {
totalDiff+=beats.get(i)-beats.get(i-1);
}
long averageDiff = totalDiff/(beats.size()-1);
return (1/((double)averageDiff/1000000000l)*60);
} else {
return 0;
}
}
@Override
public void keyTyped(KeyEvent e) {
@ -130,7 +235,18 @@ public class LLSIG implements KeyListener{
public void keyPressed(KeyEvent e) {
int lane = -1;
switch (e.getKeyCode()) {
case KeyEvent.VK_A:{lane=0;}break;
case KeyEvent.VK_A:{
if (BPM_MEASURE) {
beats.add(System.nanoTime());
}
lane=0;
}break;
case KeyEvent.VK_BACK_SLASH:{
if (METRONOME) {
testOffset=musicPlayer.getPlayPosition();
beatNumber=0;
}
}break;
case KeyEvent.VK_S:{lane=1;}break;
case KeyEvent.VK_D:{lane=2;}break;
case KeyEvent.VK_F:{lane=3;}break;
@ -152,10 +268,21 @@ public class LLSIG implements KeyListener{
Note n = l.getNote();
int diff = n.getStartFrame()-LLSIG.game.musicPlayer.getPlayPosition();
if (diff<=BAD_TIMING_WINDOW) {
if (Math.abs(diff)<=PERFECT_TIMING_WINDOW) {l.lastRating=TimingRating.PERFECT;} else
if (Math.abs(diff)<=EXCELLENT_TIMING_WINDOW) {l.lastRating=TimingRating.EXCELLENT;} else
if (Math.abs(diff)<=GREAT_TIMING_WINDOW) {l.lastRating=TimingRating.GREAT;} else
if (Math.abs(diff)<=BAD_TIMING_WINDOW) {l.lastRating=Math.signum(diff)>0?TimingRating.EARLY:TimingRating.LATE;}
if (Math.abs(diff)<=PERFECT_TIMING_WINDOW) {l.lastRating=TimingRating.PERFECT;COMBO++;PERFECT_COUNT++;LAST_PERFECT=LLSIG.game.musicPlayer.getPlayPosition();} else
if (Math.abs(diff)<=EXCELLENT_TIMING_WINDOW) {l.lastRating=TimingRating.EXCELLENT;COMBO++;EXCELLENT_COUNT++;LAST_EXCELLENT=LLSIG.game.musicPlayer.getPlayPosition();} else
if (Math.abs(diff)<=GREAT_TIMING_WINDOW) {l.lastRating=TimingRating.GREAT;COMBO++;GREAT_COUNT++;LAST_GREAT=LLSIG.game.musicPlayer.getPlayPosition();} else
if (Math.abs(diff)<=BAD_TIMING_WINDOW) {
if (Math.signum(diff)>0) {
l.lastRating=TimingRating.EARLY;
EARLY_COUNT++;
LAST_EARLY=LLSIG.game.musicPlayer.getPlayPosition();
} else {
l.lastRating=TimingRating.LATE;
LATE_COUNT++;
LAST_LATE=LLSIG.game.musicPlayer.getPlayPosition();
}
COMBO=0;
}
l.lastNote=LLSIG.game.musicPlayer.getPlayPosition();
n.active=false;
}

@ -25,7 +25,7 @@ public class Lane{
public Note getNote(int noteOffset) throws IndexOutOfBoundsException {
for (int i=noteOffset;i<noteChart.size();i++)
{
Note n = getNote(i);
Note n = noteChart.get(i);
if (n.active) {return n;}
}
return null;
@ -68,6 +68,9 @@ public class Lane{
note.active=false;
lastRating = TimingRating.MISS;
lastNote = LLSIG.game.musicPlayer.getPlayPosition();
LLSIG.COMBO=0;
LLSIG.MISS_COUNT++;
LLSIG.LAST_MISS=LLSIG.game.musicPlayer.getPlayPosition();
}
});
}

@ -6,16 +6,13 @@ public class Player {
String song;
public Player(String song) {
this.song=song;
try {
jlpp = new JLayerPlayerPausable(song);
} catch (JavaLayerException e) {
e.printStackTrace();
}
}
public void play() {
new Thread() {
public void run() {
try {
if (jlpp!=null) {jlpp.close();}
jlpp = new JLayerPlayerPausable(song);
jlpp.play();
} catch (JavaLayerException e) {
e.printStackTrace();
@ -23,6 +20,19 @@ public class Player {
}
}.start();
}
public void play(long frame) {
new Thread() {
public void run() {
try {
if (jlpp!=null) {jlpp.close();}
jlpp = new JLayerPlayerPausable(song);
jlpp.play(frame);
} catch (JavaLayerException e) {
e.printStackTrace();
}
}
}.start();
}
public void pause() {
jlpp.pause();
}
@ -46,4 +56,7 @@ public class Player {
public int getPlayPosition() {
return jlpp.getPosition();
}
public int getFrameIndex() {
return jlpp.getFrameIndex();
}
}

Loading…
Cancel
Save