clangd is still absolutely sharting itself, I have to go the old-fashioned way and fix compiler errors one at a time ...

This commit is contained in:
Stepland 2022-04-07 00:14:01 +02:00
parent 3ab51d5bb1
commit 32ea4b309b
17 changed files with 258 additions and 301 deletions

View File

@ -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;
}
}

View File

@ -1,5 +1,6 @@
#include "better_timing.hpp"
#include <fmt/core.h>
#include <json.hpp>
#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<BPMAtBeat>& events, const SecondsAtBeat& offset) {
Timing::Timing(const std::vector<BPMAtBeat>& 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<BPMEvent> 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<double>(60 * beats_since_last_event)
/ static_cast<double>(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<BPMEvent> 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<double>(60 * beats_since_previous_event)
/ static_cast<double>(bpm_change->get_bpm())
);
return (
static_cast<double>(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<std::uint64_t>(time.asMicroseconds())), 1000000};
auto bpm_change = this->events_by_seconds.upper_bound(BPMEvent(0, fractional_seconds, 0));
const auto seconds = static_cast<double>(time.asMicroseconds()) / 1000000.0;
return beats_at(seconds);
};
Fraction Timing::beats_at(double seconds) const {
seconds -= static_cast<double>(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<std::string>();
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<std::string>()};
const auto offset = convert_to_fraction(Decimal{metadata["offset"].get<std::string>()});
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<std::string>()};
return Timing{{bpm, 0}, -1 * offset};
};
}

View File

@ -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<BPMAtBeat>& events, const SecondsAtBeat& offset);
Timing(const std::vector<BPMAtBeat>& 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<BPMEvent, OrderByBeats> events_by_beats;
std::set<BPMEvent, OrderBySeconds> events_by_seconds;
};
sf::Time frac_to_time(const Fraction& f);
}

View File

@ -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<sf::Time>& 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<sf::Time> 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<EditorState>& 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(

View File

@ -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<ChartState> chart_state;
std::optional<MusicState> music_state;
std::optional<PreciseMusic> 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<sf::Music> 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

View File

@ -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:

View File

@ -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);
}
}

View File

@ -44,7 +44,7 @@ private:
template<std::size_t number, unsigned int first = 0>
std::array<sf::Texture, number> load_tex_with_prefix(
const std::filesystem::path& folder,
const std::string& prefix,
const std::string& prefix
) {
std::array<sf::Texture, number> res;
for (unsigned int frame = first; frame <= first + number - 1; frame++) {
@ -52,17 +52,15 @@ std::array<sf::Texture, number> 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;

View File

@ -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<TextNotification>(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<TextNotification>(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<TextNotification>(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<TextNotification>(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<int>(editor_state->ticks_at(
editor_state->previousPos.asSeconds()));
editor_state->previous_playback_position.asSeconds()));
auto current_tick = static_cast<int>(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) {

View File

@ -16,7 +16,6 @@ sources += files(
'ln_marker.cpp',
'main.cpp',
'marker.cpp',
'music_state.cpp',
'note.cpp',
'notes_clipboard.cpp',
'notification.cpp',

View File

@ -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);
}

View File

@ -1,19 +0,0 @@
#pragma once
#include <filesystem>
#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();
};

View File

@ -7,54 +7,54 @@
#include <SFML/Graphics.hpp>
#include <SFML/Graphics/RenderTexture.hpp>
// #include "better_note.hpp"
// #include "better_timing.hpp"
// #include "ln_marker.hpp"
// #include "marker.hpp"
struct LongNote {
// template<typename ...Ts>
// LongNote(Ts&&... Args) : marker(std::forward<Ts>(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<typename ...Ts>
LongNote(Ts&&... Args) : marker(std::forward<Ts>(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;
};

View File

@ -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<std::uint32_t>(u);
auto high = static_cast<std::uint32_t>(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<std::uint64_t>(-1 * i));
} else {
return convert_to_mpz(static_cast<std::uint64_t>(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<std::uint64_t>(m.get_ui());
const mpz_class high_m = m >> 32;
const auto high = static_cast<std::uint64_t>(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<std::int64_t>(convert_to_uint64(-1 * m));
} else {
return static_cast<std::int64_t>(convert_to_uint64(m));
}
};

View File

@ -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);
};

View File

@ -1,11 +1,12 @@
#pragma once
#include <functional>
#include <optional>
#include <sstream>
#include <string>
template<class A, class B>
B apply_or(std::optional<A> opt, B(*func)(A), B b) {
B apply_or(std::optional<A> opt, std::function<B(A)> func, B b) {
if (opt.has_value()) {
return func(*opt);
} else {
@ -15,14 +16,13 @@ B apply_or(std::optional<A> opt, B(*func)(A), B b) {
template<class A>
std::string stringify_or(std::optional<A> 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
);
}

View File

@ -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
) {