Skip to content

Commit 712b1d6

Browse files
authored
Merge pull request #36 from neogeek/feature/calculate-beat-bars
[feat] Added CalculateBeatBars method.
2 parents 6f0f415 + 62baf6f commit 712b1d6

File tree

11 files changed

+238
-102
lines changed

11 files changed

+238
-102
lines changed

RhythmGameUtilities.Tests/Mocks/song.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

RhythmGameUtilities.Tests/UtilitiesTest.cs

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using NUnit.Framework;
34

@@ -22,18 +23,19 @@ public void TestConvertSecondsToTicks()
2223
const int seconds = 5;
2324
const int resolution = 192;
2425

26+
var bpmChanges = new Dictionary<int, int>
27+
{
28+
{ 0, 88000 },
29+
{ 3840, 112000 },
30+
{ 9984, 89600 },
31+
{ 22272, 112000 },
32+
{ 33792, 111500 },
33+
{ 34560, 112000 },
34+
{ 42240, 111980 }
35+
};
36+
2537
Assert.That(
26-
Utilities.ConvertSecondsToTicks(seconds, resolution,
27-
new Dictionary<int, int>
28-
{
29-
{ 0, 88000 },
30-
{ 3840, 112000 },
31-
{ 9984, 89600 },
32-
{ 22272, 112000 },
33-
{ 33792, 111500 },
34-
{ 34560, 112000 },
35-
{ 42240, 111980 }
36-
}), Is.EqualTo(1408));
38+
Utilities.ConvertSecondsToTicks(seconds, resolution, bpmChanges), Is.EqualTo(1408));
3739
}
3840

3941
[Test]
@@ -66,6 +68,28 @@ public void TestInverseLerp()
6668
Assert.That(Utilities.InverseLerp(0, 10, 10), Is.EqualTo(1));
6769
}
6870

71+
[Test]
72+
public void TestCalculateBeatBars()
73+
{
74+
const int resolution = 192;
75+
const int timeSignature = 4;
76+
77+
var bpmChanges = new Dictionary<int, int>
78+
{
79+
{ 0, 88000 },
80+
{ 3840, 112000 },
81+
{ 9984, 89600 },
82+
{ 22272, 112000 },
83+
{ 33792, 111500 },
84+
{ 34560, 112000 },
85+
{ 42240, 111980 }
86+
};
87+
88+
var beatBars = Utilities.CalculateBeatBars(bpmChanges, resolution, timeSignature, true);
89+
90+
Assert.That(beatBars.Count, Is.EqualTo(446));
91+
}
92+
6993
}
7094

7195
}

RhythmGameUtilities/Scripts/Utilities.cs

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ public static extern int ConvertSecondsToTicksInternal(float seconds, int resolu
6464
#endif
6565
public static extern float InverseLerp(float a, float b, float v);
6666

67+
#if WINDOWS_BUILD || UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
68+
[DllImport("libRhythmGameUtilities.dll", CallingConvention = CallingConvention.Cdecl)]
69+
#elif MACOS_BUILD || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
70+
[DllImport("libRhythmGameUtilities.dylib", CallingConvention = CallingConvention.Cdecl)]
71+
#elif LINUX_BUILD || UNITY_EDITOR_LINUX || UNITY_STANDALONE_LINUX
72+
[DllImport("libRhythmGameUtilities.so", CallingConvention = CallingConvention.Cdecl)]
73+
#endif
74+
public static extern IntPtr CalculateBeatBarsInternal(int[] bpmChangesKeys,
75+
int[] bpmChangesValues, int bpmChangesSize, int resolution, int ts,
76+
bool includeHalfNotes, out int size);
77+
6778
}
6879

6980
public static class Utilities
@@ -107,46 +118,21 @@ public static List<BeatBar> CalculateBeatBars(Dictionary<int, int> bpmChanges, i
107118
{
108119
var beatBars = new List<BeatBar>();
109120

110-
var keyValuePairs = GenerateAdjacentKeyPairs(bpmChanges);
121+
var ptrArray = UtilitiesInternal.CalculateBeatBarsInternal(bpmChanges.Keys.ToArray(),
122+
bpmChanges.Values.ToArray(), bpmChanges.Count, resolution, ts, includeHalfNotes,
123+
out var size);
111124

112-
foreach (var (startTick, endTick) in keyValuePairs)
113-
{
114-
for (var tick = startTick; tick <= endTick; tick += resolution)
115-
{
116-
beatBars.Add(new BeatBar
117-
{
118-
Position = tick, BPM = bpmChanges[startTick], TimeSignature = new[] { ts }
119-
});
120-
121-
if (includeHalfNotes && tick != endTick)
122-
{
123-
beatBars.Add(new BeatBar
124-
{
125-
Position = tick + resolution / 2,
126-
BPM = bpmChanges[startTick],
127-
TimeSignature = new[] { ts }
128-
});
129-
}
130-
}
131-
}
125+
var beatBarSize = Marshal.SizeOf(typeof(BeatBar));
132126

133-
return beatBars;
134-
}
135-
136-
public static List<Tuple<T, T>> GenerateAdjacentKeyPairs<T>(Dictionary<T, T> dictionary)
137-
{
138-
var keys = dictionary.Keys.ToList();
139-
140-
keys.Sort();
141-
142-
var adjacentKeyPairs = new List<Tuple<T, T>>();
143-
144-
for (var i = 0; i < keys.Count - 1; i += 1)
127+
for (var i = 0; i < size; i += 1)
145128
{
146-
adjacentKeyPairs.Add(new Tuple<T, T>(keys[i], keys[i + 1]));
129+
var beatBarSizePtr = new IntPtr(ptrArray.ToInt64() + beatBarSize * i);
130+
var beatBar = Marshal.PtrToStructure<BeatBar>(beatBarSizePtr);
131+
132+
beatBars.Add(beatBar);
147133
}
148134

149-
return adjacentKeyPairs;
135+
return beatBars;
150136
}
151137

152138
}

