diff --git a/src/MeasureInfo.cpp b/src/MeasureInfo.cpp index b38cd65ff8..ff3035d95b 100644 --- a/src/MeasureInfo.cpp +++ b/src/MeasureInfo.cpp @@ -34,7 +34,7 @@ void MeasureInfo::FromString(const RString& sValues) for (int i = 0; i < half_size; i++) { float nps = StringToFloat(asValues[i]); - this->npsPerMeasure.push_back(nps); + npsPerMeasure.push_back(nps); if(nps > peak_nps) { peak_nps = nps; @@ -42,10 +42,10 @@ void MeasureInfo::FromString(const RString& sValues) } for (unsigned i = half_size; i < asValues.size(); i++) { - this->notesPerMeasure.push_back(StringToInt(asValues[i])); + notesPerMeasure.push_back(StringToInt(asValues[i])); } - this->measureCount = half_size; - this->peakNps = peak_nps; + measureCount = half_size; + peakNps = peak_nps; } void MeasureInfo::CalculateMeasureInfo(const NoteData &in, MeasureInfo &out) @@ -79,18 +79,16 @@ void MeasureInfo::CalculateMeasureInfo(const NoteData &in, MeasureInfo &out) { if(curr_note.Row() != curr_row) { - // Before moving on to a new row, update the row count for the "current" measure - // Note that we're only add + // Before moving on to a new row, update the notes per measure for the current measure. out.notesPerMeasure[iMeasureIndexOut] += notes_this_row; // Update iMeasureIndex for the current row timing->NoteRowToMeasureAndBeat(curr_note.Row(), iMeasureIndexOut, iBeatIndexOut, iRowsRemainder); curr_row = curr_note.Row(); notes_this_row = 0; } - // Update tap and mine count for the current measure + // Regardless of how many notes are on this row, it's only considered 1 "note" when we want to - // calculate nps. So jumps/brackets don't inflate the nps value. Maybe we should call it - // "steps per second" or something like that? + // calculate nps. So jumps/brackets don't inflate the nps value. if (curr_note->type == TapNoteType_Tap || curr_note->type == TapNoteType_HoldHead) { notes_this_row = 1; @@ -113,6 +111,20 @@ void MeasureInfo::CalculateMeasureInfo(const NoteData &in, MeasureInfo &out) float measureDuration = timing->GetElapsedTimeFromBeat(4 * (m+1)) - timing->GetElapsedTimeFromBeat(4 * m); float nps = out.notesPerMeasure[m] / measureDuration; + // FIXME: We subtract the time at the current measure from the time at the next measure to determine + // the duration of this measure in seconds, and use that to calculate notes per second. + // + // Measures *normally* occur over some positive quantity of seconds. Measures that use warps, + // negative BPMs, and negative stops are normally reported by the SM5 engine as having a duration + // of 0 seconds, and when that happens, we safely assume that there were 0 notes in that measure. + // + // This doesn't always hold true. Measures 48 and 49 of "Mudkyp Korea/Can't Nobody" use a properly + // timed negative stop, but the engine reports them as having very small but positive durations + // which erroneously inflates the notes per second calculation. + // + // As a hold over for this case, we check that the duration is <= 0.12 (instead of 0), so this only + // breaks for cases where charts are of 2,000 BPM (which are likely rarer than those with warps). + if(measureDuration < 0.12) { out.npsPerMeasure[m] = 0;