ok it look slike offset is fixed for now !

This commit is contained in:
Stepland 2022-11-10 19:28:25 +01:00
parent 69e8add495
commit de72d441ae
9 changed files with 82 additions and 32 deletions

View File

@ -8,6 +8,17 @@
#include "json_decimal_handling.hpp"
namespace better {
bool Chart::operator==(const Chart& other) const {
return (
level == other.level
and (
((not timing.has_value()) and (not other.timing.has_value()))
or (**timing == **other.timing)
) and hakus == other.hakus
and *notes == *other.notes
);
}
nlohmann::ordered_json Chart::dump_to_memon_1_0_0(
const nlohmann::ordered_json& fallback_timing_object
) const {

View File

@ -20,7 +20,7 @@ namespace better {
std::optional<Hakus> hakus;
std::shared_ptr<Notes> notes = std::make_shared<Notes>();
bool operator==(const Chart&) const = default;
bool operator==(const Chart&) const;
nlohmann::ordered_json dump_to_memon_1_0_0(
const nlohmann::ordered_json& fallback_timing_object

View File

@ -1,5 +1,6 @@
#include "better_song.hpp"
#include <algorithm>
#include <stdexcept>
#include <fmt/core.h>
@ -193,6 +194,15 @@ namespace better {
return song;
};
bool Song::operator==(const Song& other) const {
return (
charts == other.charts
and metadata == other.metadata
and *timing == *other.timing
and hakus == other.hakus
);
}
std::ostream& operator<<(std::ostream& out, const Song& s) {
out << fmt::format("{}", s);
return out;

View File

@ -77,7 +77,7 @@ namespace better {
*/
static Song load_from_memon_legacy(const nlohmann::json& memon);
bool operator==(const Song&) const = default;
bool operator==(const Song&) const;
friend std::ostream& operator<<(std::ostream& out, const Song& s);
};

View File

@ -89,15 +89,16 @@ namespace better {
change
*/
double Timing::seconds_at(Fraction beats) const {
return offset_as_double + seconds_without_offset_at(beats);
};
double Timing::seconds_without_offset_at(Fraction beats) const {
const auto& bpm_change = bpm_event_in_effect_at(beats);
const Fraction beats_since_previous_event = beats - bpm_change.get_beats();
double seconds_since_previous_event = static_cast<double>(beats_since_previous_event) * 60 / bpm_change.get_bpm_as_double();
return (
offset_as_double
+ bpm_change.get_seconds()
+ seconds_since_previous_event
);
};
const auto previous_event_seconds = bpm_change.get_seconds();
return previous_event_seconds + seconds_since_previous_event;
}
double Timing::seconds_between(Fraction beat_a, Fraction beat_b) const {
return seconds_at(beat_b) - seconds_at(beat_a);
@ -118,8 +119,9 @@ namespace better {
Fraction Timing::beats_at(double seconds) const {
const auto& bpm_change = bpm_event_in_effect_at(seconds);
auto seconds_since_previous_event = seconds - bpm_change.get_seconds();
auto beats_since_previous_event = (
const auto previous_event_seconds = bpm_change.get_seconds() + offset_as_double;
const auto seconds_since_previous_event = seconds - previous_event_seconds;
const auto beats_since_previous_event = (
convert_to_fraction(bpm_change.get_bpm())
* Fraction{seconds_since_previous_event}
/ 60
@ -182,7 +184,8 @@ namespace better {
}
void Timing::set_offset(const Decimal& new_offset) {
shift_to_match(new_offset);
offset = new_offset;
offset_as_double = std::stod(new_offset.format("f"));
}
@ -242,7 +245,7 @@ namespace better {
void Timing::reconstruct(const std::vector<BPMAtBeat>& events, const Decimal& offset) {
reload_events_from(events);
shift_to_match(offset);
set_offset(offset);
}
void Timing::reload_events_from(const std::vector<BPMAtBeat>& events) {
@ -274,9 +277,8 @@ namespace better {
}
}
// Compute seconds offsets as if the first event happened at second 0
// then shift
// Bootstrap the alg by computing the first one out of the loop
// Compute everything as if the first BPM change happened at zero
// seconds
auto first_event = filtered_events.begin();
double current_second = 0;
events_by_beats.clear();
@ -298,19 +300,17 @@ namespace better {
current->get_bpm()
);
}
}
void Timing::shift_to_match(const Decimal& offset_) {
offset = offset_;
offset_as_double = std::stod(offset_.format("f"));
const auto shift = offset_as_double - seconds_at(0);
// Shift events so their precomputed "seconds" put beat zero
// at zero seconds
const auto shift = seconds_without_offset_at(0);
Timing::keys_by_beats_type shifted_events;
seconds_to_beats.clear();
std::for_each(
events_by_beats.cbegin(),
events_by_beats.cend(),
[&](const auto& event) {
const auto seconds = event.get_seconds() + shift;
const auto seconds = event.get_seconds() - shift;
const auto beats = event.get_beats();
shifted_events.emplace(beats, seconds, event.get_bpm());
seconds_to_beats.emplace(seconds, beats);
@ -325,7 +325,7 @@ namespace better {
}
const Timing::key_type& Timing::bpm_event_in_effect_at(double seconds) const {
auto it = seconds_to_beats.upper_bound(seconds);
auto it = seconds_to_beats.upper_bound(seconds - offset_as_double);
if (it != seconds_to_beats.begin()) {
it = std::prev(it);
}

View File

@ -69,6 +69,9 @@ namespace better {
Timing(const std::vector<BPMAtBeat>& events, const Decimal& offset);
double seconds_at(Fraction beats) const;
private:
double seconds_without_offset_at(Fraction beats) const;
public:
double seconds_between(Fraction beat_a, Fraction beat_b) const;
sf::Time time_at(Fraction beats) const;
sf::Time time_between(Fraction beat_a, Fraction beat_b) const;
@ -106,14 +109,17 @@ namespace better {
Decimal offset = 0;
double offset_as_double = 0;
// These containers hold shared pointers to the same objects
// holds the bpm changes with seconds precomputed, seconds are synced
// as if beat zero was happening at zero seconds, ignoring any offset
keys_by_beats_type events_by_beats = {};
// holds a <seconds, beats> pair for each event to allow a quick search
// when querying by seconds, seconds held in this are synced as if beat
// zero was happenning at zero seconds
std::map<double, Fraction> seconds_to_beats = {};
void reconstruct(const std::vector<BPMAtBeat>& events, const Decimal& offset);
/* Reload the timing object assuming the first event in the given
vector happens at second zero */
/* Reload using the given events */
void reload_events_from(const std::vector<BPMAtBeat>& events);
/* Shift all events in the timing object to make beat zero happen

View File

@ -10,7 +10,7 @@ TEST_CASE("make_long_note works with any input") {
better::Position pos_b{index_b};
better::TapNote a{0, pos_a};
better::TapNote b{0, pos_b};
REQUIRE_NOTHROW(make_linear_view_long_note_dummy({a, b}, 1));
REQUIRE_NOTHROW(make_long_note_dummy_for_linear_view({a, b}, 1));
}
}
}

View File

@ -20,6 +20,7 @@
#include "../../better_song.hpp"
#include "../../better_timing.hpp"
#include "../../variant_visitor.hpp"
#include "rapidcheck/gen/Arbitrary.hpp"
namespace rc {
@ -153,10 +154,15 @@ namespace rc {
}
};
struct TimingParams {
std::vector<better::BPMAtBeat> events;
Decimal offset;
};
template<>
struct Arbitrary<better::Timing> {
static Gen<better::Timing> arbitrary() {
return gen::construct<better::Timing>(
struct Arbitrary<TimingParams> {
static Gen<TimingParams> arbitrary() {
return gen::construct<TimingParams>(
gen::withSize([](std::size_t size) {
return gen::uniqueBy<std::vector<better::BPMAtBeat>>(
std::max(std::size_t(1), size),
@ -169,6 +175,18 @@ namespace rc {
}
};
template<>
struct Arbitrary<better::Timing> {
static Gen<better::Timing> arbitrary() {
return gen::map(
gen::arbitrary<TimingParams>(),
[](const TimingParams& t){
return better::Timing{t.events, t.offset};
}
);
}
};
template<>
struct Arbitrary<Hakus> {
static Gen<Hakus> arbitrary() {
@ -197,9 +215,13 @@ namespace rc {
static Gen<better::Chart> arbitrary() {
return gen::construct<better::Chart>(
gen::arbitrary<std::optional<Decimal>>(),
gen::construct<std::optional<better::Timing>>(gen::arbitrary<better::Timing>()),
gen::construct<std::optional<std::shared_ptr<better::Timing>>>(
gen::makeShared<better::Timing>(gen::arbitrary<better::Timing>())
),
gen::arbitrary<std::optional<Hakus>>(),
gen::arbitrary<better::Notes>()
gen::construct<std::shared_ptr<better::Notes>>(
gen::makeShared<better::Notes>(gen::arbitrary<better::Notes>())
)
);
}
};
@ -254,7 +276,7 @@ namespace rc {
return gen::construct<better::Song>(
gen::arbitrary<std::map<std::string, better::Chart, better::OrderByDifficultyName>>(),
gen::arbitrary<better::Metadata>(),
gen::arbitrary<better::Timing>(),
gen::makeShared<better::Timing>(gen::arbitrary<better::Timing>()),
gen::arbitrary<std::optional<Hakus>>()
);
}

View File

@ -312,6 +312,7 @@ void LinearView::draw(
ImGui::IsMouseClicked(ImGuiMouseButton_Left)
and current_window->InnerClipRect.Contains(ImGui::GetMousePos())
and not ImGui::IsAnyItemHovered()
and ImGui::IsWindowFocused()
) {
started_selection_inside_window = true;
}