RhythmGameUtilities/Structs/BeatBar.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ public struct BeatBar
1111

1212
public int BPM;
1313

14-
public int[] TimeSignature;
15-
1614
}
1715

1816
}

UnityPackage/Editor/Tests/UtilitiesTest.cs

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using NUnit.Framework;
34

@@ -22,18 +23,19 @@ public void TestConvertSecondsToTicks()
2223
const int seconds = 5;
2324
const int resolution = 192;
2425

26+
var bpmChanges = new Dictionary<int, int>
27+
{
28+
{ 0, 88000 },
29+
{ 3840, 112000 },
30+
{ 9984, 89600 },
31+
{ 22272, 112000 },
32+
{ 33792, 111500 },
33+
{ 34560, 112000 },
34+
{ 42240, 111980 }
35+
};
36+
2537
Assert.That(
26-
Utilities.ConvertSecondsToTicks(seconds, resolution,
27-
new Dictionary<int, int>
28-
{
29-
{ 0, 88000 },
30-
{ 3840, 112000 },
31-
{ 9984, 89600 },
32-
{ 22272, 112000 },
33-
{ 33792, 111500 },
34-
{ 34560, 112000 },
35-
{ 42240, 111980 }
36-
}), Is.EqualTo(1408));
38+
Utilities.ConvertSecondsToTicks(seconds, resolution, bpmChanges), Is.EqualTo(1408));
3739
}
3840

3941
[Test]
@@ -66,6 +68,28 @@ public void TestInverseLerp()
6668
Assert.That(Utilities.InverseLerp(0, 10, 10), Is.EqualTo(1));
6769
}
6870

71+
[Test]
72+
public void TestCalculateBeatBars()
73+
{
74+
const int resolution = 192;
75+
const int timeSignature = 4;
76+
77+
var bpmChanges = new Dictionary<int, int>
78+
{
79+
{ 0, 88000 },
80+
{ 3840, 112000 },
81+
{ 9984, 89600 },
82+
{ 22272, 112000 },
83+
{ 33792, 111500 },
84+
{ 34560, 112000 },
85+
{ 42240, 111980 }
86+
};
87+
88+
var beatBars = Utilities.CalculateBeatBars(bpmChanges, resolution, timeSignature, true);
89+
90+
Assert.That(beatBars.Count, Is.EqualTo(446));
91+
}
92+
6993
}
7094

7195
}

UnityPackage/Scripts/Utilities.cs

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ public static extern int ConvertSecondsToTicksInternal(float seconds, int resolu
6464
#endif
6565
public static extern float InverseLerp(float a, float b, float v);
6666

67+
#if WINDOWS_BUILD || UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
68+
[DllImport("libRhythmGameUtilities.dll", CallingConvention = CallingConvention.Cdecl)]
69+
#elif MACOS_BUILD || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
70+
[DllImport("libRhythmGameUtilities.dylib", CallingConvention = CallingConvention.Cdecl)]
71+
#elif LINUX_BUILD || UNITY_EDITOR_LINUX || UNITY_STANDALONE_LINUX
72+
[DllImport("libRhythmGameUtilities.so", CallingConvention = CallingConvention.Cdecl)]
73+
#endif
74+
public static extern IntPtr CalculateBeatBarsInternal(int[] bpmChangesKeys,
75+
int[] bpmChangesValues, int bpmChangesSize, int resolution, int ts,
76+
bool includeHalfNotes, out int size);
77+
6778
}
6879

