forked from NaiJi/project-kyoku
Interpolate music sample rate
This commit is contained in:
parent
bf409c0a61
commit
80d2c97766
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue