1
0
mirror of https://github.com/SirusDoma/VoxCharger.git synced 2024-12-18 10:25:54 +01:00
VoxCharger/Sources/Events/Time.cs
2020-04-19 04:24:01 +07:00

173 lines
5.0 KiB
C#

using System;
namespace VoxCharger
{
public class Time
{
public int Measure { get; set; }
public int Beat { get; set; }
public int Offset { get; set; }
public Time()
: this(1, 1, 0)
{
}
public Time(int measure, int beat, int cell)
{
Measure = measure;
Beat = beat;
Offset = cell;
}
public static Time FromString(string input)
{
try
{
var data = input.Split(',');
if (data.Length != 3)
return null;
return new Time()
{
Measure = int.Parse(data[0]),
Beat = int.Parse(data[1]),
Offset = int.Parse(data[2])
};
}
catch (Exception)
{
return null;
}
}
public static Time FromOffset(float absOffset, (int beat, int note) signature)
{
float remaining = (absOffset % 192f) % (192f / signature.beat);
float division = ((192f / signature.beat) / signature.note);
int measure = (int)(absOffset / 192f);
int beat = (int)((absOffset % 192f) / (192f / signature.beat)) + 1;
int offset = (int)Math.Round((remaining / division) * ((192f / 4f) / 4f));
// Since the value rounded up, there's chance this happen (precision rounding problem)
beat += offset / 48;
offset %= 48;
measure += beat / signature.beat;
beat %= signature.beat;
if (beat == 0)
{
measure -= 1;
beat = signature.beat;
}
return new Time(measure, beat, offset);
}
public int GetAbsoluteOffset((int beat, int note) signature)
{
float offset = Measure * 192f;
offset += ((Beat - 1) * (192f / signature.beat));
offset += ((Offset / (192f / 4f)) * (192f / signature.beat));
return (int)Math.Round(offset);
}
public int Difference(Time time, (int beat, int note) signature)
{
// Only effective when both using same time signature
float tick = ((192f / 4f) * (4f / signature.note));
return (int)((Measure - time.Measure) * (tick * signature.beat) +
(Beat - time.Beat) * tick +
(Offset - time.Offset));
}
public Time Add(int position, (int beat, int note) signature)
{
int measure = Measure + (int)(position / 192f);
int beat = Beat + (int)((position % 192f) / (192f / signature.beat));
float absolute = (position % 192f) % (192f / signature.beat);
int offset = Offset + (int)Math.Round((absolute / ((192f / signature.beat) / signature.note)) * ((192f / 4f) / 4f));
beat += offset / 48;
offset %= 48;
measure += beat / signature.beat;
beat %= signature.beat;
if (beat == 0)
{
measure -= 1;
beat = signature.beat;
}
return new Time(measure, beat, offset);
}
public Time Add(Time time, (int beat, int note) signature)
{
int measure = Measure + time.Measure;
int beat = Beat + time.Beat;
int offset = Offset + time.Offset;
beat += offset / 48;
offset %= 48;
measure += beat / signature.beat;
beat %= signature.beat;
if (beat == 0)
{
measure -= 1;
beat = signature.beat;
}
return new Time(measure, beat, offset);
}
public static bool operator ==(Time a, Time b)
{
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
return ReferenceEquals(a, b);
return a.Measure == b.Measure && a.Beat == b.Beat && a.Offset == b.Offset;
}
public static bool operator !=(Time a, Time b)
{
if (ReferenceEquals(a, null) || ReferenceEquals(b, null))
return ReferenceEquals(a, b);
return a.Measure != b.Measure || a.Beat != b.Beat || a.Offset != b.Offset;
}
public static Time operator +(Time time, int position)
{
return time.Add(position, (4, 4));
}
public static Time operator +(Time a, Time b)
{
return a.Add(b, (4, 4));
}
public override bool Equals(object obj)
{
return obj is Time time && time == this;
}
public override int GetHashCode()
{
return Measure + Beat + Offset;
}
public override string ToString()
{
return $"{Measure:D3},{Beat:D2},{Offset:D2}";
}
}
}