6980
public static class Utilities
@@ -107,46 +118,21 @@ public static List<BeatBar> CalculateBeatBars(Dictionary<int, int> bpmChanges, i
107118
{
108119
var beatBars = new List<BeatBar>();
109120

110-
var keyValuePairs = GenerateAdjacentKeyPairs(bpmChanges);
121+
var ptrArray = UtilitiesInternal.CalculateBeatBarsInternal(bpmChanges.Keys.ToArray(),
122+
bpmChanges.Values.ToArray(), bpmChanges.Count, resolution, ts, includeHalfNotes,
123+
out var size);
111124

112-
foreach (var (startTick, endTick) in keyValuePairs)
113-
{
114-
for (var tick = startTick; tick <= endTick; tick += resolution)
115-
{
116-
beatBars.Add(new BeatBar
117-
{
118-
Position = tick, BPM = bpmChanges[startTick], TimeSignature = new[] { ts }
119-
});
120-
121-
if (includeHalfNotes && tick != endTick)
122-
{
123-
beatBars.Add(new BeatBar
124-
{
125-
Position = tick + resolution / 2,
126-
BPM = bpmChanges[startTick],
127-
TimeSignature = new[] { ts }
128-
});
129-
}
130-
}
131-
}
125+
var beatBarSize = Marshal.SizeOf(typeof(BeatBar));
132126

133-
return beatBars;
134-
}
135-
136-
public static List<Tuple<T, T>> GenerateAdjacentKeyPairs<T>(Dictionary<T, T> dictionary)
137-
{
138-
var keys = dictionary.Keys.ToList();
139-
140-
keys.Sort();
141-
142-
var adjacentKeyPairs = new List<Tuple<T, T>>();
143-
144-
for (var i = 0; i < keys.Count - 1; i += 1)
127+
for (var i = 0; i < size; i += 1)
145128
{
146-
adjacentKeyPairs.Add(new Tuple<T, T>(keys[i], keys[i + 1]));
129+
var beatBarSizePtr = new IntPtr(ptrArray.ToInt64() + beatBarSize * i);
130+
var beatBar = Marshal.PtrToStructure<BeatBar>(beatBarSizePtr);
131+
132+
beatBars.Add(beatBar);
147133
}
148134

149-
return adjacentKeyPairs;
135+
return beatBars;
150136
}
151137

152138
}

UnityPackage/Structs/BeatBar.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ public struct BeatBar
1111

1212
public int BPM;
1313

14-
public int[] TimeSignature;
15-
1614
}
1715

1816
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
3+
struct BeatBar
4+
{
5+
6+
int Position;
7+
8+
int BPM;
9+
};

includes/RhythmGameUtilities/Utilities.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "Utilities.h"
1111

12+
#include "Structs/BeatBar.h"
1213
#include "Structs/Note.h"
1314

1415
const float SECONDS_PER_MINUTE = 60.0f;
@@ -111,6 +112,62 @@ std::vector<std::string> Split(const char *contents, const char delimiter)
111112
return parts;
112113
}
113114

115+
std::vector<BeatBar> CalculateBeatBars(std::map<int, int> bpmChanges,
116+
int resolution, int ts,
117+
bool includeHalfNotes)
118+
{
119+
std::vector<BeatBar> beatBars;
120+
121+
auto keyValuePairs = GenerateAdjacentKeyPairs(bpmChanges);
122+
123+
for (const auto &keyValuePair : keyValuePairs)
124+
{
125+
auto startTick = std::get<0>(keyValuePair);
126+
auto endTick = std::get<1>(keyValuePair);
127+
128+
for (auto tick = startTick; tick <= endTick; tick += resolution)
129+
{
130+
beatBars.push_back(
131+
{.Position = tick, .BPM = bpmChanges[startTick]});
132+
133+
if (includeHalfNotes && tick != endTick)
134+
{
135+
beatBars.push_back({.Position = tick + resolution / 2,
136+
.BPM = bpmChanges[startTick]});
137+
}
138+
}
139+
}
140+
141+
return beatBars;
142+
}
143+
144+
BeatBar *CalculateBeatBarsInternal(int *bpmChangesKeys, int *bpmChangesValues,
145+
int bpmChangesSize, int resolution, int ts,
146+
bool includeHalfNotes, int *outSize)
147+
{
148+
auto bpmChanges = std::map<int, int>();
149+
150+
for (auto i = 0; i < bpmChangesSize; i += 1)
151+
{
152+
bpmChanges[bpmChangesKeys[i]] = bpmChangesValues[i];
153+
}
154+
155+
auto internalBeatBars =
156+
CalculateBeatBars(bpmChanges, resolution, ts, includeHalfNotes);
157+
158+
*outSize = internalBeatBars.size();
159+
160+
auto beatBars =
161+
(BeatBar *)malloc(internalBeatBars.size() * sizeof(BeatBar));
162+
163+
for (auto i = 0; i < internalBeatBars.size(); i += 1)
164+
{
165+
beatBars[i] = internalBeatBars[i];
166+
}
167+
168+
return beatBars;
169+
}
170+
114171
std::vector<std::tuple<int, int>>
115172
GenerateAdjacentKeyPairs(std::map<int, int> keyValuePairs)
116173
{

0 commit comments

Comments
 (0)