Refactor music position, implement flow for Editor, link everything together

This commit is contained in:
NaiJi ✨ 2021-12-03 22:21:27 +03:00
parent 79543f6b93
commit 5e3ddccac0
19 changed files with 165 additions and 131 deletions

View File

@ -2,6 +2,7 @@
#include <set> #include <set>
#include "core/inputtype.h" #include "core/inputtype.h"
#include "core/updatedata.h"
#include "core/bpmsection.h" #include "core/bpmsection.h"
class Editor class Editor
@ -10,7 +11,7 @@ public:
virtual ~Editor() = default; virtual ~Editor() = default;
virtual void input(PlayerInput&& inputdata) = 0; virtual void input(PlayerInput&& inputdata) = 0;
virtual void update(const sf::Time& dt) = 0; virtual void update(UpdateData&& updatedata) = 0;
virtual void draw() const = 0; virtual void draw() const = 0;
inline void setBPMSections(const std::set<BPMSection, BPMSectionCompt>& sections) noexcept inline void setBPMSections(const std::set<BPMSection, BPMSectionCompt>& sections) noexcept

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "core/inputtype.h" #include "core/inputtype.h"
#include "core/updatedata.h"
class Game class Game
{ {
@ -10,6 +11,6 @@ public:
virtual void run() = 0; virtual void run() = 0;
virtual void input(PlayerInput&& inputdata) = 0; virtual void input(PlayerInput&& inputdata) = 0;
virtual void update() = 0; virtual void update(UpdateData&& updatedata) = 0;
virtual void draw() const = 0; virtual void draw() const = 0;
}; };

View File

