Skip to content

Commit

Permalink
experimental chart parsing, beats fixed up but midis will not work at…
Browse files Browse the repository at this point in the history
… all
  • Loading branch information
RileyTheFox committed Apr 26, 2023
1 parent 1dc2b62 commit 1f58b5a
Show file tree
Hide file tree
Showing 24 changed files with 560 additions and 192 deletions.
2 changes: 2 additions & 0 deletions Assets/Plugins/MoonscraperChartParser/MoonSong.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public IO.ExportOptions defaultExportOptions
MoonChart[] charts;
public List<MoonChart> unrecognisedCharts = new List<MoonChart>();

public IReadOnlyList<MoonChart> Charts => charts.ToList();

public List<Event> _events;
List<SyncTrack> _syncTrack;

Expand Down
20 changes: 20 additions & 0 deletions Assets/Script/Chart/Beat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace YARG.Chart {
public struct Beat {
public uint Position;
public float Time;
public BeatStyle Style;

public Beat(uint position, float time, BeatStyle type) {
Position = position;
Time = time;
Style = type;
}
}

public enum BeatStyle {
MEASURE,
STRONG,
WEAK,
}

}
3 changes: 3 additions & 0 deletions Assets/Script/Chart/Beat.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

158 changes: 158 additions & 0 deletions Assets/Script/Chart/BeatHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using System.Collections.Generic;
using MoonscraperChartEditor.Song;

namespace YARG.Chart {
public class BeatHandler {

private readonly MoonSong _song;

public List<Beat> Beats;
public List<Beat> Measures;

public int TotalBeatCount => Beats.Count;
private int lastMeasure;

public int CurrentMeasure { get; private set; }

public BeatHandler(MoonSong song) {
_song = song;

Beats = new List<Beat>();
Measures = new List<Beat>();
}

private void AddBeat(uint tick, BeatStyle type) {
Beats.Add(new Beat(tick, (float) _song.TickToTime(tick), type));

if (type == BeatStyle.MEASURE)
Measures.Add(Beats[^1]);
}

// Thanks mdsitton for the CH beat generation algorithm when I was making SideyBot :)
public void GenerateBeats() {
uint currentTick = 0;
uint lastTick = _song.GetLastTick();

// How many ticks to move forward to get to the next beat.
uint forwardStep = 0;

TimeSignature lastTS = null;
TimeSignature currentTS;

int currentBeatInMeasure = 0;
int beatsInTS = 0;

// The last beat style that was generated. Always starts as a measure.
BeatStyle lastStyle = BeatStyle.MEASURE;

// lastTick + forwardStep ensures we will always look ahead 1 more beat than the lastTick.
while (currentTick < lastTick + forwardStep || lastStyle != BeatStyle.MEASURE) {
// Gets previous time signature before currentTick.
currentTS = _song.GetPrevTS(currentTick);

// The number of "beats within a beat" there is
uint currentSubBeat = currentTS.denominator / 4;

bool hasTsChanged = lastTS == null || lastTS.numerator != currentTS.numerator || lastTS.denominator != currentTS.denominator;

// If denominator is larger than 4 start off with weak beats, if 4 or less use strong beats
var style = currentTS.denominator > 4 ? BeatStyle.WEAK : BeatStyle.STRONG;

// New time signature. First beat of a new time sig is always a measure.
if (hasTsChanged) {
beatsInTS = 0;
currentBeatInMeasure = 0;
}

// Beat count is equal to TS numerator, so its a new measure.
if (currentBeatInMeasure == currentTS.numerator) {
currentBeatInMeasure = 0;
}

if (currentTS.denominator <= 4 || currentBeatInMeasure % currentSubBeat == 0) {
style = BeatStyle.STRONG;
}

// Make it a measure if first beat of a measure.
if (currentBeatInMeasure == 0) {
style = BeatStyle.MEASURE;

// Handle 1/x TS's so that only the first beat in the TS gets a measure line
// and then from there it is marked at a strong beat every quarter note with everything else as weak
if (currentTS.numerator == 1 && beatsInTS > 0) {
if (currentTick >= lastTick) {
style = BeatStyle.MEASURE;
}
// if not quarter note length beats every quarter note is stressed
else if (currentTS.denominator <= 4 || (beatsInTS % currentSubBeat) == 0) {
style = BeatStyle.STRONG;
} else {
style = BeatStyle.WEAK;
}
}
}

// Last beat should never be a strong beat if denominator is bigger than 4.
if (currentBeatInMeasure == currentTS.numerator - 1 && currentTS.denominator > 4) {
style = BeatStyle.WEAK;
}

AddBeat(currentTick, style);

currentBeatInMeasure++;
beatsInTS++;

forwardStep = (uint) (_song.resolution * 4) / currentTS.denominator;
currentTick += forwardStep;
lastTS = currentTS;
lastStyle = style;
}

lastMeasure = Measures.Count - 1;
}

public void UpdateCurrentMeasure(double songTime) {
while (CurrentMeasure <= lastMeasure && songTime > Measures[CurrentMeasure].Time) {
CurrentMeasure++;
}
}

public int GetNoteMeasure(Note note) {
int dif = CurrentMeasure;

while (dif < Measures.Count && note.Time >= Measures[dif].Time)
dif++;

return dif;
}
}

public static class SongHelpers {
public static uint GetLastTick(this MoonSong song)
{
uint lastTick = 0;
foreach (var songEvent in song.events)
{
if (songEvent.tick > lastTick)
{
lastTick = songEvent.tick;
}
}
foreach (var chart in song.Charts)
{
foreach (var songObject in chart.chartObjects) {
if (songObject.tick <= lastTick) continue;

lastTick = songObject.tick;

if (songObject is MoonNote note)
{
lastTick += note.length;
}
}
}

return lastTick;
}
}
}
3 changes: 3 additions & 0 deletions Assets/Script/Chart/BeatHandler.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

