Initial commit

This commit is contained in:
muskit
2023-07-30 00:22:03 -07:00
commit 8e6966bfcd
39 changed files with 1417 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 25140b91ea8636ea5acb3ff90421f11a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+332
View File
@@ -0,0 +1,332 @@
using System;
using System.Linq;
using System.Collections.Generic;
using WacK.Data.Mer;
using Godot;
namespace WacK.Data.Chart
{
/// <summary>
/// Chart data.
/// </summary>
public class Chart
{
public static bool doneLoading { get; private set; } = false;
// [ms] = List<Note> (list for chord marking creation)
public SortedList<float, List<NotePlay>> playNotes { get; private set; }
public SortedList<float, NoteEvent<(int, int)>> timeSigChgs { get; private set; }
public SortedList<float, NoteEvent<float>> tempoChgs { get; private set; }
public SortedList<float, NoteEvent<int>> events { get; private set; }
public Chart()
{
doneLoading = false;
}
// place notes and events relative to the previous
public void Load(Mer.Mer chart)
{
playNotes = new SortedList<float, List<NotePlay>>();
List<float> tempo = new List<float>();
List<int> tempoChangeMeasures = new List<int>();
List<int> tempoChangeBeats = new List<int>();
// TODO: switch to MeasureBeat
List<int> beatsPerMeasure = new List<int>();
List<int> bpmChangeMeasures = new List<int>();
tempo.Add(0);
tempoChangeMeasures.Add(0);
tempoChangeBeats.Add(0);
beatsPerMeasure.Add(0);
bpmChangeMeasures.Add(0);
float queuedTempo = -1;
int queuedBPM = -1;
// timing info of the previous beat
float prevTime = 0;
int prevMeasure = 0;
int prevBeat = 0; // (/1920 beats per measure)
Note prevNote = null;
Note curNote = null;
var prevHoldPoint = new System.Collections.Generic.Dictionary<int, NotePlay>(); // <note idx, previous point of hold>
var curHoldNote = new System.Collections.Generic.Dictionary<int, NoteHold>(); // <next hold idx, HoldStart>
// Notes and Events //
foreach (var measure in chart.notes) // `measure` = measure: List
{
foreach (var chartNote in measure.Value) // `chartNote` = beat, ChartNote
{
var curTime = prevTime + Util.NoteTime(measure.Key - prevMeasure, chartNote.Item1 - prevBeat, tempo.Last<float>(), beatsPerMeasure.Last<int>());
var mb = new MeasureBeat(measure.Key, chartNote.Item1);
if (prevMeasure != measure.Key && prevBeat != chartNote.Item1)
{
if (queuedTempo != -1)
{
tempo.Add(queuedTempo);
tempoChangeMeasures.Add(measure.Key);
tempoChangeBeats.Add(chartNote.Item1);
queuedTempo = -1;
}
if (queuedBPM != -1)
{
beatsPerMeasure.Add(queuedBPM);
bpmChangeMeasures.Add(measure.Key);
queuedBPM = -1;
}
}
// notetype-dependent operations
switch (chartNote.Item2.noteType)
{
// Beat map data
case MerType.Tempo:
if (tempo.Count == 1)
{
tempo.Add(float.Parse(chartNote.Item2.value));
tempoChangeMeasures.Add(measure.Key);
tempoChangeBeats.Add(chartNote.Item1);
}
else
queuedTempo = float.Parse(chartNote.Item2.value);
this.tempoChgs.Add(
curTime,
new NoteEvent<float> (
curTime, mb,
NoteEventType.Tempo,
value: float.Parse(chartNote.Item2.value)
));
break;
case MerType.TimeSignature:
var words = chartNote.Item2.value.Split();
var nu = int.Parse(words[0]);
var de = int.Parse(words[1]);
if (beatsPerMeasure.Count == 1)
{
beatsPerMeasure.Add(int.Parse(chartNote.Item2.value));
bpmChangeMeasures.Add(measure.Key);
}
else
queuedBPM = int.Parse(chartNote.Item2.value);
this.timeSigChgs.Add(
curTime,
new NoteEvent<(int, int)> (
curTime, mb,
NoteEventType.TimeSignature,
value: (nu, de)
));
break;
// Playable notes
case MerType.Touch:
curNote = new NotePlay(
curTime, mb,
chartNote.Item2.position, chartNote.Item2.size
);
break;
case MerType.HoldStart:
curNote = new NoteHold(
curTime, mb,
chartNote.Item2.position, chartNote.Item2.size,
holdIndex: chartNote.Item2.holdIdx,
holdNext: chartNote.Item2.holdNextIdx
);
var nh = curNote as NoteHold;
prevHoldPoint[chartNote.Item2.holdNextIdx] = (NotePlay) curNote;
curHoldNote[chartNote.Item2.holdNextIdx] = nh;
break;
case MerType.HoldMid:
curNote = new NotePlay(
curTime, mb,
chartNote.Item2.position, chartNote.Item2.size,
type: NotePlayType.HoldMid,
holdIndex: chartNote.Item2.holdIdx,
holdNext: chartNote.Item2.holdNextIdx
);
prevHoldPoint[chartNote.Item2.holdNextIdx] = (NotePlay) curNote;
curHoldNote[chartNote.Item2.holdNextIdx] = curHoldNote[chartNote.Item2.holdIdx];
break;
case MerType.HoldEnd: // TODO: draw end note on cone texture
curNote = new NotePlay(
curTime, mb,
chartNote.Item2.position, chartNote.Item2.size,
type: NotePlayType.HoldEnd,
holdIndex: chartNote.Item2.holdIdx
);
break;
case MerType.Untimed:
curNote = new NotePlay(
curTime, mb,
chartNote.Item2.position, chartNote.Item2.size,
type: NotePlayType.Untimed
);
break;
case MerType.SwipeIn:
curNote = new NotePlay(
curTime, mb,
chartNote.Item2.position, chartNote.Item2.size,
type: NotePlayType.SwipeIn
);
break;
case MerType.SwipeOut:
curNote = new NotePlay(
curTime, mb,
chartNote.Item2.position, chartNote.Item2.size,
type: NotePlayType.SwipeOut
);
break;
case MerType.SwipeCW:
curNote = new NotePlay(
curTime, mb,
chartNote.Item2.position, chartNote.Item2.size,
type: NotePlayType.SwipeCW
);
break;
case MerType.SwipeCCW:
curNote = new NotePlay(
curTime, mb,
chartNote.Item2.position, chartNote.Item2.size,
type: NotePlayType.SwipeCCW
);
break;
// Events (invisible modifier notes)
case MerType.BGAdd:
curNote = new NoteEvent<int>(
curTime, mb,
NoteEventType.BGAdd,
chartNote.Item2.position, chartNote.Item2.size,
value: int.Parse(chartNote.Item2.value)
);
break;
case MerType.BGRem:
curNote = new NoteEvent<int>(
curTime, mb,
NoteEventType.BGRem,
chartNote.Item2.position, chartNote.Item2.size,
value: int.Parse(chartNote.Item2.value)
);
break;
}
if (curNote == null || curNote == prevNote) continue;
/* Handle our crafted curNote, storing it somewhere in this Chart */
// NotePlay
var np = curNote as NotePlay;
if (np != null)
{
// hold point handling
if (np.type == NotePlayType.HoldMid || np.type == NotePlayType.HoldEnd)
{
curHoldNote[np.holdIdx].points[curTime] = np;
}
// add note
if (!playNotes.ContainsKey(curTime))
{
playNotes[curTime] = new List<NotePlay>();
}
playNotes[curTime].Add(np);
}
// NoteEvent<float> -- tempo changes
var nef = curNote as NoteEvent<float>;
if (nef != null)
{
if (nef.type == NoteEventType.Tempo)
this.tempoChgs[curTime] = nef;
else
GD.Print($"Didn't add NoteEvent<float> of type {nef.type}");
}
// NoteEvent<(int, int)> -- time signature changes
var neii = curNote as NoteEvent<(int, int)>;
if (neii != null)
{
this.timeSigChgs[curTime] = neii;
}
// NoteEvent<int>
var nei = curNote as NoteEvent<int>;
if (nei != null)
{
this.events[curTime] = nei;
}
// update previous states
prevNote = curNote;
prevTime = curTime;
prevBeat = chartNote.Item1;
prevMeasure = measure.Key;
}
}
// chords
foreach (KeyValuePair<float, List<NotePlay>> pair in playNotes)
{
List<Note> chordableNotes = new List<Note>();
foreach (NotePlay n in pair.Value)
{
if (n.type != NotePlayType.HoldEnd && n.type != NotePlayType.Untimed)
if (!(new NotePlayType[] { NotePlayType.HoldEnd, NotePlayType.Untimed, NotePlayType.HoldMid }).Contains(n.type))
chordableNotes.Add(n);
}
if (chordableNotes.Count >= 2)
{
GD.Print($"Found chord: {string.Join(", ", chordableNotes)}");
// TODO: draw chord indicators "Chordify"
}
}
// Measure Lines //
// TODO: adapt to tempo changes in the middle of a measure
// int tempoIdx = 1;
// int bpmIdx = 1;
// for (int curMeasure = 0; curMeasure < chart.notes.Count; curMeasure++)
// {
// while (curMeasure >= bpmChangeMeasures[bpmIdx] && bpmIdx < bpmChangeMeasures.Count - 1)
// ++bpmIdx;
// GD.Print($"{curMeasure}: {bpmIdx}");
// // last tempo change / only one tempo change exists
// if (tempoIdx == tempoChangeMeasures.Count - 1)
// {
// float pos = tempoChangePositions[tempoIdx] + Util.NotePosition(curMeasure - tempoChangeMeasures[tempoIdx], 0, tempo.Last(), beatsPerMeasure[bpmIdx]);
// var ml = measureLine.Instance<MeasureLine>();
// measureScroll.AddChild(ml);
// ml.Translation = new Vector3(0, 0, pos);
// ml.Text = $"{curMeasure}";
// }
// else if (tempoIdx < tempoChangeMeasures.Count)
// {
// // TODO: adapt to key signature changes
// while (curMeasure == tempoChangeMeasures[tempoIdx])
// {
// int measuresToCreate = tempoChangeMeasures[tempoIdx] - tempoChangeMeasures[tempoIdx - 1];
// for (int i = 0; i < measuresToCreate; ++i)
// {
// int measureNum = tempoChangeMeasures[tempoIdx - 1] + i;
// // GD.Print($"{tempoIdx} / {tempoChangePositions.Count}, {tempo.Count}");
// float pos = Util.InterpFloat(tempoChangePositions[tempoIdx - 1], tempoChangePositions[tempoIdx], (float)i/measuresToCreate);
// var ml = measureLine.Instance<MeasureLine>();
// measureScroll.AddChild(ml);
// ml.Translation = new Vector3(0, 0, pos);
// ml.Text = $"{curMeasure}";
// }
// tempoIdx = Mathf.Clamp(tempoIdx + 1, 0, tempo.Count - 1);
// }
// }
// }
doneLoading = true;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 562cc671f5a30839c8769855d8d0483f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+9
View File
@@ -0,0 +1,9 @@
using System;
namespace WacK.Data.Chart
{
public enum DifficultyLevel
{
Normal, Hard, Expert, Inferno
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02342af085b6384489297bdfaaff13f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+121
View File
@@ -0,0 +1,121 @@
using System;
namespace WacK.Data.Chart
{
/// <summary>
/// Represents a non-timed chart position in measure and beat as a fraction of the measure.
/// </summary>
public class MeasureBeat
{
public const int DENOMINATOR = 1920;
public int measure { get; private set; }
/// <summary>
/// Beat in the measure, represented as beat/1920 of a measure.
/// </summary>
public int beat { get; private set; }
public MeasureBeat(int measure, int beat)
{
this.measure = measure;
this.beat = beat;
Normalize();
}
public void Normalize()
{
// beats larger than denominator
if (Math.Abs(beat) >= DENOMINATOR)
{
measure += beat / DENOMINATOR;
beat %= DENOMINATOR;
}
// positive measure, negative beats
if (beat < 0 && measure > 0)
{
measure--;
beat += DENOMINATOR;
}
}
public override string ToString()
{
return $"MeasureBeat({this.measure}, {this.beat}/{DENOMINATOR})";
}
public override int GetHashCode()
{
return measure*DENOMINATOR + beat;
}
public override bool Equals(object tgt)
{
if (tgt == null) return false;
return this == (MeasureBeat)tgt;
}
/* STATIC CONSTANTS */
public readonly static MeasureBeat ZERO = new MeasureBeat(0, 0);
/* STATIC OPERATORS */
public static MeasureBeat operator +(MeasureBeat a) => a;
public static MeasureBeat operator -(MeasureBeat a)
=> new MeasureBeat(-a.measure, -a.beat);
public static MeasureBeat operator +(MeasureBeat a, MeasureBeat b)
{
var meas = a.measure + b.measure;
var beat = a.beat + b.beat;
return new MeasureBeat(meas, beat);
}
public static MeasureBeat operator -(MeasureBeat a, MeasureBeat b)
{
return a + -b;
}
public static bool operator ==(MeasureBeat a, MeasureBeat b)
{
return a.measure == b.measure && a.beat == b.beat;
}
public static bool operator !=(MeasureBeat a, MeasureBeat b)
{
return !(a == b);
}
public static bool operator <(MeasureBeat a, MeasureBeat b)
{
if (a.measure < b.measure) return true;
if (a.measure == b.measure)
{
return a.beat < b.beat;
}
return false;
}
public static bool operator >(MeasureBeat a, MeasureBeat b)
{
if (a != b)
{
return !(a < b);
}
return false;
}
public static bool operator <=(MeasureBeat a, MeasureBeat b)
{
if (a == b) return true;
return a < b;
}
public static bool operator >=(MeasureBeat a, MeasureBeat b)
{
if (a == b) return true;
return a > b;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f19917e007c0523e9a5ccccea23e9524
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+43
View File
@@ -0,0 +1,43 @@
using System.Collections.Generic;
namespace WacK.Data.Chart
{
/// <summary>
/// Base class for various in-play note types.
/// </summary>
public abstract class Note
{
/// <summary>
/// Time in milliseconds which the note occurs.
/// </summary>
public double time = 0;
/// <summary>
/// Time of the note in MeasureBeat.
/// </summary>
public MeasureBeat measureBeat;
/// <summary>
/// The note's radial position out of 60.
/// </summary>
public int? position;
/// <summary>
/// The radial size of the note.
/// 1 <= size <= 60
/// </summary>
public int? size;
public Note(double time, MeasureBeat measureBeat, int? position = null, int? size = null)
{
this.time = time;
this.measureBeat = measureBeat;
this.position = position;
this.size = size;
}
public Note()
{
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1ed8bb3e1326d18f9927b087b6e8fe7c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+36
View File
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
namespace WacK.Data.Chart
{
public enum NoteEventType
{
Tempo,
TimeSignature,
ScrollSpeedMultiplier,
BGAdd,
BGRem,
}
/// <summary>
/// Represents an unplayable event with some associated data value.
/// </summary>
/// <typeparam name="T">The value's type.</typeparam>
public class NoteEvent<T> : Note
{
public NoteEventType type;
/// <summary>
/// A value whose function will vary depending on the type of note.
/// </summary>
public T value;
public NoteEvent(double time, MeasureBeat measureBeat, NoteEventType type, int? position = null, int? size = null, T value = default(T)) :
base(time, measureBeat, position, size)
{
this.value = value;
this.type = type;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f133260cfe1efeb06bc84818f1f694c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+20
View File
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace WacK.Data.Chart
{
/// <summary>
/// A hold note. Notably contains data about hold points.
/// </summary>
public class NoteHold : NotePlay
{
public SortedList<float, NotePlay> points;
public NoteHold(double time, MeasureBeat measureBeat, int position, int size, int holdIndex, int holdNext, bool bonus = false)
: base(time, measureBeat, position, size,holdIndex, holdNext, type: NotePlayType.HoldStart, bonus: false)
{
// points = (SortedList<float, Note>)holdPoints.Skip(1);
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 74c839480bb719c9b96e11709817d2e6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+38
View File
@@ -0,0 +1,38 @@
using System.Collections.Generic;
namespace WacK.Data.Chart
{
public enum NotePlayType
{
Touch,
HoldStart,
HoldMid,
HoldEnd,
Untimed,
SwipeIn,
SwipeOut,
SwipeCW,
SwipeCCW,
}
/// <summary>
/// Represents playable notes.
/// </summary>
public class NotePlay : Note
{
public NotePlayType type { get; private set; }
public bool isBonus { get; private set; }
public int holdIdx { get; private set; }
public int holdNextIdx { get; private set; }
public NotePlay(double time, MeasureBeat measureBeat, int position, int size, int holdIndex = -1, int holdNext = -1,
NotePlayType type = NotePlayType.Touch, bool bonus = false)
: base(time, measureBeat, position, size)
{
this.type = type;
this.isBonus = bonus;
this.holdIdx = holdIndex;
this.holdNextIdx = holdNext;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ccfc6a251580ee67a83e2269870a227c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0ed6e3a31145daf8597c9bd80394d64d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+146
View File
@@ -0,0 +1,146 @@
/**
* Chart.cs
* Representation of a chart, constructed from a .mer file.
*
* by muskit
* July 1, 2022
**/
using System;
using System.Collections.Generic;
namespace WacK.Data.Mer
{
/// <summary>
/// Structurized representation of a .mer file.
/// </summary>
public class Mer
{
/// <summary>
/// HIERARCHY:
/// Key is measure.
/// Value is List of (beat/1920, Notes) tuples.
/// </summary>
public SortedList<int, List<(int, MerNote)>> notes = new SortedList<int, List<(int, MerNote)>>();
public int playableNoteCount { get; private set; }
/// <summary>
/// Construct Chart from contents of .mer file.
/// </summary>
/// <param name="str">Contents of a .mer file.</param>
public Mer(string str)
{
if (str == String.Empty) return;
playableNoteCount = 0;
List<string> lines = new List<string>(str.Split('\n'));
foreach (var line in lines)
{
List<string> tokens = new List<string>(line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries));
if (tokens.Count == 0) continue;
if (tokens[0][0] == '#') continue;
int currentMeasure = int.Parse(tokens[0]);
int currentBeat = int.Parse(tokens[1]);
if (!notes.ContainsKey(currentMeasure))
{
notes[currentMeasure] = new List<(int, MerNote)>();
}
switch (tokens[2])
{
case "1": // common note types
switch(tokens[3])
{
case "1": // touch
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.Touch)));
++playableNoteCount;
break;
case "2": // touch w/ bonus
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.Touch, bonus: true)));
++playableNoteCount;
break;
case "20": // touch w/ bonus (+ "big effect")
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.Touch, bonus: true)));
++playableNoteCount;
break;
case "16": // untimed
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.Untimed)));
++playableNoteCount;
break;
case "26": // untimed w/ bonus
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.Untimed, bonus: true)));
++playableNoteCount;
break;
case "3": // swipe in (red)
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeIn)));
++playableNoteCount;
break;
case "21": // swipe in w/ bonus
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeIn, bonus: true)));
++playableNoteCount;
break;
case "4": // swipe out (blue)
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeOut)));
++playableNoteCount;
break;
case "22": // swipe out w/ bonus
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeOut, bonus: true)));
++playableNoteCount;
break;
case "7": // swipe CCW
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeCCW)));
++playableNoteCount;
break;
case "8": // swipe CCW w/ bonus
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeCCW, bonus: true)));
++playableNoteCount;
break;
case "5": // swipe CW
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeCW)));
++playableNoteCount;
break;
case "6": // swipe CW w/ bonus
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeCW, bonus: true)));
++playableNoteCount;
break;
case "9": // hold start
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), holdIndex: int.Parse(tokens[4]), holdNext: int.Parse(tokens[8]), type: MerType.HoldStart)));
break;
case "25": // hold start (w/ bonus)
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), holdIndex: int.Parse(tokens[4]), holdNext: int.Parse(tokens[8]), type: MerType.HoldStart, bonus: true)));
++playableNoteCount;
break;
case "10": // hold middle
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), holdIndex: int.Parse(tokens[4]), holdNext: int.Parse(tokens[8]), type: MerType.HoldMid)));
break;
case "11": // hold end
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), holdIndex: int.Parse(tokens[4]), type: MerType.HoldEnd)));
break;
case "12": // BG add
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), value: tokens[8], type: MerType.BGAdd)));
break;
case "13": // BG rem
notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), value: tokens[8], type: MerType.BGRem)));
break;
}
break;
case "2": // tempo
notes[currentMeasure].Add((currentBeat, new MerNote(value: tokens[3], type: MerType.Tempo)));
break;
case "3": // beats per measure
notes[currentMeasure].Add((currentBeat, new MerNote(value: $"{tokens[3]} {tokens[4]}", type: MerType.TimeSignature)));
break;
}
}
foreach (var measure in notes)
{
measure.Value.Sort((x, y) => x.Item1.CompareTo(y.Item1));
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 03f65fd134dbd18faba49dbb870b3450
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+38
View File
@@ -0,0 +1,38 @@
/**
* Note.cs
* A struct representing a note.
*
* by muskit
* July 1, 2022
**/
namespace WacK.Data.Mer
{
public enum MerType
{
Touch, HoldStart, HoldMid, HoldEnd, Untimed, SwipeIn, SwipeOut, SwipeCW, SwipeCCW, Tempo, TimeSignature, BGAdd, BGRem
}
public struct MerNote
{
public MerType noteType { get; private set; }
public bool isBonus { get; private set; }
// Radial values in minutes
public int position { get; private set; }
public int size { get; private set; } // 1 <= size <= 60
public string value { get; private set; }
public int holdIdx { get; private set; }
public int holdNextIdx { get; private set; }
public MerNote(int position = 0, int size = 1, string value = "", int holdIndex = -1, int holdNext = -1, MerType type = MerType.Touch, bool bonus = false)
{
this.position = position;
this.size = size;
this.value = value;
this.holdIdx = holdIndex;
this.holdNextIdx = holdNext;
this.noteType = type;
this.isBonus = bonus;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f03d973b6879b96a5b79467d1dd3cbfc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: