2021-09-14 15:02:23 -04:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <algorithm>
|
2022-10-17 22:59:51 -04:00
|
|
|
#include <memory>
|
|
|
|
#include <set>
|
2021-09-14 15:02:23 -04:00
|
|
|
|
|
|
|
#include "core/note.h"
|
2022-10-17 22:59:51 -04:00
|
|
|
#include "core/time.h"
|
2021-09-14 15:02:23 -04:00
|
|
|
|
2021-12-29 09:59:18 -05:00
|
|
|
namespace kku
|
|
|
|
{
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
template <class TNote,
|
|
|
|
class = std::enable_if_t<std::is_base_of<Note, TNote>::value>>
|
2021-09-14 15:02:23 -04:00
|
|
|
class Timeline
|
|
|
|
{
|
2022-10-17 22:59:51 -04:00
|
|
|
public:
|
|
|
|
explicit Timeline() : _current_offset(0) {}
|
2021-09-14 15:02:23 -04:00
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
typedef typename std::set<TNote *>::const_iterator Iterator;
|
2021-09-14 15:02:23 -04:00
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
void recalculate(const microsec &offset)
|
2021-12-08 13:00:47 -05:00
|
|
|
{
|
|
|
|
_current_offset = offset;
|
|
|
|
expire(_top_note);
|
|
|
|
|
|
|
|
if (!_timeline.empty())
|
|
|
|
{
|
|
|
|
Iterator head_iterator = _timeline.begin();
|
|
|
|
|
|
|
|
while (!isExpired(head_iterator))
|
|
|
|
{
|
2021-12-29 09:59:18 -05:00
|
|
|
if ((*head_iterator)->getPerfectOffset() >= offset)
|
2021-12-08 13:00:47 -05:00
|
|
|
{
|
|
|
|
Iterator pre_head = head_iterator;
|
|
|
|
--pre_head;
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
_top_note =
|
|
|
|
!isExpired(pre_head) && (*pre_head)->isActive(offset)
|
|
|
|
? pre_head
|
|
|
|
: head_iterator;
|
2021-12-08 13:00:47 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
++head_iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isExpired(_top_note))
|
|
|
|
_top_note = _timeline.begin();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
void setNotes(const std::set<TNote *, NotePtrComparator> ¬es)
|
2021-09-14 15:02:23 -04:00
|
|
|
{
|
|
|
|
_timeline = std::move(notes);
|
|
|
|
|
2021-12-08 13:00:47 -05:00
|
|
|
recalculate(_current_offset);
|
2021-09-14 15:02:23 -04:00
|
|
|
|
2021-12-03 14:21:27 -05:00
|
|
|
if (isExpired(_top_note))
|
|
|
|
return;
|
2021-09-14 15:02:23 -04:00
|
|
|
}
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
void insertNote(TNote *note)
|
2021-10-03 11:23:28 -04:00
|
|
|
{
|
2021-12-06 14:18:04 -05:00
|
|
|
_top_note = _timeline.insert(note).first;
|
2021-12-08 13:00:47 -05:00
|
|
|
recalculate(_current_offset);
|
2021-10-03 11:23:28 -04:00
|
|
|
update(_current_offset);
|
|
|
|
}
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
void insertNotes(const std::set<TNote *, NotePtrComparator> ¬es)
|
2021-10-03 11:23:28 -04:00
|
|
|
{
|
|
|
|
_timeline.insert(notes.begin(), notes.end());
|
2021-12-08 13:00:47 -05:00
|
|
|
recalculate(_current_offset);
|
2021-10-03 11:23:28 -04:00
|
|
|
update(_current_offset);
|
|
|
|
}
|
|
|
|
|
2021-09-14 15:02:23 -04:00
|
|
|
inline void clear()
|
|
|
|
{
|
2022-10-17 22:59:51 -04:00
|
|
|
for (auto ¬e : _timeline)
|
2021-09-14 15:02:23 -04:00
|
|
|
delete note;
|
|
|
|
|
|
|
|
_timeline.clear();
|
|
|
|
}
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
void update(const microsec &offset)
|
2021-09-14 15:02:23 -04:00
|
|
|
{
|
|
|
|
_current_offset = offset;
|
2021-12-08 13:00:47 -05:00
|
|
|
updateTopNote(_current_offset);
|
2021-09-14 15:02:23 -04:00
|
|
|
}
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
Iterator getActiveNote(const microsec &music_offset) noexcept
|
2021-09-14 15:02:23 -04:00
|
|
|
{
|
2021-12-08 13:00:47 -05:00
|
|
|
Iterator return_note = _timeline.end();
|
|
|
|
|
|
|
|
auto note_iterator = _top_note;
|
|
|
|
while (!isExpired(note_iterator))
|
|
|
|
{
|
2022-10-17 22:59:51 -04:00
|
|
|
const auto ¬e = *note_iterator;
|
2021-12-08 13:00:47 -05:00
|
|
|
if (note->isActive(music_offset))
|
|
|
|
{
|
|
|
|
return_note = note_iterator;
|
|
|
|
break;
|
|
|
|
}
|
2021-12-29 09:59:18 -05:00
|
|
|
else if (note->getPerfectOffset() > music_offset)
|
2021-12-08 13:00:47 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
++note_iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
return return_note;
|
2021-09-14 15:02:23 -04:00
|
|
|
}
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
inline Iterator getNoteBy(const microsec &music_offset) noexcept
|
2021-11-24 13:21:30 -05:00
|
|
|
{
|
|
|
|
return std::find_if(_timeline.begin(), _timeline.end(),
|
2022-10-17 22:59:51 -04:00
|
|
|
[music_offset](const auto ¬e) {
|
2021-12-29 09:59:18 -05:00
|
|
|
return note->getPerfectOffset() == music_offset;
|
2021-11-24 13:21:30 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
inline bool isExpired(const Iterator &iterator) const noexcept
|
2021-09-14 15:02:23 -04:00
|
|
|
{
|
|
|
|
return iterator == _timeline.end();
|
|
|
|
}
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
inline void expire(Iterator &iterator) noexcept
|
2021-09-14 15:02:23 -04:00
|
|
|
{
|
|
|
|
iterator = _timeline.end();
|
|
|
|
}
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
inline Iterator getTopNote() const noexcept { return _top_note; }
|
2021-12-21 12:07:19 -05:00
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
inline Iterator begin() const noexcept { return _timeline.begin(); }
|
2022-02-16 14:20:13 -05:00
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
inline Iterator end() const noexcept { return _timeline.end(); }
|
2022-02-23 17:45:43 -05:00
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
private:
|
|
|
|
std::set<TNote *, NotePtrComparator> _timeline;
|
2021-09-14 15:02:23 -04:00
|
|
|
microsec _current_offset;
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
inline void updateTopNote(const microsec &music_offset) noexcept
|
2021-12-08 13:00:47 -05:00
|
|
|
{
|
2022-01-11 16:01:28 -05:00
|
|
|
if (isExpired(_top_note))
|
|
|
|
return;
|
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
const auto &top_note = *_top_note;
|
2021-09-14 15:02:23 -04:00
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
bool already_played = top_note->getPerfectOffset() < music_offset &&
|
|
|
|
!top_note->isActive(music_offset);
|
2021-09-14 15:02:23 -04:00
|
|
|
|
2021-12-21 10:48:39 -05:00
|
|
|
if (already_played)
|
|
|
|
++_top_note;
|
2021-09-14 15:02:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Iterator _top_note;
|
|
|
|
};
|
2021-12-29 09:59:18 -05:00
|
|
|
|
2022-10-17 22:59:51 -04:00
|
|
|
} // namespace kku
|