Interpolate music sample rate

This commit is contained in:
NaiJi ✨ 2021-07-19 20:59:23 +03:00
parent bf409c0a61
commit 80d2c97766
6 changed files with 57 additions and 33 deletions

View File

@ -16,7 +16,7 @@ public:
virtual void putToGame(const microsec &offset) = 0; virtual void putToGame(const microsec &offset) = 0;
virtual bool isInGame() const = 0; virtual bool isInGame() const = 0;
virtual bool isExpired() const = 0; virtual bool shouldRemove() const = 0;
microsec offset() const microsec offset() const
{ {

View File

@ -9,11 +9,12 @@ Beatmap ClassicMapCreator::createBeatmap(const std::string& filepath) const
{ {
(void) filepath; (void) filepath;
microsec starting_beat_offset = 352162; microsec starting_beat_offset = 362162;
int amount_of_beats = 209; int amount_of_beats = 209;
microsec interval = 1412162; microsec interval = 1412162;
microsec tempo_interval = interval / 4; microsec tempo_interval = interval / 2;
microsec note_input_offset = 412162 / 3; microsec note_input_offset = 412162 / 2;
microsec note_input_offset_fast = 412162 / 6;
microsec bpm_iterator = starting_beat_offset; microsec bpm_iterator = starting_beat_offset;
microsec bpm_end = starting_beat_offset + (interval * amount_of_beats); microsec bpm_end = starting_beat_offset + (interval * amount_of_beats);
@ -30,7 +31,7 @@ Beatmap ClassicMapCreator::createBeatmap(const std::string& filepath) const
while (bpm_iterator < bpm_end) while (bpm_iterator < bpm_end)
{ {
ClassicNote::ClassicNoteInitializer init; ClassicNote::ClassicNoteInitializer init;
ClassicNote::ClassicNoteInitializer::Element element, element2; ClassicNote::ClassicNoteInitializer::Element element;
init.intervals = input_intervals; init.intervals = input_intervals;
init.perfect_offset = bpm_iterator; init.perfect_offset = bpm_iterator;
@ -39,22 +40,29 @@ Beatmap ClassicMapCreator::createBeatmap(const std::string& filepath) const
element.keys = {sf::Keyboard::W, sf::Keyboard::Up}; element.keys = {sf::Keyboard::W, sf::Keyboard::Up};
element.type = Type::UP; element.type = Type::UP;
init.elements = {element};
notes.emplace_back(new ClassicNote(std::move(init), _graphics_manager));
if (counter == 0) if (counter == 0)
{ {
counter = 3; ClassicNote::ClassicNoteInitializer init2;
element2.coordinates = {x, 300.}; ClassicNote::ClassicNoteInitializer::Element element2;
element2.falling_curve_interpolation = {}; init2.intervals = input_intervals;
element2.keys = {sf::Keyboard::A, sf::Keyboard::Left}; init2.perfect_offset = bpm_iterator + note_input_offset_fast;
element2.type = Type::LEFT;
init.elements = {element, element2}; element2.coordinates = {x + 35, 390. + 50.};
element2.falling_curve_interpolation = {};
element2.keys = {sf::Keyboard::D, sf::Keyboard::Right};
element2.type = Type::RIGHT;
init2.elements = {element2};
notes.emplace_back(new ClassicNote(std::move(init2), _graphics_manager));
counter = 3;
} }
else
init.elements = {element};
--counter; --counter;
notes.emplace_back(new ClassicNote(std::move(init), _graphics_manager));
bpm_iterator += tempo_interval; bpm_iterator += tempo_interval;
x += 70; x += 70;

View File

@ -1,8 +1,11 @@
#include "classicnote.h" #include "classicnote.h"
#include "classicsprite.h" #include "classicsprite.h"
#include "classicgraphicsmanager.h" #include "classicgraphicsmanager.h"
// Replace with interface by dependency injection
#include "classicflyinganimationscenario.h" #include "classicflyinganimationscenario.h"
#include "classicdyinganimationscenario.h" #include "classicdyinganimationscenario.h"
//
ClassicNote::ClassicNote(ClassicNoteInitializer &&init, const std::unique_ptr<ClassicGraphicsManager> &manager) : ClassicNote::ClassicNote(ClassicNoteInitializer &&init, const std::unique_ptr<ClassicGraphicsManager> &manager) :
Note(init.perfect_offset), Note(init.perfect_offset),
@ -17,6 +20,7 @@ ClassicNote::ClassicNote(ClassicNoteInitializer &&init, const std::unique_ptr<Cl
_elements[i].coordinates = init.elements[i].coordinates; _elements[i].coordinates = init.elements[i].coordinates;
_elements[i].type = init.elements[i].type; _elements[i].type = init.elements[i].type;
// Animations will be injected into note.
_elements[i].animations[State::NONE] = nullptr; _elements[i].animations[State::NONE] = nullptr;
_elements[i].animations[State::FLYING] = std::make_shared<ClassicFlyingAnimationScenario>(); _elements[i].animations[State::FLYING] = std::make_shared<ClassicFlyingAnimationScenario>();
_elements[i].animations[State::ACTIVE] = _elements[i].animations[State::FLYING]; _elements[i].animations[State::ACTIVE] = _elements[i].animations[State::FLYING];
@ -49,7 +53,7 @@ bool ClassicNote::isInGame() const
|| _state == State::DYING; || _state == State::DYING;
} }
bool ClassicNote::isExpired() const bool ClassicNote::shouldRemove() const
{ {
return _state == State::DEAD; return _state == State::DEAD;
} }

View File

@ -56,7 +56,7 @@ public:
virtual void input(PlayerInput&& inputdata) override; virtual void input(PlayerInput&& inputdata) override;
virtual void putToGame(const microsec &music_offset) override; virtual void putToGame(const microsec &music_offset) override;
virtual bool isInGame() const override; virtual bool isInGame() const override;
virtual bool isExpired() const override; virtual bool shouldRemove() const override;
virtual void draw() const override; virtual void draw() const override;
private: private:
@ -67,11 +67,11 @@ private:
std::array<std::shared_ptr<ClassicAnimationScenario>, 5> animations; std::array<std::shared_ptr<ClassicAnimationScenario>, 5> animations;
std::array<sf::Keyboard::Key, 2> keys; std::array<sf::Keyboard::Key, 2> keys;
Coordinates coordinates; Coordinates coordinates; // Each note may consist of several buttons.
Type type; Type type; // For example, ↑ → or ↓ → ←
// Note Element represents this idea.
bool pressed = false; bool pressed = false; // Each ending button in such sequence
sf::Keyboard::Key pressed_as; sf::Keyboard::Key pressed_as; // is an element.
}; };
std::vector<NoteElement> _elements; std::vector<NoteElement> _elements;

View File

@ -2,7 +2,10 @@
#include "classictimeline.h" #include "classictimeline.h"
#include <iostream> #include <iostream>
ClassicTimeline::ClassicTimeline() ClassicTimeline::ClassicTimeline() :
_sfml_music_offset(0),
_previous_frame_offset(0),
_absolute_offset(0)
{ {
// BPM of METEOR is 170. // BPM of METEOR is 170.
// Length is 1:14 // Length is 1:14
@ -12,7 +15,6 @@ ClassicTimeline::ClassicTimeline()
_music.openFromFile(song_filename); _music.openFromFile(song_filename);
_music.setVolume(10); _music.setVolume(10);
_last_timestamp = -1;
} }
void ClassicTimeline::run(std::vector<Note*>&& notes, const microsec& visibility) void ClassicTimeline::run(std::vector<Note*>&& notes, const microsec& visibility)
@ -27,6 +29,8 @@ void ClassicTimeline::run(std::vector<Note*>&& notes, const microsec& visibility
fetchVisibleNotes(); fetchVisibleNotes();
_music.play(); _music.play();
_previous_frame_offset = _offset_interpolator.restart().asMicroseconds();
} }
ClassicTimeline::~ClassicTimeline() ClassicTimeline::~ClassicTimeline()
@ -44,15 +48,20 @@ void ClassicTimeline::clear()
void ClassicTimeline::update() void ClassicTimeline::update()
{ {
const auto& music_offset = currentMusicOffset(); const auto interpolator_timestamp = _offset_interpolator.getElapsedTime().asMicroseconds();
if (music_offset != _last_timestamp) const auto sfml_new_offset = currentMusicOffset();
_absolute_offset += (interpolator_timestamp - _previous_frame_offset);
_previous_frame_offset = interpolator_timestamp;
if (sfml_new_offset != _sfml_music_offset)
{ {
checkCurrentActiveNote(); _absolute_offset = ((_absolute_offset + sfml_new_offset) / 2);
checkForNextActiveNote(); _sfml_music_offset = sfml_new_offset;
updateVisibleSprites(music_offset);
} }
_last_timestamp = music_offset; checkCurrentActiveNote();
checkForNextActiveNote();
updateVisibleSprites(_absolute_offset);
} }
void ClassicTimeline::checkCurrentActiveNote() void ClassicTimeline::checkCurrentActiveNote()
@ -118,8 +127,7 @@ bool ClassicTimeline::isVisiblyClose(const Iterator& iterator, const microsec& m
void ClassicTimeline::fetchVisibleNotes() void ClassicTimeline::fetchVisibleNotes()
{ {
const microsec music_offset = currentMusicOffset(); findLastVisibleNote(_absolute_offset);
findLastVisibleNote(music_offset);
findFirstVisibleNote(); findFirstVisibleNote();
} }
@ -151,7 +159,7 @@ void ClassicTimeline::findFirstVisibleNote()
while (note_iterator != _last_visible_note) while (note_iterator != _last_visible_note)
{ {
auto note = *note_iterator; auto note = *note_iterator;
if (note->isExpired()) if (note->shouldRemove())
++_first_visible_note; ++_first_visible_note;
++note_iterator; ++note_iterator;

View File

@ -3,6 +3,7 @@
#include "timeline.h" #include "timeline.h"
#include <SFML/Audio/Music.hpp> #include <SFML/Audio/Music.hpp>
#include <SFML/System/Clock.hpp>
#include <vector> #include <vector>
#include <memory> #include <memory>
@ -33,9 +34,12 @@ private:
std::vector<microsec> _input_intervals; std::vector<microsec> _input_intervals;
std::vector<Note*> _timeline; std::vector<Note*> _timeline;
microsec _visibility_offset; microsec _visibility_offset;
microsec _last_timestamp;
sf::Music _music; sf::Music _music;
sf::Clock _offset_interpolator;
microsec _sfml_music_offset;
microsec _previous_frame_offset;
microsec _absolute_offset;
void updateVisibleSprites(const microsec& music_offset); void updateVisibleSprites(const microsec& music_offset);
void checkCurrentActiveNote(); void checkCurrentActiveNote();