@ -28,6 +28,9 @@ public:
expire(_last_visible_note); expire(_last_visible_note);
expire(_active_note); expire(_active_note);
if (isExpired(_top_note))
return;
fetchVisibleNotes(); fetchVisibleNotes();
} }
@ -55,21 +58,20 @@ public:
{ {
_current_offset = offset; _current_offset = offset;
if (isExpired(_top_note))
return;
checkCurrentActiveNote(); checkCurrentActiveNote();
checkForNextActiveNote(); checkForNextActiveNote();
updateVisibleSprites(_current_offset); updateVisibleSprites(_current_offset);
} }
void drawVisibleNotes() const std::pair<Iterator, Iterator> getVisibleNotes() const
{ {
if (nothingToDraw()) if (nothingToDraw())
return; return std::pair<Iterator, Iterator>();
std::for_each(_first_visible_note, _last_visible_note, return std::make_pair(_first_visible_note, _last_visible_note);
[](const auto& note)
{
note->draw();
});
} }
void fetchVisibleNotes() void fetchVisibleNotes()
@ -80,6 +82,9 @@ public:
void findLastVisibleNote(const microsec& music_offset) void findLastVisibleNote(const microsec& music_offset)
{ {
if (isExpired(_top_note))
return;
Iterator note_iterator = _top_note; Iterator note_iterator = _top_note;
while (isVisiblyClose(note_iterator, music_offset)) while (isVisiblyClose(note_iterator, music_offset))
{ {

View File

@ -0,0 +1,10 @@
#pragma once
#include <SFML/System/Time.hpp>
#include "tools/mathutils.h"
struct UpdateData
{
const microsec timestamp;
const sf::Time dt;
};

View File

@ -2,15 +2,17 @@
ClassicEditor::ClassicEditor(std::shared_ptr<ClassicGraphicsManager>&& manager) : ClassicEditor::ClassicEditor(std::shared_ptr<ClassicGraphicsManager>&& manager) :
_graphics_manager(manager), _graphics_manager(manager),
_selected_type(Type::UP) _selected_type(Type::UP),
_current_time(0)
{ {
_context.graphics_manager = _graphics_manager; _context.graphics_manager = _graphics_manager;
_timeline.setNotes({}, 1648648);
} }
void ClassicEditor::input(PlayerInput&& inputdata) void ClassicEditor::input(PlayerInput&& inputdata)
{ {
_current_time = inputdata.timestamp;
const auto& event = inputdata.event; const auto& event = inputdata.event;
const auto offset = _music.fetchOffset();
switch (event.type) switch (event.type)
{ {
@ -20,13 +22,13 @@ void ClassicEditor::input(PlayerInput&& inputdata)
case sf::Event::MouseButtonPressed: case sf::Event::MouseButtonPressed:
{ {
const auto note = _timeline.getNoteBy(offset); const auto note = _timeline.getNoteBy(_current_time);
if (_timeline.isExpired(note)) if (_timeline.isExpired(note))
{ {
NoteInitializer init; NoteInitializer init;
init.context = &_context; init.context = &_context;
init.intervals = {}; init.intervals = {};
init.perfect_offset = offset; init.perfect_offset = _current_time;
ElementInitializer elem_init; ElementInitializer elem_init;
elem_init.type = _selected_type; elem_init.type = _selected_type;
@ -45,18 +47,22 @@ void ClassicEditor::input(PlayerInput&& inputdata)
} }
} }
void ClassicEditor::update(const sf::Time& dt) void ClassicEditor::update(UpdateData&& updatedata)
{ {
(void)dt; _timeline.update(updatedata.timestamp);
// TODO!!!
_timeline.update(_music.fetchOffset());
_timeline.fetchVisibleNotes(); _timeline.fetchVisibleNotes();
} }
void ClassicEditor::draw() const void ClassicEditor::draw() const
{ {
_timeline.drawVisibleNotes(); const auto& graphics_manager = _graphics_manager;
auto notes = _timeline.getVisibleNotes();
std::for_each(notes.first, notes.second,
[graphics_manager](const auto& note)
{
note->draw();
});
} }
void ClassicEditor::selectNoteType(Type type) noexcept void ClassicEditor::selectNoteType(Type type) noexcept

View File

@ -4,7 +4,6 @@
#include "core/editor.h" #include "core/editor.h"
#include "core/timeline.h" #include "core/timeline.h"
#include "tools/music.h"
#include "mockclassicnote.h" #include "mockclassicnote.h"
@ -16,17 +15,17 @@ public:
explicit ClassicEditor(std::shared_ptr<ClassicGraphicsManager>&& manager); explicit ClassicEditor(std::shared_ptr<ClassicGraphicsManager>&& manager);
virtual void input(PlayerInput&& inputdata) override; virtual void input(PlayerInput&& inputdata) override;
virtual void update(const sf::Time& dt) override; virtual void update(UpdateData&& updatedata) override;
virtual void draw() const override; virtual void draw() const override;
void selectNoteType(Type type) noexcept; void selectNoteType(Type type) noexcept;
private: private:
Music _music;
Context _context; Context _context;
std::shared_ptr<ClassicGraphicsManager> _graphics_manager; std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
Timeline<MockClassicNote> _timeline; Timeline<MockClassicNote> _timeline;
Type _selected_type; Type _selected_type;
microsec _current_time;
}; };

View File

@ -1,6 +1,7 @@
#include "classicgame.h" #include "classicgame.h"
#include "classicnote.h" #include "classicnote.h"
#include "classicmapcreator.h" #include "classicmapcreator.h"
#include "graphics/classicgraphicsmanager.h"
#include "holdmanager.h" #include "holdmanager.h"
ClassicGame::ClassicGame(std::shared_ptr<ClassicGraphicsManager>&& manager) : ClassicGame::ClassicGame(std::shared_ptr<ClassicGraphicsManager>&& manager) :
@ -59,16 +60,11 @@ void ClassicGame::run()
_context.graphics_manager = _graphics_manager; _context.graphics_manager = _graphics_manager;
auto beatmap = classic::createBeatmap("aa", _context); auto beatmap = classic::createBeatmap("aa", _context);
_music.openFromFile("METEOR.flac");
_music.setVolume(10);
_music.play();
_timeline.setNotes(beatmap.notes, beatmap.visibility_offset); _timeline.setNotes(beatmap.notes, beatmap.visibility_offset);
} }
void ClassicGame::input(PlayerInput&& inputdata) void ClassicGame::input(PlayerInput&& inputdata)
{ {
inputdata.timestamp = _music.fetchOffset();
switch (inputdata.event.type) switch (inputdata.event.type)
{ {
default: default:
@ -77,20 +73,6 @@ void ClassicGame::input(PlayerInput&& inputdata)
case sf::Event::KeyPressed: case sf::Event::KeyPressed:
{ {
if (inputdata.event.key.code == sf::Keyboard::Space)
{
if (_music.isPaused())
{
_music.play();
return;
}
else
{
_music.pause();
return;
}
}
auto note_it = _timeline.getActiveNote(); auto note_it = _timeline.getActiveNote();
if (!_timeline.isExpired(note_it)) if (!_timeline.isExpired(note_it))
@ -111,13 +93,20 @@ void ClassicGame::input(PlayerInput&& inputdata)
} }
} }
void ClassicGame::update() void ClassicGame::update(UpdateData&& updatedata)
{ {
_timeline.update(_music.fetchOffset()); _timeline.update(updatedata.timestamp);
_timeline.fetchVisibleNotes(); _timeline.fetchVisibleNotes();
} }
void ClassicGame::draw() const void ClassicGame::draw() const
{ {
_timeline.drawVisibleNotes(); const auto& graphics_manager = _graphics_manager;
auto notes = _timeline.getVisibleNotes();
std::for_each(notes.first, notes.second,
[graphics_manager](const auto& note)
{
note->draw();
});
} }

View File

@ -8,9 +8,8 @@
#include "core/game.h" #include "core/game.h"
#include "core/timeline.h" #include "core/timeline.h"
#include "tools/music.h"
#include "classicmode/context.h" #include "context.h"
#include "classicnote.h" #include "classicnote.h"
#include "classicmode/classicactions.h" #include "classicmode/classicactions.h"
@ -27,7 +26,7 @@ public:
virtual void run() override; virtual void run() override;
virtual void input(PlayerInput&& inputdata) override; virtual void input(PlayerInput&& inputdata) override;
virtual void update() override; virtual void update(UpdateData&& updatedata) override;
virtual void draw() const override; virtual void draw() const override;
private: private:
@ -42,6 +41,5 @@ private:
sf::SoundBuffer _slap_buffer; sf::SoundBuffer _slap_buffer;
sf::Sound _slap; sf::Sound _slap;
Music _music;
Context _context; Context _context;
}; };

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "classicmode/context.h" #include "context.h"
#include "core/note.h" #include "core/note.h"
#include "core/precisionevaluator.h" #include "core/precisionevaluator.h"
#include "classicmode/noteinitializer.h" #include "classicmode/noteinitializer.h"

View File

@ -0,0 +1,12 @@
#pragma once
#include <memory>
class ClassicGraphicsManager;
class HoldManager;
struct Context
{
std::shared_ptr<ClassicGraphicsManager> graphics_manager;
std::shared_ptr<HoldManager> hold_manager;
};

View File

@ -23,6 +23,9 @@ EditorState::~EditorState()
void EditorState::input(const sf::Event& event) void EditorState::input(const sf::Event& event)
{ {
if (event.key.code == sf::Keyboard::Space && event.type == sf::Event::KeyReleased)
_music.isPaused() ? _music.play() : _music.pause();
_group->input(event); _group->input(event);
} }
@ -38,19 +41,57 @@ void EditorState::draw() const
void EditorState::enter() void EditorState::enter()
{ {
_music.openFromFile("Uta-test.flac");
_music.setVolume(5);
auto& group = _group; auto& group = _group;
auto& music = _music; auto& music = _music;
auto& editor = _editor; auto& editor = _editor;
_music->openFromFile("Uta-test.flac"); _bpm_calculator = std::make_shared<BPMCalculator>();
_music->setVolume(5); auto& bpm_calculator = _bpm_calculator;
_bpm_calculator = std::make_shared<BPMCalculator>(_music);
std::shared_ptr<BPMCalculatorWidget> bpm_widget = std::make_shared<BPMCalculatorWidget>(_bpm_calculator, _font); std::shared_ptr<BPMCalculatorWidget> bpm_widget = std::make_shared<BPMCalculatorWidget>(_bpm_calculator, _font);
bpm_widget->init(_editor);
auto button_start = std::make_shared<PushButton>("Start", _font);
auto button_stop = std::make_shared<PushButton>("Stop", _font);
auto button_apply = std::make_shared<PushButton>("Apply", _font);
button_start->setCallback([bpm_calculator, button_start, button_stop, &music]()
{
music.play();
bpm_calculator->start();
button_start->setVisibility(false);
button_stop->setVisibility(true);
});
button_stop->setCallback([bpm_calculator, button_start, button_stop, &music]()
{
music.stop();
bpm_calculator->stop();
button_start->setVisibility(true);
button_stop->setVisibility(false);
});
button_apply->setCallback([&editor, bpm_calculator]()
{
BPMSection section;
section.bpm = bpm_calculator->fetchApproximatedInfo().BPM;
section.fraction = 2;
section.offset_start = bpm_calculator->getStartingOffset();
editor->insertBPMSection(std::move(section));
});
BPMCalculatorWidget::Init bpm_widget_init;
bpm_widget_init.stop = button_stop;
bpm_widget_init.apply = button_apply;
bpm_widget_init.start = button_start;
bpm_widget_init.current_time = [&music]() -> microsec { return music.fetchOffset(); };
bpm_widget->init(std::move(bpm_widget_init));
const auto bpm_widget_callback = [&group, bpm_widget=bpm_widget, &music]() const auto bpm_widget_callback = [&group, bpm_widget=bpm_widget, &music]()
{ {
music->stop(); music.stop();
bpm_widget->setVisibility(false); bpm_widget->setVisibility(false);
group->unblock(); group->unblock();
}; };
@ -113,14 +154,14 @@ void EditorState::enter()
editor->draw(); editor->draw();
}; };
callbacks.onInput = [&editor](const sf::Event& event) callbacks.onInput = [&editor, &music](const sf::Event& event)
{ {
editor->input(PlayerInput{0, event}); editor->input(PlayerInput{music.fetchOffset(), event});
}; };
callbacks.onUpdate = [&editor](const sf::Time& dt) callbacks.onUpdate = [&editor, &music](const sf::Time& dt)
{ {
editor->update(dt); editor->update(UpdateData{music.fetchOffset(), dt});
}; };
auto editor_widget = std::make_shared<EditorWidget>(std::move(callbacks)); auto editor_widget = std::make_shared<EditorWidget>(std::move(callbacks));

View File

@ -33,7 +33,7 @@ private:
Callbacks _callbacks; Callbacks _callbacks;
std::shared_ptr<Music> _music; Music _music;
std::shared_ptr<BPMCalculator> _bpm_calculator; std::shared_ptr<BPMCalculator> _bpm_calculator;
std::shared_ptr<Group> _group; std::shared_ptr<Group> _group;

View File

@ -13,17 +13,15 @@ GameState::GameState(sf::RenderWindow& game_window, const std::shared_ptr<Game>&
void GameState::input(const sf::Event& event) void GameState::input(const sf::Event& event)
{ {
_game->input({0, event}); if (event.key.code == sf::Keyboard::Space && event.type == sf::Event::KeyReleased)
_music.isPaused() ? _music.play() : _music.pause();
_game->input(PlayerInput{_music.fetchOffset(), event});
} }
void GameState::update(const sf::Time& dt) void GameState::update(const sf::Time& dt)
{ {
(void)dt; _game->update(UpdateData{_music.fetchOffset(), dt});
// !!!!!!!!!!!!!!!!!!!!!!
// TODO.
//
// Oh dude... hang in there
_game->update();
} }
void GameState::draw() const void GameState::draw() const
@ -34,6 +32,10 @@ void GameState::draw() const
void GameState::enter() void GameState::enter()
{ {
_game->run(); _game->run();
_music.openFromFile("METEOR.flac");
_music.setVolume(10);
_music.play();
} }
void GameState::leave() void GameState::leave()

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "state.h" #include "state.h"
#include "tools/music.h"
#include <SFML/Graphics/RenderWindow.hpp> #include <SFML/Graphics/RenderWindow.hpp>
class Group; class Group;
@ -28,6 +29,7 @@ public:
virtual void leave() override; virtual void leave() override;
private: private:
Music _music;
std::shared_ptr<Game> _game; std::shared_ptr<Game> _game;
sf::RenderWindow& _game_window; sf::RenderWindow& _game_window;

View File

@ -29,7 +29,7 @@ void BPMCalculatorWidget::input(const sf::Event& event)
case sf::Event::KeyPressed: case sf::Event::KeyPressed:
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space) if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space)
{ {
_bpm_calculator->click(); _bpm_calculator->click(_current_time());
} }
break; break;
} }
@ -46,7 +46,7 @@ void BPMCalculatorWidget::update(const sf::Time& dt)
{ {
_bpm_value.setString(std::to_string(static_cast<int>(beat_info.BPM))); _bpm_value.setString(std::to_string(static_cast<int>(beat_info.BPM)));
const microsec until_beat = _bpm_calculator->fetchTimeUntilNextBeat(); const microsec until_beat = _bpm_calculator->fetchTimeUntilNextBeat(_current_time());
const auto time_relation = static_cast<long double>(beat_info.interval) / static_cast<long double>(until_beat); const auto time_relation = static_cast<long double>(beat_info.interval) / static_cast<long double>(until_beat);
const auto slider_path_left = _slider->rect().width / time_relation; const auto slider_path_left = _slider->rect().width / time_relation;
if (slider_path_left < 50) if (slider_path_left < 50)
@ -111,39 +111,13 @@ void BPMCalculatorWidget::setPosition(const sf::Vector2f &position)
Window::setPosition(position); Window::setPosition(position);
} }
void BPMCalculatorWidget::init(const std::unique_ptr<Editor>& _editor) void BPMCalculatorWidget::init(Init &&init)
{ {
auto& bpm_calculator = _bpm_calculator; _button_start = init.start;
_button_stop = init.stop;
_button_apply = init.apply;
_button_start = std::make_shared<PushButton>("Start", _font); _current_time = init.current_time;
_button_stop = std::make_shared<PushButton>("Stop", _font);
_button_apply = std::make_shared<PushButton>("Apply", _font);
_button_start->setCallback([bpm_calculator, button_start=_button_start, button_stop=_button_stop]()
{
bpm_calculator->music()->play(); // Remove when global play/stop available
bpm_calculator->start();
button_start->setVisibility(false);
button_stop->setVisibility(true);
});
_button_stop->setCallback([bpm_calculator, button_start=_button_start, button_stop=_button_stop]()
{
bpm_calculator->music()->stop(); // Remove when global play/stop available
bpm_calculator->stop();
button_start->setVisibility(true);
button_stop->setVisibility(false);
});
_button_apply->setCallback([&_editor, bpm_calculator]()
{
BPMSection section;
section.bpm = bpm_calculator->fetchApproximatedInfo().BPM;
section.fraction = 2;
section.offset_start = bpm_calculator->getStartingOffset();
_editor->insertBPMSection(std::move(section));
});
addChild(_button_start); addChild(_button_start);
addChild(_button_stop); addChild(_button_stop);

View File

@ -8,6 +8,7 @@
#include <SFML/Graphics/Text.hpp> #include <SFML/Graphics/Text.hpp>
#include <SFML/Audio/Sound.hpp> #include <SFML/Audio/Sound.hpp>
#include <SFML/Audio/SoundBuffer.hpp> #include <SFML/Audio/SoundBuffer.hpp>
#include "tools/mathutils.h"
class BPMCalculator; class BPMCalculator;
class Editor; class Editor;
@ -15,6 +16,15 @@ class Editor;
class BPMCalculatorWidget : public Window class BPMCalculatorWidget : public Window
{ {
public: public:
struct Init
{
std::shared_ptr<PushButton> start;
std::shared_ptr<PushButton> stop;
std::shared_ptr<PushButton> apply;
std::function<microsec(void)> current_time;
};
explicit BPMCalculatorWidget(const std::shared_ptr<BPMCalculator>& bpm_calculator, const std::shared_ptr<sf::Font> &font); explicit BPMCalculatorWidget(const std::shared_ptr<BPMCalculator>& bpm_calculator, const std::shared_ptr<sf::Font> &font);
virtual void input(const sf::Event& event) override; virtual void input(const sf::Event& event) override;
@ -26,7 +36,7 @@ public:
virtual void setVisibility(bool is_visible = true) override; virtual void setVisibility(bool is_visible = true) override;
void init(const std::unique_ptr<Editor>& _editor); void init(Init&& init);
private: private:
std::shared_ptr<PushButton> _button_start; std::shared_ptr<PushButton> _button_start;
@ -41,5 +51,6 @@ private:
bool _ticked; bool _ticked;
sf::Text _bpm_value; sf::Text _bpm_value;
std::function<microsec(void)> _current_time;
}; };

View File

@ -7,19 +7,16 @@
class BPMCalculator class BPMCalculator
{ {
public: public:
explicit BPMCalculator(const std::shared_ptr<Music>& music); explicit BPMCalculator();
void setMusic(const std::shared_ptr<Music>& music);
std::shared_ptr<Music> music() const;
void start(); void start();
void stop(); void stop();
void click(); void click(const microsec& offset);
bool calculating() const; bool calculating() const;
const beat_utils::BeatInfo& fetchApproximatedInfo(); const beat_utils::BeatInfo& fetchApproximatedInfo();
microsec fetchTimeUntilNextBeat(); microsec fetchTimeUntilNextBeat(const microsec& offset);
microsec getStartingOffset() const; microsec getStartingOffset() const;
void setStartingOffset(microsec offset); void setStartingOffset(microsec offset);
@ -29,7 +26,6 @@ private:
bool _need_recalculate; bool _need_recalculate;
bool _calculating; bool _calculating;
std::shared_ptr<Music> _music;
std::vector<microsec> _deltas; std::vector<microsec> _deltas;
microsec _previous_click_offset; microsec _previous_click_offset;
microsec _first_click_offset; microsec _first_click_offset;

View File

@ -3,8 +3,7 @@
#include <numeric> #include <numeric>
#include <iostream> #include <iostream>
BPMCalculator::BPMCalculator(const std::shared_ptr<Music>& music) : BPMCalculator::BPMCalculator()
_music(music)
{ {
reset(); reset();
} }
@ -18,17 +17,6 @@ void BPMCalculator::reset()
_need_recalculate = true; _need_recalculate = true;
} }
void BPMCalculator::setMusic(const std::shared_ptr<Music>& music)
{
_music = music;
reset();
}
std::shared_ptr<Music> BPMCalculator::music() const
{
return _music;
}
void BPMCalculator::start() void BPMCalculator::start()
{ {
reset(); reset();
@ -46,25 +34,24 @@ bool BPMCalculator::calculating() const
return _calculating; return _calculating;
} }
void BPMCalculator::click() void BPMCalculator::click(const microsec &offset)
{ {
if (!_calculating) if (!_calculating)
return; return;
const microsec click_offset = _music->fetchOffset();
_need_recalculate = true; _need_recalculate = true;
if (_previous_click_offset == 0) if (_previous_click_offset == 0)
{ {
_previous_click_offset = click_offset; _previous_click_offset = offset;
_first_click_offset = click_offset; _first_click_offset = offset;
return; return;
} }
const microsec delta = click_offset - _previous_click_offset; const microsec delta = offset - _previous_click_offset;
_deltas.emplace_back(delta); _deltas.emplace_back(delta);
_previous_click_offset = click_offset; _previous_click_offset = offset;
} }
const beat_utils::BeatInfo& BPMCalculator::fetchApproximatedInfo() const beat_utils::BeatInfo& BPMCalculator::fetchApproximatedInfo()
@ -98,9 +85,9 @@ void BPMCalculator::moveStartingOffsetBy(microsec shift)
_first_click_offset += shift; _first_click_offset += shift;
} }
microsec BPMCalculator::fetchTimeUntilNextBeat() microsec BPMCalculator::fetchTimeUntilNextBeat(const microsec& offset)
{ {
const microsec actual_offset = _music->fetchOffset() - getStartingOffset(); const microsec actual_offset = offset - getStartingOffset();
return actual_offset % fetchApproximatedInfo().interval; return actual_offset % fetchApproximatedInfo().interval;
} }

View File

@ -29,7 +29,7 @@ void Music::stop()
bool Music::isPaused() const bool Music::isPaused() const
{ {
return (_music.getStatus() == sf::Music::Paused); return (_music.getStatus() != sf::Music::Playing);
} }
void Music::setVolume(int volume) void Music::setVolume(int volume)