From bac435667289f6d128ce8ce110af940d80caf0fd Mon Sep 17 00:00:00 2001 From: Kyzentun Date: Sat, 11 Apr 2015 22:50:06 -0600 Subject: [PATCH] Changed TimingData to always return the entry before the closest one when using the lookup table to avoid various problems that occur only when the current time is exactly on the current entry in the lookup table. --- src/TimingData.cpp | 67 +++++++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/src/TimingData.cpp b/src/TimingData.cpp index 4fba921f08..c4f8fa7368 100644 --- a/src/TimingData.cpp +++ b/src/TimingData.cpp @@ -60,7 +60,7 @@ void TimingData::PrepareLookup() // lookups would probably cause FindEntryInLookup to return the wrong // thing. So release the lookups. -Kyz ReleaseLookup(); - const unsigned int segments_per_lookup= 32; + const unsigned int segments_per_lookup= 16; const vector* segs= m_avpTimingSegments; const vector& bpms= segs[SEGMENT_BPM]; const vector& warps= segs[SEGMENT_WARP]; @@ -86,6 +86,13 @@ void TimingData::PrepareLookup() float time= GetElapsedTimeInternal(time_start, FLT_MAX, curr_segment); m_time_start_lookup.push_back(lookup_item_t(NoteRowToBeat(time_start.last_row), time_start)); } + // If there are less than two entries, then FindEntryInLookup in lookup + // will always decide there's no appropriate entry. So clear the table. + // -Kyz + if(m_beat_start_lookup.size() < 2) + { + ReleaseLookup(); + } // DumpLookupTables(); } @@ -105,15 +112,37 @@ void TimingData::ReleaseLookup() #undef CLEAR_LOOKUP } +RString SegInfoStr(const vector& segs, unsigned int index, const RString& name) +{ + if(index < segs.size()) + { + return ssprintf("%s: %d at %d", name.c_str(), index, segs[index]->GetRow()); + } + return ssprintf("%s: %d at end", name.c_str(), index); +} + void TimingData::DumpOneTable(const beat_start_lookup_t& lookup, const RString& name) { + const vector* segs= m_avpTimingSegments; + const vector& bpms= segs[SEGMENT_BPM]; + const vector& warps= segs[SEGMENT_WARP]; + const vector& stops= segs[SEGMENT_STOP]; + const vector& delays= segs[SEGMENT_DELAY]; LOG->Trace("%s lookup table:", name.c_str()); for(size_t lit= 0; lit < lookup.size(); ++lit) { const lookup_item_t& item= lookup[lit]; const GetBeatStarts& starts= item.second; LOG->Trace("%zu: %f", lit, item.first); - LOG->Trace(" bpm: %d, warp: %d, stop: %d, delay: %d, last_row: %d, last_time: %f, warp_destination: %f, is_warping: %d", starts.bpm, starts.warp, starts.stop, starts.delay, starts.last_row, starts.last_time, starts.warp_destination, starts.is_warping); + RString str= ssprintf(" %s, %s, %s, %s,\n" + " last_row: %d, last_time: %.3f,\n" + " warp_destination: %.3f, is_warping: %d", + SegInfoStr(bpms, starts.bpm, "bpm").c_str(), + SegInfoStr(warps, starts.warp, "warp").c_str(), + SegInfoStr(stops, starts.stop, "stop").c_str(), + SegInfoStr(delays, starts.delay, "delay").c_str(), + starts.last_row, starts.last_time, starts.warp_destination, starts.is_warping); + LOG->Trace(str.c_str()); } } @@ -138,6 +167,11 @@ TimingData::beat_start_lookup_t::const_iterator FindEntryInLookup( { return lookup.end(); } + if(lookup[upper].first < entry) + { + // See explanation at the end of this function. -Kyz + return lookup.begin() + upper - 1; + } while(upper - lower > 1) { size_t next= (upper + lower) / 2; @@ -155,7 +189,15 @@ TimingData::beat_start_lookup_t::const_iterator FindEntryInLookup( break; } } - return lookup.begin() + lower; + // If the time or beat being looked up is close enough to the starting + // point that is returned, such as putting the time inside a stop or delay, + // then it can make arrows unhittable. So always return the entry before + // the closest one to prevent that. -Kyz + if(lower == 0) + { + return lookup.end(); + } + return lookup.begin() + lower - 1; } bool TimingData::empty() const @@ -847,21 +889,9 @@ float TimingData::GetElapsedTimeInternal(GetBeatStarts& start, float beat, float bps= GetBPMAtRow(start.last_row) / 60.0f; #define INC_INDEX(index) ++curr_segment; ++index; bool find_marker= beat < FLT_MAX; - // Stops require this special kluge to handle the case where a stop and a - // warp are on the same row and the lookup table entry would be between - // the stop and the warp. If that happens, then the last_time in the entry - // is pushed past the marker by the stop, so the marker can't be found and - // the step that is on that row comes up as a miss. - // So this kluge backs up the lookup table entry by one step if the last - // thing found was a stop. -Kyz - bool last_found_was_a_stop= false; - GetBeatStarts pre_stop_state= start; - unsigned int start_segment= curr_segment; - while(curr_segment < max_segment || curr_segment - start_segment <= 1) + while(curr_segment < max_segment) { - last_found_was_a_stop= false; - pre_stop_state= start; int event_row= INT_MAX; int event_type= NOT_FOUND; FindEvent(event_row, event_type, start, beat, find_marker, bpms, warps, stops, @@ -881,7 +911,6 @@ float TimingData::GetElapsedTimeInternal(GetBeatStarts& start, float beat, break; case FOUND_STOP: case FOUND_STOP_DELAY: - last_found_was_a_stop= true; time_to_next_event= ToStop(stops[start.stop])->GetPause(); next_event_time= start.last_time + time_to_next_event; start.last_time= next_event_time; @@ -911,10 +940,6 @@ float TimingData::GetElapsedTimeInternal(GetBeatStarts& start, float beat, start.last_row= event_row; } #undef INC_INDEX - if(last_found_was_a_stop) - { - start= pre_stop_state; - } return start.last_time; }