Patterns
Theory
To find patterns, we must:
Cluster Notes. Grouping
Find association between clusters. [Combinations ](#combinations
Remove unwanted associations. Filtering
Visualizing how it works
We'll walk through how our algorithm finds the A -> C Jack pattern.
Firstly, we group the notes into clusters. This is done by checking which notes have the same offset.
We see that A
and B
are on the same offset, thus they are grouped together.
Secondly, we find combinations between the groups. This is done by taking the cartesian product between groups. A <--> B is not a combination as they are in the same group.
Finally, we filter out unwanted combinations. In this case, we want to filter out all combinations that are not Jacks.
Input
To start, we initialize Pattern
in 2 ways:
Grouping
Horizontally: Grouping across columns of the same offset
Vertically: Grouping across offsets of the same column
Vertical & Horizontal Window
Windows define how far forward/sideways a note should look to group.
Consider the following marked X
If h_window=2, v_window=20
. All notes will be grouped as one, anything smaller will split them.
Avoid Jack
When grouping, you may want to avoid grouping jacks together
avoid_jack=True
prevents that, forcing the next note to another group.
Large Horizontal Window with Jack Avoidance
For Example
Notice that 3
was rejected from Group 1 because avoid_jack=True
. Thus moved to Group 2
Examples
Let's say we want to group with the parameters
vwindow = 0, hwindow = None
vwindow = 1000, hwindow = None
2, 3 and 4 are together as 4 is within the vwindow
of 2;
vwindow = 1000, hwindow = 1
2 and 3 aren't together as they are > 1 column apart, due to hwindow
(combinations)=
Combinations
For example:
Size
Flatten & Make Size 2
By default, the returned structure is List[List[List[int]]]
.
You may flatten
it.
make_size2
splits size>3
into pairs.
Filters
For each ..._filter
, we expect a Callable / lambda
.
You can use custom filters, however, I recommend our in-house lambdas for this.
Filter Chord
For example, if we only wanted 2-sized chords followed by 2-sized chords or lower sized chords, we can do the following:
Filter Chord controls which group combinations pass through.
Filter Chord Options
ANY_ORDER
Make Additional Filters of any order
[A, B, C] -> Any Order -> [A, B, C], [A, C, B], ..., [C, B, A]
AND_LOWER
Make Additional Filters of any lower combination (Down to 1)
[2, 3] -> And Lower -> [2, 3], [2, 2], ... , [1, 2], [1, 1]
AND_HIGHER
Make Additional Filters of any higher combination (Up to Keys)
[1, 2] -> And Higher -> [1, 2], [2, 2], ... , [3, 4], [4, 4]
Filter Combo
The above example includes occurrences of [0, 1, 2, 3]
and its horizontal mirror: [3, 2, 1, 0]
Filter Combo Options
REPEAT
Repeats the filter that are within bounds
For example, a [1, 2] filter =========== | _ _ O _ | | _ O _ _ | -> Repeat -> =========== =========== =========== =========== | _ O _ _ | | _ _ O _ | | _ _ _ O | | O _ _ _ | | _ O _ _ | | _ _ O _ | =========== =========== =========== [0, 1] [1, 2] [2, 3] [1, 2] -> Repeat -> [0, 1], [1, 2], [2, 3]
HMIRROR
Mirrors the filter Horizontally
For example, a [1, 3] filter Mirror | =========== =====|===== | _ _ _ O | | _ _|_ O | | _ _ _ _ | | _ _|_ _ | | _ O _ _ | -> H Mirror -> | _ O|_ _ | =========== =====|===== | Mirror =========== =========== | _ _ _ O | | O _ _ _ | | _ _ _ _ | | _ _ _ _ | | _ O _ _ | | _ _ O _ | =========== =========== [1, 3] [2, 0] [1, 3] -> H Mirror -> [1, 3], [2, 0]
VMIRROR
Mirrors the filter Vertically
For example, a [1, 3] filter =========== =========== | _ _ _ O | | _ _ _ O | | _ _ _ _ | Mirror --------------- Mirror | _ O _ _ | -> V Mirror -> | _ O _ _ | =========== =========== =========== =========== | _ _ _ O | | _ O _ _ | | _ _ _ _ | | _ _ _ _ | | _ O _ _ | | _ _ _ O | =========== =========== [1, 3] [3, 1] [1, 3] -> V Mirror -> [1, 3], [3, 1]
Filter Type
The above example includes occurrences of [OsuHit, OsuHit, OsuHold]
and any other order: [OsuHit, OsuHold, OsuHit]
, [OsuHold, OsuHit, OsuHit]
For example, if we want to match only LN Heads/Hits, excluding LN Tails.
Options
ANY_ORDER
Make Additional Filters of any order
[A, B, C] -> Any Order -> [A, B, C], [A, C, B], ..., [C, B, A]
VMIRROR
Mirrors the filter
[A, B] -> Mirror -> [A, B], [B, A]
Custom Filters
As long as they fit the signature, you can make it work.
All of them are functions accepting a certain data structure and return the boolean filter verdict.
Chord Filter
- Input
np.ndarray[int]
of chord sizes- Output
bool
verdict
Example I/O
Implement a function that accepts if the first chord size is greater than 1.
Combo Filter
- Input
np.ndarray[int]
of combos- Output
np.ndarray[bool]
verdict
Example I/O
Implement a function that accepts if the first column is less than 3.
Type Filter
- Input
np.ndarray[type]
of combos- Output
np.ndarray[bool]
verdict
Example I/O
Implement a function that accepts if the second column is a subclass of HoldTail
.