Only make a single copy of the string in LoadFromSMNoteDataString() when stripping out comments. Previously, the string was copied as many times as there were comments. Now, the whole loading can happen with a single copy of the data.
We can actually go much higher; I set this to 1<<30 instead of 1<<31 so
we don't overflow when eg. adding one beat or one measure in some
algorithms.
The advantage of this over "999999" is it won't break if ROWS_PER_BEAT
is changed to a large value.
Also, since this value will typically be much larger than any actual row, it'll
quickly show up any algorithms that aren't iterating properly.
An advantage over older code using 999999 is that we don't have to
manually clamp the value to a reasonable range; FOREACH_NONEMPTY_ROW_IN_TRACK_RANGE,
etc. don't care.
An advantage of this over using -1 as a sentinel is that we don't have to
carefully check and fill in the value in every function using it.
It actually looks like almost all of NoteDataUtil can be done naturally
in fixed-point: instead of passing around floating point, converting it to
fixed point for NoteData indexing, and adding floating-point beat fractions,
just pass around fixed point everywhere, and convert beat fractions to
fixed-point (which probably happens at compile-time)
If TimingData, etc. does the same thing, things will be simpler ...
using them in general over beats: it's more precise (we can tell exactly
how it'll round, and we can compare them without ugly error-margin hacks),
and it's what we need to use them with NoteData.
store attack info in TapNote
in the SMNoteData string, store the attack params inline (like with keysounds)
play keysounds when hit
still doesn't play keysounds on a miss
still doesn't play autoKeysounds
fix "impossible to get 100% on a course that uses AddMines" by calculating RadarValues after applying mods
Trail::GetRadarValues needs to do caching. Performance is bad.