diff --git a/src/better_note.cpp b/src/better_note.cpp index a80f31d..af9b832 100644 --- a/src/better_note.cpp +++ b/src/better_note.cpp @@ -75,7 +75,12 @@ namespace better { "Attempted to create a LongNote with a zero-length tail" ); } - if (tail_tip.get_x() != position.get_x() and tail_tip.get_y() != position.get_y()) { + if ( + not ( + (tail_tip.get_x() == position.get_x()) + xor (tail_tip.get_y() == position.get_y()) + ) + ) { std::stringstream ss; ss << "Attempted to create a LongNote with and invalid tail : "; ss << "position: " << position << " , tail_tip: " << tail_tip; @@ -174,6 +179,8 @@ namespace better { return {pos.get_x(), pos.get_y() + length}; case 3: // left return {pos.get_x() - length, pos.get_y()}; + default: + return pos; } } diff --git a/src/better_timing.cpp b/src/better_timing.cpp index ea9b961..a2249ba 100644 --- a/src/better_timing.cpp +++ b/src/better_timing.cpp @@ -1,5 +1,6 @@ #include "better_timing.hpp" +#include #include #include "better_beats.hpp" @@ -23,21 +24,28 @@ namespace better { return beats; } - BPMEvent::BPMEvent(Fraction beats, Fraction seconds, Decimal bpm) : - BPMAtBeat(bpm, beats), + BPMEvent::BPMEvent(Fraction beats, double seconds, Decimal bpm) : + bpm(bpm), + beats(beats), seconds(seconds) {}; + Decimal BPMEvent::get_bpm() const { + return bpm; + } + + Fraction BPMEvent::get_beats() const { + return beats; + } + Fraction BPMEvent::get_seconds() const { return seconds; }; + - /* - Create a default-constructed Timing, which corresponds to the fallback - timing object from the memon spec : 120 BPM, offset 0 - */ - Timing::Timing(): - Timing({{120, 0}}, {0,0}) + // Default constructor, used when creating a new song from scratch + Timing::Timing() + Timing({120, 0}, 0) {}; /* @@ -45,7 +53,9 @@ namespace better { beats, the offset parameter is more flexible than a "regular" beat zero offset as it accepts non-zero beats */ - Timing::Timing(const std::vector& events, const SecondsAtBeat& offset) { + Timing::Timing(const std::vector& events, const Decimal& new_offset) : + offset(new_offset) + { if (events.empty()) { throw std::invalid_argument( "Attempted to create a Timing object with no BPM events" @@ -70,10 +80,8 @@ namespace better { } } - // First compute everything as if the first BPM change happened at - // zero seconds, then shift according to the offset auto first_event = sorted_events.begin(); - Fraction current_second = 0; + double current_second = 0; std::vector bpm_changes; bpm_changes.reserve(sorted_events.size()); bpm_changes.emplace_back( @@ -85,10 +93,11 @@ namespace better { auto previous = first_event; auto current = std::next(first_event); for (; current != sorted_events.end(); ++previous, ++current) { - auto beats_since_last_event = + Fraction beats_since_last_event = current->get_beats() - previous->get_beats(); auto seconds_since_last_event = - (60 * beats_since_last_event) / convert_to_fraction(previous->get_bpm()); + static_cast(60 * beats_since_last_event) + / static_cast(previous->get_bpm()); current_second += seconds_since_last_event; bpm_changes.emplace_back( current->get_beats(), @@ -100,86 +109,67 @@ namespace better { .insert(bpm_changes.begin(), bpm_changes.end()); this->events_by_seconds .insert(bpm_changes.begin(), bpm_changes.end()); - auto unshifted_seconds_at_offset = - this->fractional_seconds_at(offset.beats); - auto shift = offset.seconds - unshifted_seconds_at_offset; - std::vector shifted_bpm_changes; - std::transform( - bpm_changes.begin(), - bpm_changes.end(), - std::back_inserter(shifted_bpm_changes), - [shift](const BPMEvent& b){ - return BPMEvent( - b.get_beats(), - b.get_seconds() + shift, - b.get_bpm() - ); - } - ); - this->events_by_beats - .insert(shifted_bpm_changes.begin(), shifted_bpm_changes.end()); - this->events_by_seconds - .insert(shifted_bpm_changes.begin(), shifted_bpm_changes.end()); } /* - Return the number of seconds at the given beat. + Return the amount of seconds at the given beat. Before the first bpm change, compute backwards from the first bpm, after the first bpm change, compute forwards from the previous bpm change */ - Fraction Timing::fractional_seconds_at(Fraction beats) const { + double Timing::seconds_at(Fraction beats) const { auto bpm_change = this->events_by_beats.upper_bound(BPMEvent(beats, 0, 0)); if (bpm_change != this->events_by_beats.begin()) { bpm_change = std::prev(bpm_change); } auto beats_since_previous_event = beats - bpm_change->get_beats(); auto seconds_since_previous_event = ( - Fraction{60} - * beats_since_previous_event - / convert_to_fraction(bpm_change->get_bpm()) + static_cast(60 * beats_since_previous_event) + / static_cast(bpm_change->get_bpm()) + ); + return ( + static_cast(offset) + + bpm_change->get_seconds() + + seconds_since_previous_event ); - return bpm_change->get_seconds() + seconds_since_previous_event; }; - Fraction Timing::fractional_seconds_between( - Fraction beat_a, - Fraction beat_b - ) const { - return ( - fractional_seconds_at(beat_b) - - fractional_seconds_at(beat_a) - ); + double Timing::seconds_between(Fraction beat_a, Fraction beat_b) const { + return seconds_at(beat_b) - seconds_at(beat_a); }; sf::Time Timing::time_at(Fraction beats) const { - return frac_to_time(fractional_seconds_at(beats)); + return sf::seconds(seconds_at(beats)); }; sf::Time Timing::time_between(Fraction beat_a, Fraction beat_b) const { - return frac_to_time(fractional_seconds_between(beat_a, beat_b)); + return sf::seconds(seconds_between(beat_a, beat_b)); }; Fraction Timing::beats_at(sf::Time time) const { - Fraction fractional_seconds{convert_to_mpz(static_cast(time.asMicroseconds())), 1000000}; - auto bpm_change = this->events_by_seconds.upper_bound(BPMEvent(0, fractional_seconds, 0)); + const auto seconds = static_cast(time.asMicroseconds()) / 1000000.0; + return beats_at(seconds); + }; + + Fraction Timing::beats_at(double seconds) const { + seconds -= static_cast(offset); + auto bpm_change = this->events_by_seconds.upper_bound(BPMEvent(0, seconds, 0)); if (bpm_change != this->events_by_seconds.begin()) { bpm_change = std::prev(bpm_change); } - auto seconds_since_previous_event = fractional_seconds - bpm_change->get_seconds(); + auto seconds_since_previous_event = seconds - bpm_change->get_seconds(); auto beats_since_previous_event = ( convert_to_fraction(bpm_change->get_bpm()) - * seconds_since_previous_event - / Fraction{60} + * Fraction{seconds_since_previous_event} + / 60 ); return bpm_change->get_beats() + beats_since_previous_event; }; nlohmann::ordered_json Timing::dump_to_memon_1_0_0() const { nlohmann::ordered_json j; - const auto offset = fractional_seconds_at(0); - j["offset"] = convert_to_decimal(offset, 5).format("f"); + j["offset"] = offset.format("f"); auto bpms = nlohmann::ordered_json::array(); for (const auto& bpm_change : events_by_beats) { bpms.push_back({ @@ -189,14 +179,13 @@ namespace better { } j["bpms"] = bpms; return j; - } + }; Timing Timing::load_from_memon_1_0_0(const nlohmann::json& json) { - Fraction offset = 0; + double offset = 0; if (json.contains("offset")) { const auto string_offset = json["offset"].get(); - const auto decimal_offset = Decimal{string_offset}; - offset = convert_to_fraction(decimal_offset); + offset = Decimal{string_offset}; } std::uint64_t resolution = 240; if (json.contains("resolution")) { @@ -219,25 +208,17 @@ namespace better { } return { bpms, - {offset, 0} + offset }; - } + }; /* - For this function, offset is the OPPOSITE of the time (in seconds) at which + In legacy memon, offset is the OPPOSITE of the time (in seconds) at which the first beat occurs in the music file */ Timing Timing::load_from_memon_legacy(const nlohmann::json& metadata) { const auto bpm = Decimal{metadata["BPM"].get()}; - const auto offset = convert_to_fraction(Decimal{metadata["offset"].get()}); - const BPMAtBeat bpm_at_beat{bpm, 0}; - const SecondsAtBeat seconds_at_beat{-1 * offset, 0}; - return Timing{{bpm_at_beat}, seconds_at_beat}; - } - - sf::Time frac_to_time(const Fraction& f) { - const Fraction microseconds = f * 1000000; - const mpz_class approximated = microseconds.get_num() / microseconds.get_den(); - return sf::microseconds(convert_to_int64(approximated)); + const auto offset = Decimal{metadata["offset"].get()}; + return Timing{{bpm, 0}, -1 * offset}; }; } \ No newline at end of file diff --git a/src/better_timing.hpp b/src/better_timing.hpp index cf61d02..76684f8 100644 --- a/src/better_timing.hpp +++ b/src/better_timing.hpp @@ -15,7 +15,7 @@ namespace better { struct SecondsAtBeat { - Fraction seconds; + Decimal seconds; Fraction beats; }; @@ -29,12 +29,16 @@ namespace better { Fraction beats; }; - class BPMEvent : public BPMAtBeat { + class BPMEvent { public: - BPMEvent(Fraction beats, Fraction seconds, Decimal bpm); + BPMEvent(Fraction beats, double seconds, Decimal bpm); + Decimal get_bpm() const; + Fraction get_beats() const; Fraction get_seconds() const; private: - Fraction seconds; + Decimal bpm; + Fraction beats; + double seconds; }; struct OrderByBeats { @@ -54,24 +58,25 @@ namespace better { class Timing { public: Timing(); - Timing(const std::vector& events, const SecondsAtBeat& offset); + Timing(const std::vector& events, const Decimal& offset); - Fraction fractional_seconds_at(Fraction beats) const; - Fraction fractional_seconds_between(Fraction beat_a, Fraction beat_b) const; + double seconds_at(Fraction beats) const; + 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; Fraction beats_at(sf::Time time) const; + Fraction beats_at(double seconds) const; nlohmann::ordered_json dump_to_memon_1_0_0() const; static Timing load_from_memon_1_0_0(const nlohmann::json& json); static Timing load_from_memon_legacy(const nlohmann::json& metadata); + + Decimal offset; private: std::set events_by_beats; std::set events_by_seconds; }; - - sf::Time frac_to_time(const Fraction& f); } \ No newline at end of file diff --git a/src/editor_state.cpp b/src/editor_state.cpp index dabcb08..42cdaf5 100644 --- a/src/editor_state.cpp +++ b/src/editor_state.cpp @@ -58,6 +58,44 @@ EditorState::EditorState( reload_jacket(); }; +int EditorState::get_volume() const { + return volume; +} + +void EditorState::set_volume(int newMusicVolume) { + volume = std::clamp(newMusicVolume, 0, 10); + if (music) { + music->setVolume(Toolbox::convertVolumeToNormalizedDB(volume)*100.f); + } +} + +void EditorState::volume_up() { + set_volume(volume + 1); +} + +void EditorState::volume_down() { + set_volume(volume - 1); +} + +int EditorState::get_speed() const { + return speed; +} + +void EditorState::set_speed(int newMusicSpeed) { + speed = std::clamp(newMusicSpeed, 1, 20); + if (music) { + music->setPitch(speed / 10.f); + } +} + +void EditorState::speed_up() { + set_speed(speed + 1); +} + +void EditorState::speed_down() { + set_speed(speed - 1); +} + const Interval& EditorState::get_editable_range() { reload_editable_range(); @@ -68,14 +106,14 @@ void EditorState::set_playback_position(sf::Time newPosition) { newPosition = std::clamp(newPosition, editable_range.start, editable_range.end); previous_playback_position = newPosition - (sf::seconds(1) / 60.f); playback_position = newPosition; - if (music_state) { + if (music) { if ( playback_position >= sf::Time::Zero - and playback_position < music_state->music.getDuration() + and playback_position < music->getDuration() ) { - music_state->music.setPlayingOffset(playback_position); + music->setPlayingOffset(playback_position); } else { - music_state->music.stop(); + music->stop(); } } }; @@ -187,7 +225,12 @@ void EditorState::display_playfield(Marker& marker, MarkerEndingState markerEndi (ImVec4) ImColor::HSV(0, 0, 1.f, 0.5f)); if (ImGui::ImageButton(playfield.button, {squareSize, squareSize}, 0)) { if (chart_state) { - chart_state->toggle_note(playback_position, snap, {x, y}); + chart_state->toggle_note( + playback_position, + snap, + {x, y}, + applicable_timing + ); } } if (ImGui::IsItemHovered() and chart_state and chart_state->creating_long_note) { @@ -262,7 +305,7 @@ void EditorState::display_properties() { if (feis::InputTextColored( "Audio", &song.metadata.audio, - music_state.has_value(), + music.has_value(), "Invalid Audio Path" )) { reload_music(); @@ -295,9 +338,9 @@ void EditorState::display_properties() { Decimal{0}, song.metadata.preview_loop.start ); - if (music_state.has_value()) { + if (music.has_value()) { song.metadata.preview_loop.start = std::min( - Decimal{music_state->music.getDuration().asMicroseconds()} / 1000000, + Decimal{music->getDuration().asMicroseconds()} / 1000000, song.metadata.preview_loop.start ); } @@ -307,12 +350,12 @@ void EditorState::display_properties() { Decimal{0}, song.metadata.preview_loop.duration ); - if (music_state.has_value()) { + if (music.has_value()) { song.metadata.preview_loop.start = std::min( ( Decimal{ - music_state->music - .getDuration() + music + ->getDuration() .asMicroseconds() } / 1000000 - song.metadata.preview_loop.start @@ -335,7 +378,7 @@ status of the editor. Will appear in the "Editor Status" window void EditorState::display_status() { ImGui::Begin("Status", &showStatus, ImGuiWindowFlags_AlwaysAutoResize); { - if (not music_state) { + if (not music) { if (not song.metadata.audio.empty()) { ImGui::TextColored( ImVec4(1, 0.42, 0.41, 1), @@ -396,12 +439,12 @@ void EditorState::display_playback_status() { ImGui::SameLine(); ImGui::TextDisabled("Beats :"); ImGui::SameLine(); - ImGui::TextUnformatted(convert_to_decimal(this->current_exact_beats(), 3).format(".3f").c_str()); + ImGui::TextUnformatted(fmt::format("{:.3f}", current_exact_beats().get_d()).c_str()); ImGui::SameLine(); - if (music_state) { + if (music) { ImGui::TextDisabled("Music File Offset :"); ImGui::SameLine(); - ImGui::TextUnformatted(Toolbox::to_string(music_state->music.getPrecisePlayingOffset()).c_str()); + ImGui::TextUnformatted(Toolbox::to_string(music->getPrecisePlayingOffset()).c_str()); ImGui::SameLine(); } ImGui::TextDisabled("Timeline Position :"); @@ -524,6 +567,7 @@ void EditorState::display_linear_view() { if (chart_state) { linear_view.update( *chart_state, + applicable_timing, playback_position, ImGui::GetContentRegionMax() ); @@ -589,7 +633,7 @@ EditorState::SaveOutcome EditorState::ask_to_save_if_needed() { } case EditorState::UserWantsToSave::No: return EditorState::SaveOutcome::UserDeclindedSaving; - case EditorState::UserWantsToSave::Cancel: + default: return EditorState::SaveOutcome::UserCanceled; } }; @@ -662,12 +706,21 @@ void EditorState::open_chart(const std::string& name) { reload_applicable_timing(); }; +void EditorState::update_visible_notes() { + if (chart_state) { + chart_state->update_visible_notes( + playback_position, + applicable_timing + ); + } +}; + void EditorState::reload_editable_range() { auto old_range = this->editable_range; Interval new_range; - if (music_state) { - new_range += music_state->music.getDuration(); + if (music) { + new_range += music->getDuration(); } if (chart_state and not chart_state->chart.notes.empty()) { const auto beat_of_last_event = chart_state->chart.notes.crbegin()->second.get_end(); @@ -677,7 +730,7 @@ void EditorState::reload_editable_range() { new_range.end += sf::seconds(10); // If there is no music, make sure we can edit at least the first whole minute - if (not music_state) { + if (not music) { new_range += sf::seconds(60); } @@ -715,15 +768,15 @@ void EditorState::reload_jacket() { */ void EditorState::reload_music() { if (not song_path.has_value() or song.metadata.audio.empty()) { - music_state.reset(); + music.reset(); return; } const auto absolute_music_path = song_path->parent_path() / song.metadata.audio; try { - music_state.emplace(absolute_music_path); + music.emplace(absolute_music_path); } catch (const std::exception& e) { - music_state.reset(); + music.reset(); } reload_editable_range(); @@ -778,7 +831,7 @@ void EditorState::save(const std::filesystem::path& path) { void feis::open(std::optional& ed, std::filesystem::path assets, std::filesystem::path settings) { if (ed and ed->ask_to_save_if_needed() == EditorState::SaveOutcome::UserCanceled) { - return + return; } const char* _filepath = tinyfd_openFileDialog( diff --git a/src/editor_state.hpp b/src/editor_state.hpp index 5b1edcc..a21470b 100644 --- a/src/editor_state.hpp +++ b/src/editor_state.hpp @@ -12,7 +12,6 @@ #include "history.hpp" #include "history_actions.hpp" #include "marker.hpp" -#include "music_state.hpp" #include "notes_clipboard.hpp" #include "notifications_queue.hpp" #include "playfield.hpp" @@ -39,7 +38,18 @@ public: std::optional chart_state; - std::optional music_state; + std::optional music; + + int get_volume() const; + void set_volume(int newMusicVolume); + void volume_up(); + void volume_down(); + + /* These speed dials also work when no music is loaded */ + int get_speed() const; + void set_speed(int newMusicSpeed); + void speed_up(); + void speed_down(); std::optional preview_audio; @@ -100,7 +110,7 @@ public: SaveOutcome ask_to_save_if_needed(); - void save_if_needed(); + SaveOutcome save_if_needed(); bool needs_to_save() const; @@ -131,8 +141,13 @@ public: void open_chart(const std::string& name); + void update_visible_notes(); + private: + int volume = 10; // 0 -> 10 + int speed = 10; // 1 -> 20 + /* sf::Time bounds (in the audio file "coordinates") which are accessible (and maybe editable) from the editor, can extend before and after diff --git a/src/history.hpp b/src/history.hpp index a9ec7b9..fe5a887 100644 --- a/src/history.hpp +++ b/src/history.hpp @@ -91,12 +91,12 @@ public: if (next_actions.empty()) { last_saved_action = nullptr; } else { - last_saved_action = previous_actions.front(); + last_saved_action = &previous_actions.front(); } } bool current_state_is_saved() const { - return last_saved_action == previous_actions.front(); + return last_saved_action == &previous_actions.front(); }; private: diff --git a/src/ln_marker.cpp b/src/ln_marker.cpp index 1ea3217..30ad54f 100644 --- a/src/ln_marker.cpp +++ b/src/ln_marker.cpp @@ -11,7 +11,7 @@ LNMarker::LNMarker(std::filesystem::path folder) : square_background(load_tex_with_prefix<16, 200>(folder, "LN0001_M")), tail_cycle(load_tex_with_prefix<16, 0>(folder, "LN0001_M")) { - for (tex& : tail_cycle) { + for (auto& tex : tail_cycle) { tex.setRepeated(true); } } diff --git a/src/ln_marker.hpp b/src/ln_marker.hpp index 0d4ac55..0e269d4 100644 --- a/src/ln_marker.hpp +++ b/src/ln_marker.hpp @@ -44,7 +44,7 @@ private: template std::array load_tex_with_prefix( const std::filesystem::path& folder, - const std::string& prefix, + const std::string& prefix ) { std::array res; for (unsigned int frame = first; frame <= first + number - 1; frame++) { @@ -52,17 +52,15 @@ std::array load_tex_with_prefix( "{prefix}{frame:03}.png", fmt::arg("prefix", prefix), fmt::arg("frame", frame) - ) - std::stringstream filename; - filename << prefix << std::setfill('0') << std::setw(3) - << frame << ".png"; - std::filesystem::path texFile = folder / filename.str(); + ); + std::filesystem::path texFile = folder / filename; sf::Texture tex; if (!tex.loadFromFile(texFile.string())) { - std::stringstream err; - err << "Unable to load texture folder " << folder - << "\nfailed on texture " << filename.str(); - throw std::runtime_error(err.str()); + throw std::runtime_error(fmt::format( + "Unable to load texture folder {}, failed on texture {}", + folder.string(), + filename + )); } tex.setSmooth(true); res.at(frame - first) = tex; diff --git a/src/main.cpp b/src/main.cpp index d60795e..90897e4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -196,12 +196,12 @@ int main() { // Arrow keys case sf::Keyboard::Up: if (event.key.shift) { - if (editor_state and editor_state->music_state) { - editor_state->music_state->volume_up(); + if (editor_state) { + editor_state->volume_up(); notificationsQueue.push( std::make_shared(fmt::format( "Music Volume : {}%", - editor_state->music_state->volume * 10 + editor_state->get_volume() * 10 )) ); } @@ -213,12 +213,12 @@ int main() { break; case sf::Keyboard::Down: if (event.key.shift) { - if (editor_state and editor_state->music_state) { - editor_state->music_state->volume_down(); + if (editor_state) { + editor_state->volume_down(); notificationsQueue.push( std::make_shared(fmt::format( "Music Volume : {}%", - editor_state->music_state->volume * 10 + editor_state->get_volume() * 10 )) ); } @@ -230,11 +230,11 @@ int main() { break; case sf::Keyboard::Left: if (event.key.shift) { - if (editor_state and editor_state->music_state) { - editor_state->music_state->speed_down(); + if (editor_state) { + editor_state->speed_down(); notificationsQueue.push(std::make_shared(fmt::format( "Speed : {}%", - editor_state->music_state->speed * 10 + editor_state->get_speed() * 10 ))); } } else { @@ -251,11 +251,11 @@ int main() { break; case sf::Keyboard::Right: if (event.key.shift) { - if (editor_state and editor_state->music_state) { - editor_state->music_state->speed_up(); + if (editor_state) { + editor_state->speed_up(); notificationsQueue.push(std::make_shared(fmt::format( "Speed : {}%", - editor_state->music_state->speed * 10 + editor_state->get_speed() * 10 ))); } } else { @@ -397,28 +397,23 @@ int main() { // Audio playback management if (editor_state) { - if (editor_state->chart_state) { - editor_state->chart_state->update_visible_notes( - editor_state->playback_position, - editor_state->applicable_timing - ); - } + editor_state->update_visible_notes(); if (editor_state->playing) { editor_state->previous_playback_position = editor_state->playback_position; - editor_state->playback_position += delta * (editor_state->musicSpeed / 10.f); + editor_state->playback_position += delta * (editor_state->get_speed() / 10.f); if (editor_state->music) { switch (editor_state->music->getStatus()) { case sf::Music::Stopped: case sf::Music::Paused: - if (editor_state->playbackPosition.asSeconds() >= 0 - and editor_state->playbackPosition + if (editor_state->playback_position.asSeconds() >= 0 + and editor_state->playback_position < editor_state->music->getDuration()) { - editor_state->music->setPlayingOffset(editor_state->playbackPosition); + editor_state->music->setPlayingOffset(editor_state->playback_position); editor_state->music->play(); } break; case sf::Music::Playing: - editor_state->playbackPosition = + editor_state->playback_position = editor_state->music->getPrecisePlayingOffset(); break; default: @@ -427,9 +422,9 @@ int main() { } if (beatTick.shouldPlay) { auto previous_tick = static_cast(editor_state->ticks_at( - editor_state->previousPos.asSeconds())); + editor_state->previous_playback_position.asSeconds())); auto current_tick = static_cast(editor_state->ticks_at( - editor_state->playbackPosition.asSeconds())); + editor_state->playback_position.asSeconds())); if (previous_tick / editor_state->getResolution() != current_tick / editor_state->getResolution()) { beatTick.play(); @@ -439,8 +434,8 @@ int main() { int note_count = 0; for (auto note : editor_state->visibleNotes) { float noteTiming = editor_state->getSecondsAt(note.getTiming()); - if (noteTiming >= editor_state->previousPos.asSeconds() - and noteTiming <= editor_state->playbackPosition.asSeconds()) { + if (noteTiming >= editor_state->previous_playback_position.asSeconds() + and noteTiming <= editor_state->playback_position.asSeconds()) { note_count++; } } @@ -455,9 +450,9 @@ int main() { } } - if (editor_state->playbackPosition > editor_state->getPreviewEnd()) { + if (editor_state->playback_position > editor_state->getPreviewEnd()) { editor_state->playing = false; - editor_state->playbackPosition = editor_state->getPreviewEnd(); + editor_state->playback_position = editor_state->getPreviewEnd(); } } else { if (editor_state->music) { diff --git a/src/meson.build b/src/meson.build index af8c771..2f8e3a9 100644 --- a/src/meson.build +++ b/src/meson.build @@ -16,7 +16,6 @@ sources += files( 'ln_marker.cpp', 'main.cpp', 'marker.cpp', - 'music_state.cpp', 'note.cpp', 'notes_clipboard.cpp', 'notification.cpp', diff --git a/src/music_state.cpp b/src/music_state.cpp deleted file mode 100644 index 786af71..0000000 --- a/src/music_state.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "music_state.hpp" -#include "toolbox.hpp" - - -void MusicState::set_speed(int newMusicSpeed) { - speed = std::clamp(newMusicSpeed, 1, 20); - music.setPitch(speed / 10.f); -} - -void MusicState::speed_up() { - set_speed(speed + 1); -} - -void MusicState::speed_down() { - set_speed(speed - 1); -} - -void MusicState::set_volume(int newMusicVolume) { - volume = std::clamp(newMusicVolume, 0, 10); - music.setVolume(Toolbox::convertVolumeToNormalizedDB(volume)*100.f); -} - -void MusicState::volume_up() { - set_volume(volume + 1); -} - -void MusicState::volume_down() { - set_volume(volume - 1); -} \ No newline at end of file diff --git a/src/music_state.hpp b/src/music_state.hpp deleted file mode 100644 index 2804bfd..0000000 --- a/src/music_state.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include - -#include "precise_music.hpp" - -struct MusicState { - explicit MusicState(const std::filesystem::path& path) : music(path) {}; - PreciseMusic music; - int volume = 10; // 0 -> 10 - void set_volume(int newMusicVolume); - void volume_up(); - void volume_down(); - - int speed = 10; // 1 -> 20 - void set_speed(int newMusicSpeed); - void speed_up(); - void speed_down(); -}; \ No newline at end of file diff --git a/src/playfield.hpp b/src/playfield.hpp index 5deed63..fcc5840 100644 --- a/src/playfield.hpp +++ b/src/playfield.hpp @@ -7,54 +7,54 @@ #include #include -// #include "better_note.hpp" -// #include "better_timing.hpp" -// #include "ln_marker.hpp" -// #include "marker.hpp" - -struct LongNote { -// template -// LongNote(Ts&&... Args) : marker(std::forward(Args)...) {}; - - LNMarker marker; - sf::RenderTexture layer; - sf::Sprite backgroud; - sf::Sprite outline; - sf::Sprite highlight; - sf::Sprite tail; - sf::Sprite triangle; -}; +#include "better_note.hpp" +#include "better_timing.hpp" +#include "ln_marker.hpp" +#include "marker.hpp" class Playfield { -// public: -// Playfield(std::filesystem::path assets_folder); -// sf::Texture base_texture; -// sf::Sprite button; -// sf::Sprite button_pressed; -// sf::Sprite note_selected; -// sf::Sprite note_collision; +public: + Playfield(std::filesystem::path assets_folder); + sf::Texture base_texture; + sf::Sprite button; + sf::Sprite button_pressed; + sf::Sprite note_selected; + sf::Sprite note_collision; -// sf::RenderTexture marker_layer; -// sf::Sprite marker_sprite; + sf::RenderTexture marker_layer; + sf::Sprite marker_sprite; -// LongNote long_note; + struct LongNote { + template + LongNote(Ts&&... Args) : marker(std::forward(Args)...) {}; -// void resize(unsigned int width); + LNMarker marker; + sf::RenderTexture layer; + sf::Sprite backgroud; + sf::Sprite outline; + sf::Sprite highlight; + sf::Sprite tail; + sf::Sprite triangle; + }; + + LongNote long_note; -// void draw_tail_and_receptor( -// const better::LongNote& note, -// const sf::Time& playbackPosition, -// const better::Timing& timing -// ); + void resize(unsigned int width); -// void draw_long_note( -// const better::LongNote& note, -// const sf::Time& playbackPosition, -// const better::Timing& timing, -// Marker& marker, -// MarkerEndingState& markerEndingState -// ); + void draw_tail_and_receptor( + const better::LongNote& note, + const sf::Time& playbackPosition, + const better::Timing& timing + ); -// private: -// const std::filesystem::path texture_path; + void draw_long_note( + const better::LongNote& note, + const sf::Time& playbackPosition, + const better::Timing& timing, + Marker& marker, + MarkerEndingState& markerEndingState + ); + +private: + const std::filesystem::path texture_path; }; diff --git a/src/special_numeric_types.cpp b/src/special_numeric_types.cpp index 4b9c48f..8f11819 100644 --- a/src/special_numeric_types.cpp +++ b/src/special_numeric_types.cpp @@ -30,15 +30,6 @@ Fraction round_fraction(const Fraction& f) { return floor_fraction(f + Fraction{1, 2}); }; -Decimal convert_to_decimal(const Fraction& f, std::uint64_t precision) { - const Fraction precision_mod = fast_pow(Fraction{1, 10}, precision); - const Fraction floored = f - (f % precision_mod); - return ( - Decimal{convert_to_int64(floored.get_num())} - / Decimal{convert_to_int64(floored.get_den())} - ); -}; - Fraction convert_to_fraction(const Decimal& d) { const auto reduced = d.reduce(); const auto sign = reduced.sign(); @@ -47,7 +38,7 @@ Fraction convert_to_fraction(const Decimal& d) { if (exponent >= 0) { return Fraction{sign > 0 ? 1 : -1} * Fraction{coefficient} * fast_pow(Fraction{10}, exponent); } else { - return Fraction{sign > 0 ? 1 : -1} * Fraction{coefficient} / fast_pow(Fraction{10}, exponent); + return Fraction{sign > 0 ? 1 : -1} * Fraction{coefficient} / fast_pow(Fraction{10}, -exponent); } }; @@ -61,37 +52,4 @@ Fraction floor_beats(Fraction beats, std::uint64_t denominator) { beats *= denominator; const auto nearest = floor_fraction(beats); return nearest / Fraction{denominator}; -}; - -mpz_class convert_to_mpz(std::uint64_t u) { - auto low = static_cast(u); - auto high = static_cast(u >> 32); - return mpz_class{low} + (mpz_class{high} << 32); -}; - -mpz_class convert_to_mpz(std::int64_t i) { - if (i < 0) { - return -1 * convert_to_mpz(static_cast(-1 * i)); - } else { - return convert_to_mpz(static_cast(i)); - } -}; - -std::uint64_t convert_to_uint64(const mpz_class& m) { - if (m < 0) { - throw std::invalid_argument("Cannot convert negative mpz to std::uint64_t"); - } - - const auto low = static_cast(m.get_ui()); - const mpz_class high_m = m >> 32; - const auto high = static_cast(high_m.get_ui()); - return low + (high << 32); -}; - -std::int64_t convert_to_int64(const mpz_class& m) { - if (m < 0) { - return -1 * static_cast(convert_to_uint64(-1 * m)); - } else { - return static_cast(convert_to_uint64(m)); - } }; \ No newline at end of file diff --git a/src/special_numeric_types.hpp b/src/special_numeric_types.hpp index 092c675..a4479ec 100644 --- a/src/special_numeric_types.hpp +++ b/src/special_numeric_types.hpp @@ -13,7 +13,6 @@ std::strong_ordering operator<=>(const Fraction& lhs, const Fraction& rhs); Fraction operator%(Fraction a, const Fraction& b); Fraction floor_fraction(const Fraction& f); Fraction round_fraction(const Fraction& f); -Decimal convert_to_decimal(const Fraction& f, std::uint64_t precision); Fraction convert_to_fraction(const Decimal& d); // Rounds a given beat to the nearest given division (defaults to nearest 1/240th) @@ -35,9 +34,4 @@ Number fast_pow(const Number base, const std::uint64_t exponent) { n /= 2; } return result; -}; - -mpz_class convert_to_mpz(std::uint64_t u); -mpz_class convert_to_mpz(std::int64_t i); -std::uint64_t convert_to_uint64(const mpz_class& m); -std::int64_t convert_to_int64(const mpz_class& m); \ No newline at end of file +}; \ No newline at end of file diff --git a/src/std_optional_extras.hpp b/src/std_optional_extras.hpp index 1de2458..c58b74b 100644 --- a/src/std_optional_extras.hpp +++ b/src/std_optional_extras.hpp @@ -1,11 +1,12 @@ #pragma once +#include #include #include #include template -B apply_or(std::optional opt, B(*func)(A), B b) { +B apply_or(std::optional opt, std::function func, B b) { if (opt.has_value()) { return func(*opt); } else { @@ -15,14 +16,13 @@ B apply_or(std::optional opt, B(*func)(A), B b) { template std::string stringify_or(std::optional opt, std::string fallback) { - auto cb = [](const A& a){ - std::stringstream ss; - ss << a; - return ss.str(); - }; return apply_or( opt, - &cb, + [](const A& a) -> std::string { + std::stringstream ss; + ss << a; + return ss.str(); + }, fallback ); } \ No newline at end of file diff --git a/src/widgets/linear_view.cpp b/src/widgets/linear_view.cpp index 7112aa7..c3a2aef 100644 --- a/src/widgets/linear_view.cpp +++ b/src/widgets/linear_view.cpp @@ -54,7 +54,7 @@ void LinearView::resize(unsigned int width, unsigned int height) { void LinearView::update( const ChartState& chart_state, - const Timing& timing, + const better::Timing& timing, const sf::Time& playback_position, const ImVec2& size ) {