mirror of
https://gitlab.com/square-game-liberation-front/F.E.I.S.git
synced 2025-02-28 23:41:33 +01:00
More things working with claps
This commit is contained in:
parent
d22d80a3e5
commit
b6e8d2b622
@ -2,7 +2,7 @@ sources += files([
|
|||||||
'al_check.cpp',
|
'al_check.cpp',
|
||||||
'al_resource.cpp',
|
'al_resource.cpp',
|
||||||
'audio_device.cpp',
|
'audio_device.cpp',
|
||||||
'clap_player.cpp',
|
'note_claps.cpp',
|
||||||
'open_music.cpp',
|
'open_music.cpp',
|
||||||
'open_sound_stream.cpp',
|
'open_sound_stream.cpp',
|
||||||
'precise_sound_stream.cpp',
|
'precise_sound_stream.cpp',
|
||||||
|
@ -1,36 +1,32 @@
|
|||||||
#include "clap_player.hpp"
|
#include "note_claps.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "../better_note.hpp"
|
#include "../better_note.hpp"
|
||||||
|
|
||||||
ClapPlayer::ClapPlayer(
|
NoteClaps::NoteClaps(
|
||||||
const better::Notes* notes_,
|
const better::Notes* notes_,
|
||||||
const better::Timing* timing_,
|
const better::Timing* timing_,
|
||||||
const std::filesystem::path& assets
|
const std::filesystem::path& assets
|
||||||
) :
|
) :
|
||||||
notes(notes_),
|
notes(notes_),
|
||||||
timing(timing_),
|
timing(timing_),
|
||||||
note_clap(),
|
note_clap()
|
||||||
chord_clap()
|
|
||||||
{
|
{
|
||||||
if (not note_clap.loadFromFile(assets / "sounds" / "note.wav")) {
|
if (not note_clap.loadFromFile(assets / "sounds" / "note.wav")) {
|
||||||
throw std::runtime_error("Could not load note clap audio file");
|
throw std::runtime_error("Could not load note clap audio file");
|
||||||
}
|
}
|
||||||
if (not chord_clap.loadFromFile(assets / "sounds" / "chord.wav")) {
|
|
||||||
throw std::runtime_error("Could not load chord clap audio file");
|
|
||||||
}
|
|
||||||
sf::SoundStream::initialize(note_clap.getChannelCount(), note_clap.getSampleRate());
|
sf::SoundStream::initialize(note_clap.getChannelCount(), note_clap.getSampleRate());
|
||||||
samples.resize(note_clap.getChannelCount() * note_clap.getSampleRate(), 0);
|
samples.resize(note_clap.getChannelCount() * note_clap.getSampleRate(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClapPlayer::set_notes_and_timing(const better::Notes* notes_, const better::Timing* timing_) {
|
void NoteClaps::set_notes_and_timing(const better::Notes* notes_, const better::Timing* timing_) {
|
||||||
notes = notes_;
|
notes = notes_;
|
||||||
timing = timing_;
|
timing = timing_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClapPlayer::onGetData(sf::SoundStream::Chunk& data) {
|
bool NoteClaps::onGetData(sf::SoundStream::Chunk& data) {
|
||||||
samples.assign(samples.size(), 0);
|
samples.assign(samples.size(), 0);
|
||||||
if (timing != nullptr and notes != nullptr) {
|
if (timing != nullptr and notes != nullptr) {
|
||||||
const auto start_sample = current_sample;
|
const auto start_sample = current_sample;
|
||||||
@ -51,7 +47,7 @@ bool ClapPlayer::onGetData(sf::SoundStream::Chunk& data) {
|
|||||||
// Should we still be playing the clap ?
|
// Should we still be playing the clap ?
|
||||||
const auto next = std::next(it);
|
const auto next = std::next(it);
|
||||||
const auto last_audible_start = start_sample - static_cast<std::int64_t>(note_clap.getSampleCount());
|
const auto last_audible_start = start_sample - static_cast<std::int64_t>(note_clap.getSampleCount());
|
||||||
if (it->first <= last_audible_start) {
|
if (it->first <= last_audible_start or ((not play_chords) and it->second > 1)) {
|
||||||
it = notes_at_sample.erase(it);
|
it = notes_at_sample.erase(it);
|
||||||
} else {
|
} else {
|
||||||
const auto full_clap_start_in_buffer = static_cast<std::int64_t>(it->first) - static_cast<std::int64_t>(start_sample);
|
const auto full_clap_start_in_buffer = static_cast<std::int64_t>(it->first) - static_cast<std::int64_t>(start_sample);
|
||||||
@ -92,12 +88,12 @@ bool ClapPlayer::onGetData(sf::SoundStream::Chunk& data) {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ClapPlayer::onSeek(sf::Time timeOffset) {
|
void NoteClaps::onSeek(sf::Time timeOffset) {
|
||||||
current_sample = timeToSamples(timeOffset);
|
current_sample = timeToSamples(timeOffset);
|
||||||
notes_at_sample.clear();
|
notes_at_sample.clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
std::int64_t ClapPlayer::timeToSamples(sf::Time position) const {
|
std::int64_t NoteClaps::timeToSamples(sf::Time position) const {
|
||||||
// Always ROUND, no unchecked truncation, hence the addition in the numerator.
|
// Always ROUND, no unchecked truncation, hence the addition in the numerator.
|
||||||
// This avoids most precision errors arising from "samples => Time => samples" conversions
|
// This avoids most precision errors arising from "samples => Time => samples" conversions
|
||||||
// Original rounding calculation is ((Micros * Freq * Channels) / 1000000) + 0.5
|
// Original rounding calculation is ((Micros * Freq * Channels) / 1000000) + 0.5
|
||||||
@ -105,7 +101,7 @@ std::int64_t ClapPlayer::timeToSamples(sf::Time position) const {
|
|||||||
return ((static_cast<std::int64_t>(position.asMicroseconds()) * note_clap.getSampleRate() * note_clap.getChannelCount()) + 500000) / 1000000;
|
return ((static_cast<std::int64_t>(position.asMicroseconds()) * note_clap.getSampleRate() * note_clap.getChannelCount()) + 500000) / 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
sf::Time ClapPlayer::samplesToTime(std::int64_t samples) const {
|
sf::Time NoteClaps::samplesToTime(std::int64_t samples) const {
|
||||||
sf::Time position = sf::Time::Zero;
|
sf::Time position = sf::Time::Zero;
|
||||||
|
|
||||||
// Make sure we don't divide by 0
|
// Make sure we don't divide by 0
|
@ -10,15 +10,16 @@
|
|||||||
#include "../better_timing.hpp"
|
#include "../better_timing.hpp"
|
||||||
#include "precise_sound_stream.hpp"
|
#include "precise_sound_stream.hpp"
|
||||||
|
|
||||||
class ClapPlayer: public PreciseSoundStream {
|
class NoteClaps: public PreciseSoundStream {
|
||||||
public:
|
public:
|
||||||
ClapPlayer(
|
NoteClaps(
|
||||||
const better::Notes* notes_,
|
const better::Notes* notes_,
|
||||||
const better::Timing* timing_,
|
const better::Timing* timing_,
|
||||||
const std::filesystem::path& assets
|
const std::filesystem::path& assets
|
||||||
);
|
);
|
||||||
|
|
||||||
void set_notes_and_timing(const better::Notes* notes, const better::Timing* timing);
|
void set_notes_and_timing(const better::Notes* notes, const better::Timing* timing);
|
||||||
|
std::atomic<bool> play_chords = true;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool onGetData(Chunk& data) override;
|
bool onGetData(Chunk& data) override;
|
||||||
@ -35,5 +36,4 @@ private:
|
|||||||
const better::Notes* notes;
|
const better::Notes* notes;
|
||||||
const better::Timing* timing;
|
const better::Timing* timing;
|
||||||
sf::SoundBuffer note_clap;
|
sf::SoundBuffer note_clap;
|
||||||
sf::SoundBuffer chord_clap;
|
|
||||||
};
|
};
|
@ -83,10 +83,10 @@ void SyncedSoundStreams::unsafe_update_streams() {
|
|||||||
bool modified_stuff = false;
|
bool modified_stuff = false;
|
||||||
auto _do_request = VariantVisitor {
|
auto _do_request = VariantVisitor {
|
||||||
[this](const AddStream& a) {
|
[this](const AddStream& a) {
|
||||||
InternalStream internal_stream{a.s, {}};
|
InternalStream internal_stream{a.stream, {}};
|
||||||
internal_stream.buffers.m_channelCount = a.s->getChannelCount();
|
internal_stream.buffers.m_channelCount = a.stream->getChannelCount();
|
||||||
internal_stream.buffers.m_sampleRate = a.s->getSampleRate();
|
internal_stream.buffers.m_sampleRate = a.stream->getSampleRate();
|
||||||
internal_stream.buffers.m_format = AudioDevice::getFormatFromChannelCount(a.s->getChannelCount());
|
internal_stream.buffers.m_format = AudioDevice::getFormatFromChannelCount(a.stream->getChannelCount());
|
||||||
streams.emplace(a.name, internal_stream);
|
streams.emplace(a.name, internal_stream);
|
||||||
},
|
},
|
||||||
[this](const RemoveStream& r) {
|
[this](const RemoveStream& r) {
|
||||||
|
@ -49,7 +49,7 @@ struct InternalStream {
|
|||||||
|
|
||||||
struct AddStream {
|
struct AddStream {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::shared_ptr<PreciseSoundStream> s;
|
std::shared_ptr<PreciseSoundStream> stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RemoveStream {
|
struct RemoveStream {
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#include "variant_visitor.hpp"
|
#include "variant_visitor.hpp"
|
||||||
|
|
||||||
EditorState::EditorState(const std::filesystem::path& assets_) :
|
EditorState::EditorState(const std::filesystem::path& assets_) :
|
||||||
clap_player(std::make_shared<ClapPlayer>(nullptr, nullptr, assets_)),
|
note_claps(std::make_shared<NoteClaps>(nullptr, nullptr, assets_)),
|
||||||
playfield(assets_),
|
playfield(assets_),
|
||||||
linear_view(assets_),
|
linear_view(assets_),
|
||||||
applicable_timing(song.timing),
|
applicable_timing(song.timing),
|
||||||
@ -43,7 +43,7 @@ EditorState::EditorState(const std::filesystem::path& assets_) :
|
|||||||
{
|
{
|
||||||
reload_music();
|
reload_music();
|
||||||
reload_jacket();
|
reload_jacket();
|
||||||
audio.add_stream(note_clap_stream, clap_player);
|
audio.add_stream(note_clap_stream, note_claps);
|
||||||
};
|
};
|
||||||
|
|
||||||
EditorState::EditorState(
|
EditorState::EditorState(
|
||||||
@ -53,7 +53,7 @@ EditorState::EditorState(
|
|||||||
) :
|
) :
|
||||||
song(song_),
|
song(song_),
|
||||||
song_path(song_path),
|
song_path(song_path),
|
||||||
clap_player(std::make_shared<ClapPlayer>(nullptr, nullptr, assets_)),
|
note_claps(std::make_shared<NoteClaps>(nullptr, nullptr, assets_)),
|
||||||
playfield(assets_),
|
playfield(assets_),
|
||||||
linear_view(assets_),
|
linear_view(assets_),
|
||||||
applicable_timing(song.timing),
|
applicable_timing(song.timing),
|
||||||
@ -65,7 +65,7 @@ EditorState::EditorState(
|
|||||||
}
|
}
|
||||||
reload_music();
|
reload_music();
|
||||||
reload_jacket();
|
reload_jacket();
|
||||||
audio.add_stream(note_clap_stream, clap_player);
|
audio.add_stream(note_clap_stream, note_claps);
|
||||||
};
|
};
|
||||||
|
|
||||||
int EditorState::get_volume() const {
|
int EditorState::get_volume() const {
|
||||||
@ -110,6 +110,14 @@ const Interval<sf::Time>& EditorState::get_editable_range() {
|
|||||||
return editable_range;
|
return editable_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void EditorState::toggle_playback() {
|
||||||
|
if (get_status() != sf::SoundSource::Playing) {
|
||||||
|
play();
|
||||||
|
} else {
|
||||||
|
pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditorState::play() {
|
void EditorState::play() {
|
||||||
audio.play();
|
audio.play();
|
||||||
}
|
}
|
||||||
@ -795,7 +803,7 @@ void EditorState::open_chart(const std::string& name) {
|
|||||||
chart_state.emplace(chart, name_ref, assets);
|
chart_state.emplace(chart, name_ref, assets);
|
||||||
reload_editable_range();
|
reload_editable_range();
|
||||||
reload_applicable_timing();
|
reload_applicable_timing();
|
||||||
clap_player->set_notes_and_timing(&chart.notes, &applicable_timing);
|
note_claps->set_notes_and_timing(&chart.notes, &applicable_timing);
|
||||||
};
|
};
|
||||||
|
|
||||||
void EditorState::update_visible_notes() {
|
void EditorState::update_visible_notes() {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include "custom_sfml_audio/clap_player.hpp"
|
#include "custom_sfml_audio/note_claps.hpp"
|
||||||
#include "custom_sfml_audio/open_music.hpp"
|
#include "custom_sfml_audio/open_music.hpp"
|
||||||
#include "custom_sfml_audio/synced_sound_streams.hpp"
|
#include "custom_sfml_audio/synced_sound_streams.hpp"
|
||||||
#include "widgets/linear_view.hpp"
|
#include "widgets/linear_view.hpp"
|
||||||
@ -46,7 +46,7 @@ public:
|
|||||||
std::optional<ChartState> chart_state;
|
std::optional<ChartState> chart_state;
|
||||||
|
|
||||||
SyncedSoundStreams audio;
|
SyncedSoundStreams audio;
|
||||||
std::shared_ptr<ClapPlayer> clap_player;
|
std::shared_ptr<NoteClaps> note_claps;
|
||||||
std::optional<std::shared_ptr<OpenMusic>> music = {};
|
std::optional<std::shared_ptr<OpenMusic>> music = {};
|
||||||
|
|
||||||
int get_volume() const;
|
int get_volume() const;
|
||||||
@ -76,6 +76,7 @@ public:
|
|||||||
|
|
||||||
const Interval<sf::Time>& get_editable_range();
|
const Interval<sf::Time>& get_editable_range();
|
||||||
|
|
||||||
|
void toggle_playback();
|
||||||
void play();
|
void play();
|
||||||
void pause();
|
void pause();
|
||||||
void stop();
|
void stop();
|
||||||
|
56
src/main.cpp
56
src/main.cpp
@ -1,3 +1,4 @@
|
|||||||
|
#include <SFML/Audio/SoundSource.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
@ -63,9 +64,9 @@ int main() {
|
|||||||
16.f);
|
16.f);
|
||||||
ImGui::SFML::UpdateFontTexture();
|
ImGui::SFML::UpdateFontTexture();
|
||||||
|
|
||||||
SoundEffect beatTick {assets_folder / "sounds" / "beat.wav"};
|
// SoundEffect beatTick {assets_folder / "sounds" / "beat.wav"};
|
||||||
SoundEffect noteTick {assets_folder / "sounds" / "note.wav"};
|
// SoundEffect noteTick {assets_folder / "sounds" / "note.wav"};
|
||||||
SoundEffect chordTick {assets_folder / "sounds" / "chord.wav"};
|
// SoundEffect chordTick {assets_folder / "sounds" / "chord.wav"};
|
||||||
|
|
||||||
// Loading markers preview
|
// Loading markers preview
|
||||||
std::map<std::filesystem::path, sf::Texture> markerPreviews;
|
std::map<std::filesystem::path, sf::Texture> markerPreviews;
|
||||||
@ -297,6 +298,7 @@ int main() {
|
|||||||
* F keys
|
* F keys
|
||||||
*/
|
*/
|
||||||
case sf::Keyboard::F3:
|
case sf::Keyboard::F3:
|
||||||
|
/*
|
||||||
if (beatTick.toggle()) {
|
if (beatTick.toggle()) {
|
||||||
notificationsQueue.push(std::make_shared<TextNotification>(
|
notificationsQueue.push(std::make_shared<TextNotification>(
|
||||||
"Beat tick : on"));
|
"Beat tick : on"));
|
||||||
@ -304,8 +306,10 @@ int main() {
|
|||||||
notificationsQueue.push(std::make_shared<TextNotification>(
|
notificationsQueue.push(std::make_shared<TextNotification>(
|
||||||
"Beat tick : off"));
|
"Beat tick : off"));
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
case sf::Keyboard::F4:
|
case sf::Keyboard::F4:
|
||||||
|
/*
|
||||||
if (event.key.shift) {
|
if (event.key.shift) {
|
||||||
if (chordTick.toggle()) {
|
if (chordTick.toggle()) {
|
||||||
noteTick.shouldPlay = true;
|
noteTick.shouldPlay = true;
|
||||||
@ -325,11 +329,12 @@ int main() {
|
|||||||
"Note tick : off"));
|
"Note tick : off"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
case sf::Keyboard::Space:
|
case sf::Keyboard::Space:
|
||||||
if (not ImGui::GetIO().WantTextInput) {
|
if (not ImGui::GetIO().WantTextInput) {
|
||||||
if (editor_state) {
|
if (editor_state) {
|
||||||
editor_state->playing = not editor_state->playing;
|
editor_state->toggle_playback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -416,36 +421,15 @@ int main() {
|
|||||||
// Audio playback management
|
// Audio playback management
|
||||||
if (editor_state) {
|
if (editor_state) {
|
||||||
editor_state->update_visible_notes();
|
editor_state->update_visible_notes();
|
||||||
if (editor_state->playing) {
|
if (editor_state->get_status() == sf::SoundSource::Playing) {
|
||||||
editor_state->previous_playback_position = editor_state->playback_position;
|
editor_state->previous_playback_position = editor_state->playback_position;
|
||||||
editor_state->playback_position = editor_state->current_time() + delta * (editor_state->get_speed() / 10.f);
|
|
||||||
switch (editor_state->get_status()) {
|
|
||||||
case sf::Music::Stopped:
|
|
||||||
case sf::Music::Paused:
|
|
||||||
editor_state->set_playback_position(editor_state->current_time());
|
|
||||||
editor_state->play();
|
|
||||||
break;
|
|
||||||
case sf::Music::Playing:
|
|
||||||
editor_state->playback_position = editor_state->get_precise_playback_position();
|
editor_state->playback_position = editor_state->get_precise_playback_position();
|
||||||
break;
|
// editor_state->playback_position = editor_state->current_time() + delta * (editor_state->get_speed() / 10.f);
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (beatTick.shouldPlay) {
|
|
||||||
const auto previous_beat = editor_state->previous_exact_beats();
|
|
||||||
const auto current_beat = editor_state->current_exact_beats();
|
|
||||||
if (floor_fraction(previous_beat) != floor_fraction(current_beat)) {
|
|
||||||
beatTick.play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (editor_state->current_time() > editor_state->get_editable_range().end) {
|
if (editor_state->current_time() > editor_state->get_editable_range().end) {
|
||||||
editor_state->playing = false;
|
|
||||||
editor_state->playback_position = editor_state->get_editable_range().end;
|
|
||||||
}
|
|
||||||
} else if (editor_state->get_status() == sf::SoundSource::Playing) {
|
|
||||||
editor_state->pause();
|
editor_state->pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Drawing
|
// Drawing
|
||||||
if (editor_state) {
|
if (editor_state) {
|
||||||
@ -495,24 +479,18 @@ int main() {
|
|||||||
} else {
|
} else {
|
||||||
chartPropertiesDialog.should_refresh_values = true;
|
chartPropertiesDialog.should_refresh_values = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editor_state->showSoundSettings) {
|
if (editor_state->showSoundSettings) {
|
||||||
ImGui::Begin("Sound Settings", &editor_state->showSoundSettings, ImGuiWindowFlags_AlwaysAutoResize);
|
ImGui::Begin("Sound Settings", &editor_state->showSoundSettings, ImGuiWindowFlags_AlwaysAutoResize); {
|
||||||
{
|
if (ImGui::TreeNode("Note Clap")) {
|
||||||
if (ImGui::TreeNode("Beat Tick")) {
|
static auto play_chords = editor_state->note_claps->play_chords.load();
|
||||||
beatTick.displayControls();
|
if (ImGui::Checkbox("Play on chords", &play_chords)) {
|
||||||
ImGui::TreePop();
|
editor_state->note_claps->play_chords.store(play_chords);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::TreeNode("Note Tick")) {
|
|
||||||
noteTick.displayControls();
|
|
||||||
ImGui::Checkbox("Chord sound", &chordTick.shouldPlay);
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
bg.render(window);
|
bg.render(window);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user