109 changes: 15 additions & 94 deletions Assets/Script/Chart/Loaders/GuitarChartLoader.cs
Original file line number Diff line number Diff line change
@@ -1,107 +1,28 @@
using System.Collections.Generic;
using System.Collections.Generic;
using MoonscraperChartEditor.Song;
using YARG.Data;

namespace YARG.Chart {
public class GuitarChartLoader : IChartLoader<GuitarNote> {
public class GuitarChartLoader : IChartLoader<NoteInfo> {
public List<NoteInfo> GetNotesFromChart(MoonSong song, MoonChart chart) {
var notes = new List<NoteInfo>();

public List<GuitarNote> GetNotesFromChart(MoonSong song, MoonChart chart) {
var notes = new List<GuitarNote>();

var starpowers = chart.starPower.ToArray();

// Previous note (could be same tick)
Note previousGameNote = null;

// Previous note that is a different tick
Note previousSeparateGameNote = null;

Note parentNote = null;
foreach (var moonNote in chart.notes) {
var prevSeparateNote = moonNote.PreviousSeperateMoonNote;
var nextSeparateNote = moonNote.NextSeperateMoonNote;

var flags = NoteFlags.None;

foreach (var starpower in starpowers) {
uint spEndTick = starpower.tick + starpower.length;

// Current note is within the bounds of current StarPower.
// MoonNote tick is bigger or equal to StarPower tick
// and smaller than StarPower end tick.
if (moonNote.tick >= starpower.tick && moonNote.tick < spEndTick) {
flags |= NoteFlags.StarPower;

// If this is first note, or previous note is before starpower tick, mark as starpower start.
if (prevSeparateNote is null || prevSeparateNote.tick < starpower.tick)
{
flags |= NoteFlags.StarPowerStart;
}
// If this is last note, or next note is not in starpower range, mark as end of starpower.
if (nextSeparateNote is null || nextSeparateNote.tick >= spEndTick)
{
flags |= NoteFlags.StarPowerEnd;
}
}
}

// The tick this note has ended
uint noteFinishTick = moonNote.tick + moonNote.length;
if(nextSeparateNote is not null && nextSeparateNote.tick < noteFinishTick) {
flags |= NoteFlags.ExtendedSustain;
}
if (moonNote.isChord) {
flags |= NoteFlags.Chord;
}

// Length of the note in realtime
double timeLength = song.TickToTime(moonNote.tick + moonNote.length, song.resolution) - moonNote.time;

int fret = MoonGuitarNoteToFret(moonNote);
var currentNote = new GuitarNote(previousSeparateGameNote, moonNote.time, timeLength, moonNote.tick,
moonNote.length, fret, moonNote.type, flags);

// First note, must be a parent note
if (previousGameNote is null) {
parentNote = currentNote;

previousGameNote = currentNote;
notes.Add(currentNote);
var note = new NoteInfo {
time = (float)moonNote.time,
length = (float)timeLength,
fret = moonNote.rawNote,
hopo = moonNote.type == MoonNote.MoonNoteType.Hopo,
tap = moonNote.type == MoonNote.MoonNoteType.Tap,
};

continue;
}

// Ticks don't match previous game note
if (previousGameNote.Tick != currentNote.Tick) {
parentNote = currentNote;

previousSeparateGameNote = previousGameNote;

previousSeparateGameNote.nextNote = currentNote;
currentNote.previousNote = previousSeparateGameNote;

notes.Add(currentNote);
} else {
// Add as a child note if ticks match
parentNote.AddChildNote(currentNote);
}

previousGameNote = currentNote;
notes.Add(note);
}

return notes;
}

private static int MoonGuitarNoteToFret(MoonNote note) {
return note.guitarFret switch {
MoonNote.GuitarFret.Open => 0,
MoonNote.GuitarFret.Green => 1,
MoonNote.GuitarFret.Red => 2,
MoonNote.GuitarFret.Yellow => 3,
MoonNote.GuitarFret.Blue => 4,
MoonNote.GuitarFret.Orange => 5,
_ => 1
};
}

}
}
}
}
14 changes: 3 additions & 11 deletions Assets/Script/Chart/Loaders/GuitarChartLoader.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Assets/Script/Chart/Loaders/IChartLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using MoonscraperChartEditor.Song;

namespace YARG.Chart {
public interface IChartLoader<T> where T : Note {
public interface IChartLoader<T> {

public List<T> GetNotesFromChart(MoonSong song, MoonChart chart);

Expand Down
3 changes: 3 additions & 0 deletions Assets/Script/Chart/Loaders/New.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
using MoonscraperChartEditor.Song;

namespace YARG.Chart {
public class DrumChartLoader : IChartLoader<DrumNote> {
public class NewDrumChartLoader : IChartLoader<DrumNote> {

private readonly bool _isPro;
private readonly bool _isDoubleBass;

public DrumChartLoader(bool isPro, bool doubleBass) {
public NewDrumChartLoader(bool isPro, bool doubleBass) {
_isPro = isPro;
_isDoubleBass = doubleBass;
}
Expand Down
Loading

0 comments on commit 1f58b5a

Please sign in to comment.