diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs
new file mode 100644
index 0000000000..425f5a16a9
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/TaikoDifficultyHitObjectColour.cs
@@ -0,0 +1,78 @@
+namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing
+{
+ ///
+ /// Stores colour compression information for a .
+ ///
+ public class TaikoDifficultyHitObjectColour
+ {
+ const int max_repetition_interval = 16;
+
+ private TaikoDifficultyHitObjectColour previous;
+
+ ///
+ /// True if the current colour is different from the previous colour.
+ ///
+ public bool Delta { get; private set; }
+
+ ///
+ /// How many notes are Delta repeated
+ ///
+ public int DeltaRunLength { get; private set; }
+
+ ///
+ /// How many notes between the current and previous identical .
+ /// Negative number means that there is no repetition in range.
+ ///
+ public int RepetitionInterval { get; private set; }
+
+ ///
+ /// Get the instance for the given hitObject. This is implemented
+ /// as a static function instead of constructor to allow for reusing existing instances.
+ /// TODO: findRepetitionInterval needs to be called a final time after all hitObjects have been processed.
+ ///
+ public static TaikoDifficultyHitObjectColour GetInstanceFor(
+ TaikoDifficultyHitObject hitObject, TaikoDifficultyHitObject lastObject, TaikoDifficultyHitObjectColour previous)
+ {
+ bool delta = lastObject == null || hitObject.HitType != lastObject.HitType;
+ if (delta == previous.Delta)
+ {
+ previous.DeltaRunLength += 1;
+ return previous;
+ }
+ else
+ {
+ // Calculate RepetitionInterval for previous
+ previous.RepetitionInterval = findRepetitionInterval(previous);
+
+ return new TaikoDifficultyHitObjectColour()
+ {
+ Delta = delta,
+ DeltaRunLength = 1,
+ RepetitionInterval = -1,
+ previous = previous
+ };
+ }
+ }
+
+ ///
+ /// Finds the closest previous that has the identical delta value
+ /// and run length to target, and returns the amount of notes between them.
+ ///
+ private static int findRepetitionInterval(TaikoDifficultyHitObjectColour target) {
+ if (target.previous == null || target.previous.previous == null)
+ return -1;
+
+ int interval = target.previous.DeltaRunLength;
+ TaikoDifficultyHitObjectColour other = target.previous.previous;
+ while(other != null && interval < max_repetition_interval) {
+ if (other.Delta == target.Delta && other.DeltaRunLength == target.DeltaRunLength)
+ return interval;
+ else
+ interval += other.DeltaRunLength;
+ other = other.previous;
+ }
+
+ return -1;
+ }
+ }
+}
\ No newline at end of file