diff --git a/src/itdelatrisu/opsu/GameData.java b/src/itdelatrisu/opsu/GameData.java index 93ee852e..0d05bbdd 100644 --- a/src/itdelatrisu/opsu/GameData.java +++ b/src/itdelatrisu/opsu/GameData.java @@ -1033,14 +1033,17 @@ public class GameData { * @param y the y coordinate * @param hitSound the object's hit sound */ - public void sliderTickResult(int time, int result, float x, float y, byte hitSound) { + public void sliderTickResult(int time, int result, float x, float y, OsuHitObject hitObject, int repeats) { int hitValue = 0; switch (result) { case HIT_SLIDER30: hitValue = 30; incrementComboStreak(); changeHealth(1f); - SoundController.playHitSound(hitSound); + SoundController.playHitSound( + hitObject.getEdgeHitSoundType(repeats), + hitObject.getSampleSet(repeats), + hitObject.getAdditionSampleSet(repeats)); break; case HIT_SLIDER10: hitValue = 10; @@ -1076,7 +1079,7 @@ public class GameData { * @param isSpinner whether the hit object was a spinner */ public void hitResult(int time, int result, float x, float y, Color color, - boolean end, byte hitSound, boolean isSpinner) { + boolean end, OsuHitObject hitObject, int repeats, boolean isSpinner) { int hitValue = 0; boolean perfectHit = false; switch (result) { @@ -1104,8 +1107,11 @@ public class GameData { return; } if (hitValue > 0) { - SoundController.playHitSound(hitSound); - + SoundController.playHitSound( + hitObject.getEdgeHitSoundType(repeats), + hitObject.getSampleSet(repeats), + hitObject.getAdditionSampleSet(repeats)); + /** * [SCORE FORMULA] * Score = Hit Value + Hit Value * (Combo * Difficulty * Mod) / 25 diff --git a/src/itdelatrisu/opsu/OsuHitObject.java b/src/itdelatrisu/opsu/OsuHitObject.java index 6d6a2f63..e3e31fd9 100644 --- a/src/itdelatrisu/opsu/OsuHitObject.java +++ b/src/itdelatrisu/opsu/OsuHitObject.java @@ -71,6 +71,9 @@ public class OsuHitObject { /** Hit sound type (SOUND_* bitmask). */ private byte hitSound; + /** Hit sound addition (sampleSet, AdditionSampleSet, ?, ...). */ + private byte[] addition; + /** Slider curve type (SLIDER_* constant). */ private char sliderType; @@ -85,6 +88,12 @@ public class OsuHitObject { /** Spinner end time (in ms). */ private int endTime; + + /** Edge Hit sound type (SOUND_* bitmask). */ + private byte[] edgeHitSound; + + /** Edge Hit sound addition (sampleSet, AdditionSampleSet). */ + private byte[][] edgeAddition; // additional v10+ parameters not implemented... // addition -> sampl:add:cust:vol:hitsound @@ -156,8 +165,12 @@ public class OsuHitObject { // type-specific fields if ((type & OsuHitObject.TYPE_CIRCLE) > 0) { - /* 'addition' not implemented. */ - + if (tokens.length > 5) { + String[] additionTokens = tokens[5].split(":"); + addition = new byte[additionTokens.length]; + for (int j = 0; j < additionTokens.length; j++) + this.addition[j] = Byte.parseByte(additionTokens[j]); + } } else if ((type & OsuHitObject.TYPE_SLIDER) > 0) { // slider curve type and coordinates String[] sliderTokens = tokens[5].split("\\|"); @@ -171,8 +184,22 @@ public class OsuHitObject { } this.repeat = Integer.parseInt(tokens[6]); this.pixelLength = Float.parseFloat(tokens[7]); - /* edge fields and 'addition' not implemented. */ - + if (tokens.length > 8) { + String[] edgeHitSoundTokens = tokens[8].split("\\|"); + this.edgeHitSound = new byte[edgeHitSoundTokens.length]; + for (int j = 0; j < edgeHitSoundTokens.length; j++) { + edgeHitSound[j] = Byte.parseByte(edgeHitSoundTokens[j]); + } + } + if (tokens.length > 9) { + String[] edgeAdditionTokens = tokens[9].split("\\|"); + this.edgeAddition = new byte[edgeAdditionTokens.length][2]; + for (int j = 0; j < edgeAdditionTokens.length; j++) { + String[] tedgeAddition = edgeAdditionTokens[j].split(":"); + edgeAddition[j][0] = Byte.parseByte(tedgeAddition[0]); + edgeAddition[j][1] = Byte.parseByte(tedgeAddition[1]); + } + } } else { //if ((type & OsuHitObject.TYPE_SPINNER) > 0) { // some 'endTime' fields contain a ':' character (?) int index = tokens[5].indexOf(':'); @@ -212,6 +239,16 @@ public class OsuHitObject { * @return the sound type (SOUND_* bitmask) */ public byte getHitSoundType() { return hitSound; } + + /** + * Returns the edge hit sound type. + * @return the sound type (SOUND_* bitmask) + */ + public byte getEdgeHitSoundType(int i) { + if(edgeHitSound != null) + return edgeHitSound[i]; + else return hitSound; + } /** * Returns the slider type. @@ -301,4 +338,26 @@ public class OsuHitObject { * Returns the number of extra skips on the combo colors. */ public int getComboSkip() { return (type >> TYPE_NEWCOMBO); } + + /** + * Returns the Sample Set at i. + */ + public byte getSampleSet(int i) { + if (edgeAddition != null) + return edgeAddition[i][0]; + if (addition != null) + return addition[0]; + return 0; + } + + /** + * Returns the Addition Sample Set at i. + */ + public byte getAdditionSampleSet(int i) { + if (edgeAddition != null) + return edgeAddition[i][1]; + if (addition != null) + return addition[1]; + return 0; + } } diff --git a/src/itdelatrisu/opsu/OsuParser.java b/src/itdelatrisu/opsu/OsuParser.java index 40a460e6..3e1c450a 100644 --- a/src/itdelatrisu/opsu/OsuParser.java +++ b/src/itdelatrisu/opsu/OsuParser.java @@ -564,8 +564,8 @@ public class OsuParser { // set combo info // - new combo: get next combo index, reset combo number // - else: maintain combo index, increase combo number - if (((hitObject.isNewCombo() || first) && !hitObject.isSpinner())) { - int skip = 1 + hitObject.getComboSkip(); + if (hitObject.isNewCombo() || first) { + int skip = (hitObject.isSpinner()?0:1) + hitObject.getComboSkip(); for (int i = 0; i < skip; i++) { comboIndex = (comboIndex + 1) % osu.combo.length; comboNumber = 1; diff --git a/src/itdelatrisu/opsu/audio/HitSound.java b/src/itdelatrisu/opsu/audio/HitSound.java index 8b7d6f44..e451547e 100644 --- a/src/itdelatrisu/opsu/audio/HitSound.java +++ b/src/itdelatrisu/opsu/audio/HitSound.java @@ -73,6 +73,9 @@ public enum HitSound implements SoundController.SoundComponent { /** Current sample set. */ private static SampleSet currentSampleSet; + /** Current default sample set. */ + private static SampleSet currentDefaultSampleSet = SampleSet.NORMAL; + /** The file name. */ private String filename; @@ -112,25 +115,38 @@ public enum HitSound implements SoundController.SoundComponent { } /** - * Sets the sample set to use when playing hit sounds. - * @param sampleSet the sample set ("None", "Normal", "Soft", "Drum") + * Sets the default sample set to use when playing hit sounds. + * @param sampleSet the sample set ("auto", "Normal", "Soft", "Drum") */ - public static void setSampleSet(String sampleSet) { - currentSampleSet = null; + public static void setDefaultSampleSet(String sampleSet) { + currentDefaultSampleSet = SampleSet.NORMAL; for (SampleSet ss : SampleSet.values()) { if (sampleSet.equalsIgnoreCase(ss.getName())) { - currentSampleSet = ss; + currentDefaultSampleSet = ss; return; } } } + /** + * Sets the default sample set to use when playing hit sounds. + * @param sampleSet the sample set (0:auto, 1:normal, 2:soft, 3:drum) + */ + public static void setDefaultSampleSet(byte sampleType) { + currentDefaultSampleSet = SampleSet.NORMAL; + for (SampleSet ss : SampleSet.values()) { + if (sampleType == ss.getIndex()) { + currentDefaultSampleSet = ss; + return; + } + } + } /** * Sets the sample set to use when playing hit sounds. - * @param sampleType the sample set (0:none, 1:normal, 2:soft, 3:drum) + * @param sampleType the sample set (0:auto, 1:normal, 2:soft, 3:drum) */ public static void setSampleSet(byte sampleType) { - currentSampleSet = null; + currentSampleSet = currentDefaultSampleSet; for (SampleSet ss : SampleSet.values()) { if (sampleType == ss.getIndex()) { currentSampleSet = ss; @@ -138,4 +154,6 @@ public enum HitSound implements SoundController.SoundComponent { } } } + + } diff --git a/src/itdelatrisu/opsu/audio/SoundController.java b/src/itdelatrisu/opsu/audio/SoundController.java index f9e1d476..22eff929 100644 --- a/src/itdelatrisu/opsu/audio/SoundController.java +++ b/src/itdelatrisu/opsu/audio/SoundController.java @@ -255,7 +255,7 @@ public class SoundController { * Plays hit sound(s) using an OsuHitObject bitmask. * @param hitSound the hit sound (bitmask) */ - public static void playHitSound(byte hitSound) { + public static void playHitSound(byte hitSound, byte sampleSet, byte additionSampleSet) { if (hitSound < 0) return; @@ -264,16 +264,16 @@ public class SoundController { return; // play all sounds - if (hitSound == OsuHitObject.SOUND_NORMAL) - playClip(HitSound.NORMAL.getClip(), volume); - else { - if ((hitSound & OsuHitObject.SOUND_WHISTLE) > 0) - playClip(HitSound.WHISTLE.getClip(), volume); - if ((hitSound & OsuHitObject.SOUND_FINISH) > 0) - playClip(HitSound.FINISH.getClip(), volume); - if ((hitSound & OsuHitObject.SOUND_CLAP) > 0) - playClip(HitSound.CLAP.getClip(), volume); - } + HitSound.setSampleSet(sampleSet); + playClip(HitSound.NORMAL.getClip(), volume); + + HitSound.setSampleSet(additionSampleSet); + if ((hitSound & OsuHitObject.SOUND_WHISTLE) > 0) + playClip(HitSound.WHISTLE.getClip(), volume); + if ((hitSound & OsuHitObject.SOUND_FINISH) > 0) + playClip(HitSound.FINISH.getClip(), volume); + if ((hitSound & OsuHitObject.SOUND_CLAP) > 0) + playClip(HitSound.CLAP.getClip(), volume); } /** diff --git a/src/itdelatrisu/opsu/objects/Circle.java b/src/itdelatrisu/opsu/objects/Circle.java index 18c73c31..ed8dd179 100644 --- a/src/itdelatrisu/opsu/objects/Circle.java +++ b/src/itdelatrisu/opsu/objects/Circle.java @@ -141,7 +141,7 @@ public class Circle implements HitObject { data.hitResult( hitObject.getTime(), result, hitObject.getX(), hitObject.getY(), - color, comboEnd, hitObject.getHitSoundType(), false + color, comboEnd, hitObject, 0, false ); return true; } @@ -153,7 +153,6 @@ public class Circle implements HitObject { public boolean update(boolean overlap, int delta, int mouseX, int mouseY) { int time = hitObject.getTime(); float x = hitObject.getX(), y = hitObject.getY(); - byte hitSound = hitObject.getHitSoundType(); int trackPosition = MusicController.getPosition(); int[] hitResultOffset = game.getHitResultOffsets(); @@ -161,17 +160,17 @@ public class Circle implements HitObject { if (overlap || trackPosition > time + hitResultOffset[GameData.HIT_50]) { if (isAutoMod) // "auto" mod: catch any missed notes due to lag - data.hitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitSound, false); + data.hitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, 0, false); else // no more points can be scored, so send a miss - data.hitResult(time, GameData.HIT_MISS, x, y, null, comboEnd, hitSound, false); + data.hitResult(time, GameData.HIT_MISS, x, y, null, comboEnd, hitObject, 0, false); return true; } // "auto" mod: send a perfect hit result else if (isAutoMod) { if (Math.abs(trackPosition - time) < hitResultOffset[GameData.HIT_300]) { - data.hitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitSound, false); + data.hitResult(time, GameData.HIT_300, x, y, color, comboEnd, hitObject, 0, false); return true; } } diff --git a/src/itdelatrisu/opsu/objects/Slider.java b/src/itdelatrisu/opsu/objects/Slider.java index 79140bf1..6a233058 100644 --- a/src/itdelatrisu/opsu/objects/Slider.java +++ b/src/itdelatrisu/opsu/objects/Slider.java @@ -253,10 +253,14 @@ public class Slider implements HitObject { if (currentRepeats % 2 == 0) { // last circle float[] lastPos = curve.pointAt(1); data.hitResult(hitObject.getTime() + (int) sliderTimeTotal, result, - lastPos[0],lastPos[1], color, comboEnd, hitObject.getHitSoundType(), false); + lastPos[0],lastPos[1], color, comboEnd, + hitObject, currentRepeats+1 + , false); } else { // first circle data.hitResult(hitObject.getTime() + (int) sliderTimeTotal, result, - hitObject.getX(), hitObject.getY(), color, comboEnd, hitObject.getHitSoundType(), false); + hitObject.getX(), hitObject.getY(), color, comboEnd, + hitObject, currentRepeats+1 + , false); } return result; @@ -286,7 +290,9 @@ public class Slider implements HitObject { data.addHitError(hitObject.getTime(), x,y,trackPosition - hitObject.getTime()); sliderClickedInitial = true; data.sliderTickResult(hitObject.getTime(), result, - hitObject.getX(), hitObject.getY(), hitObject.getHitSoundType()); + hitObject.getX(), hitObject.getY(), + hitObject, currentRepeats + ); return true; } } @@ -315,7 +321,6 @@ public class Slider implements HitObject { } } - byte hitSound = hitObject.getHitSoundType(); int trackPosition = MusicController.getPosition(); int[] hitResultOffset = game.getHitResultOffsets(); int lastIndex = hitObject.getSliderX().length - 1; @@ -330,10 +335,10 @@ public class Slider implements HitObject { if (isAutoMod) { // "auto" mod: catch any missed notes due to lag ticksHit++; data.sliderTickResult(time, GameData.HIT_SLIDER30, - hitObject.getX(), hitObject.getY(), hitSound); + hitObject.getX(), hitObject.getY(), hitObject, currentRepeats); } else data.sliderTickResult(time, GameData.HIT_MISS, - hitObject.getX(), hitObject.getY(), hitSound); + hitObject.getX(), hitObject.getY(), hitObject, currentRepeats); } // "auto" mod: send a perfect hit result @@ -342,7 +347,7 @@ public class Slider implements HitObject { ticksHit++; sliderClickedInitial = true; data.sliderTickResult(time, GameData.HIT_SLIDER30, - hitObject.getX(), hitObject.getY(), hitSound); + hitObject.getX(), hitObject.getY(), hitObject, currentRepeats); } } } @@ -411,17 +416,18 @@ public class Slider implements HitObject { ticksHit++; if (currentRepeats % 2 > 0) // last circle data.sliderTickResult(trackPosition, GameData.HIT_SLIDER30, - hitObject.getSliderX()[lastIndex], hitObject.getSliderY()[lastIndex], hitSound); + hitObject.getSliderX()[lastIndex], hitObject.getSliderY()[lastIndex], + hitObject, currentRepeats); else // first circle data.sliderTickResult(trackPosition, GameData.HIT_SLIDER30, - c[0], c[1], hitSound); + c[0], c[1], hitObject, currentRepeats); } // held during new tick if (isNewTick) { ticksHit++; data.sliderTickResult(trackPosition, GameData.HIT_SLIDER10, - c[0], c[1], (byte) -1); + c[0], c[1], hitObject, currentRepeats); } // held near end of slider @@ -431,9 +437,9 @@ public class Slider implements HitObject { followCircleActive = false; if (isNewRepeat) - data.sliderTickResult(trackPosition, GameData.HIT_MISS, 0, 0, (byte) -1); + data.sliderTickResult(trackPosition, GameData.HIT_MISS, 0, 0, hitObject, currentRepeats); if (isNewTick) - data.sliderTickResult(trackPosition, GameData.HIT_MISS, 0, 0, (byte) -1); + data.sliderTickResult(trackPosition, GameData.HIT_MISS, 0, 0, hitObject, currentRepeats); } return false; diff --git a/src/itdelatrisu/opsu/objects/Spinner.java b/src/itdelatrisu/opsu/objects/Spinner.java index 7a16f5bc..64c7ebd8 100644 --- a/src/itdelatrisu/opsu/objects/Spinner.java +++ b/src/itdelatrisu/opsu/objects/Spinner.java @@ -164,7 +164,7 @@ public class Spinner implements HitObject { result = GameData.HIT_MISS; data.hitResult(hitObject.getEndTime(), result, width / 2, height / 2, - Color.transparent, true, (byte) -1, true); + Color.transparent, true, hitObject, 0, true); return result; } diff --git a/src/itdelatrisu/opsu/states/Game.java b/src/itdelatrisu/opsu/states/Game.java index 095b734c..f5a69ce4 100644 --- a/src/itdelatrisu/opsu/states/Game.java +++ b/src/itdelatrisu/opsu/states/Game.java @@ -449,7 +449,7 @@ public class Game extends BasicGameState { beatLengthBase = beatLength = timingPoint.getBeatLength(); else beatLength = beatLengthBase * timingPoint.getSliderMultiplier(); - HitSound.setSampleSet(timingPoint.getSampleType()); + HitSound.setDefaultSampleSet(timingPoint.getSampleType()); SoundController.setSampleVolume(timingPoint.getSampleVolume()); timingPointIndex++; } @@ -728,7 +728,7 @@ public class Game extends BasicGameState { OsuTimingPoint timingPoint = osu.timingPoints.get(0); if (!timingPoint.isInherited()) { beatLengthBase = beatLength = timingPoint.getBeatLength(); - HitSound.setSampleSet(timingPoint.getSampleType()); + HitSound.setDefaultSampleSet(timingPoint.getSampleType()); SoundController.setSampleVolume(timingPoint.getSampleVolume()); timingPointIndex++; } diff --git a/src/itdelatrisu/opsu/states/SongMenu.java b/src/itdelatrisu/opsu/states/SongMenu.java index cfb4679d..ebcd7ce4 100644 --- a/src/itdelatrisu/opsu/states/SongMenu.java +++ b/src/itdelatrisu/opsu/states/SongMenu.java @@ -1260,7 +1260,7 @@ public class SongMenu extends BasicGameState { OsuFile osu = MusicController.getOsuFile(); Display.setTitle(String.format("%s - %s", game.getTitle(), osu.toString())); OsuParser.parseHitObjects(osu); - HitSound.setSampleSet(osu.sampleSet); + HitSound.setDefaultSampleSet(osu.sampleSet); ((Game) game.getState(Opsu.STATE_GAME)).setRestart(Game.Restart.NEW); game.enterState(Opsu.STATE_GAME, new FadeOutTransition(Color.black), new FadeInTransition(Color.black)); }