mirror of
https://gitlab.com/square-game-liberation-front/F.E.I.S.git
synced 2025-02-28 15:30:32 +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_resource.cpp',
|
||||
'audio_device.cpp',
|
||||
'clap_player.cpp',
|
||||
'note_claps.cpp',
|
||||
'open_music.cpp',
|
||||
'open_sound_stream.cpp',
|
||||
'precise_sound_stream.cpp',
|
||||
|
@ -1,36 +1,32 @@
|
||||
#include "clap_player.hpp"
|
||||
#include "note_claps.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../better_note.hpp"
|
||||
|
||||
ClapPlayer::ClapPlayer(
|
||||
NoteClaps::NoteClaps(
|
||||
const better::Notes* notes_,
|
||||
const better::Timing* timing_,
|
||||
const std::filesystem::path& assets
|
||||
) :
|
||||
notes(notes_),
|
||||
timing(timing_),
|
||||
note_clap(),
|
||||
chord_clap()
|
||||
note_clap()
|
||||
{
|
||||
if (not note_clap.loadFromFile(assets / "sounds" / "note.wav")) {
|
||||
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());
|
||||
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_;
|
||||
timing = timing_;
|
||||
}
|
||||
|
||||
bool ClapPlayer::onGetData(sf::SoundStream::Chunk& data) {
|
||||
bool NoteClaps::onGetData(sf::SoundStream::Chunk& data) {
|
||||
samples.assign(samples.size(), 0);
|
||||
if (timing != nullptr and notes != nullptr) {
|
||||
const auto start_sample = current_sample;
|
||||
@ -51,7 +47,7 @@ bool ClapPlayer::onGetData(sf::SoundStream::Chunk& data) {
|
||||
// Should we still be playing the clap ?
|
||||
const auto next = std::next(it);
|
||||
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);
|
||||
} else {
|
||||
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;
|
||||
};
|
||||
|
||||
void ClapPlayer::onSeek(sf::Time timeOffset) {
|
||||
void NoteClaps::onSeek(sf::Time timeOffset) {
|
||||
current_sample = timeToSamples(timeOffset);
|
||||
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.
|
||||
// This avoids most precision errors arising from "samples => Time => samples" conversions
|
||||
// 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;
|
||||
}
|
||||
|
||||
sf::Time ClapPlayer::samplesToTime(std::int64_t samples) const {
|
||||
sf::Time NoteClaps::samplesToTime(std::int64_t samples) const {
|
||||
sf::Time position = sf::Time::Zero;
|
||||
|
||||
// Make sure we don't divide by 0
|
@ -10,15 +10,16 @@
|
||||
#include "../better_timing.hpp"
|
||||
#include "precise_sound_stream.hpp"
|
||||
|
||||
class ClapPlayer: public PreciseSoundStream {
|
||||
class NoteClaps: public PreciseSoundStream {
|
||||
public:
|
||||
ClapPlayer(
|
||||
NoteClaps(
|
||||
const better::Notes* notes_,
|
||||
const better::Timing* timing_,
|
||||
const std::filesystem::path& assets
|
||||
);
|
||||
|
||||
void set_notes_and_timing(const better::Notes* notes, const better::Timing* timing);
|
||||
std::atomic<bool> play_chords = true;
|
||||
|
||||
protected:
|
||||
bool onGetData(Chunk& data) override;
|
||||
@ -35,5 +36,4 @@ private:
|
||||
const better::Notes* notes;
|
||||
const better::Timing* timing;
|
||||
sf::SoundBuffer note_clap;
|
||||
sf::SoundBuffer chord_clap;
|
||||
};
|
@ -83,10 +83,10 @@ void SyncedSoundStreams::unsafe_update_streams() {
|
||||
bool modified_stuff = false;
|
||||
auto _do_request = VariantVisitor {
|
||||
[this](const AddStream& a) {
|
||||
InternalStream internal_stream{a.s, {}};
|
||||
internal_stream.buffers.m_channelCount = a.s->getChannelCount();
|
||||
internal_stream.buffers.m_sampleRate = a.s->getSampleRate();
|
||||
internal_stream.buffers.m_format = AudioDevice::getFormatFromChannelCount(a.s->getChannelCount());
|
||||
InternalStream internal_stream{a.stream, {}};
|
||||
internal_stream.buffers.m_channelCount = a.stream->getChannelCount();
|
||||
internal_stream.buffers.m_sampleRate = a.stream->getSampleRate();
|
||||
internal_stream.buffers.m_format = AudioDevice::getFormatFromChannelCount(a.stream->getChannelCount());
|
||||
streams.emplace(a.name, internal_stream);
|
||||
},
|
||||
[this](const RemoveStream& r) {
|
||||
|
@ -49,7 +49,7 @@ struct InternalStream {
|
||||
|
||||
struct AddStream {
|
||||
std::string name;
|
||||
std::shared_ptr<PreciseSoundStream> s;
|
||||
std::shared_ptr<PreciseSoundStream> stream;
|
||||
};
|
||||
|
||||
struct RemoveStream {
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "variant_visitor.hpp"
|
||||
|
||||
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_),
|
||||
linear_view(assets_),
|
||||
applicable_timing(song.timing),
|
||||
@ -43,7 +43,7 @@ EditorState::EditorState(const std::filesystem::path& assets_) :
|
||||
{
|
||||
reload_music();
|
||||
reload_jacket();
|
||||
audio.add_stream(note_clap_stream, clap_player);
|
||||
audio.add_stream(note_clap_stream, note_claps);
|
||||
};
|
||||
|
||||
EditorState::EditorState(
|
||||
@ -53,7 +53,7 @@ EditorState::EditorState(
|
||||
) :
|
||||
song(song_),
|
||||
song_path(song_path),
|
||||
clap_player(std::make_shared<ClapPlayer>(nullptr, nullptr, assets_)),
|
||||
note_claps(std::make_shared<NoteClaps>(nullptr, nullptr, assets_)),
|
||||
playfield(assets_),
|
||||
linear_view(assets_),
|
||||
applicable_timing(song.timing),
|
||||
@ -65,7 +65,7 @@ EditorState::EditorState(
|
||||
}
|
||||
reload_music();
|
||||
reload_jacket();
|
||||
audio.add_stream(note_clap_stream, clap_player);
|
||||
audio.add_stream(note_clap_stream, note_claps);
|
||||
};
|
||||
|
||||
int EditorState::get_volume() const {
|
||||
@ -110,6 +110,14 @@ const Interval<sf::Time>& EditorState::get_editable_range() {
|
||||
return editable_range;
|
||||
};
|
||||
|
||||
void EditorState::toggle_playback() {
|
||||
if (get_status() != sf::SoundSource::Playing) {
|
||||
play();
|
||||
} else {
|
||||
pause();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorState::play() {
|
||||
audio.play();
|
||||
}
|
||||
@ -795,7 +803,7 @@ void EditorState::open_chart(const std::string& name) {
|
||||
chart_state.emplace(chart, name_ref, assets);
|
||||
reload_editable_range();
|
||||
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() {
|
||||
|
@ -8,7 +8,7 @@
|
||||
#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/synced_sound_streams.hpp"
|
||||
#include "widgets/linear_view.hpp"
|
||||
@ -46,7 +46,7 @@ public:
|
||||
std::optional<ChartState> chart_state;
|
||||
|
||||
SyncedSoundStreams audio;
|
||||
std::shared_ptr<ClapPlayer> clap_player;
|
||||
std::shared_ptr<NoteClaps> note_claps;
|
||||
std::optional<std::shared_ptr<OpenMusic>> music = {};
|
||||
|
||||
int get_volume() const;
|
||||
@ -76,6 +76,7 @@ public:
|
||||
|
||||
const Interval<sf::Time>& get_editable_range();
|
||||
|
||||
void toggle_playback();
|
||||
void play();
|
||||
void pause();
|
||||
void stop();
|
||||
|
60
src/main.cpp
60
src/main.cpp
@ -1,3 +1,4 @@
|
||||
#include <SFML/Audio/SoundSource.hpp>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <variant>
|
||||
@ -63,9 +64,9 @@ int main() {
|
||||
16.f);
|
||||
ImGui::SFML::UpdateFontTexture();
|
||||
|
||||
SoundEffect beatTick {assets_folder / "sounds" / "beat.wav"};
|
||||
SoundEffect noteTick {assets_folder / "sounds" / "note.wav"};
|
||||
SoundEffect chordTick {assets_folder / "sounds" / "chord.wav"};
|
||||
// SoundEffect beatTick {assets_folder / "sounds" / "beat.wav"};
|
||||
// SoundEffect noteTick {assets_folder / "sounds" / "note.wav"};
|
||||
// SoundEffect chordTick {assets_folder / "sounds" / "chord.wav"};
|
||||
|
||||
// Loading markers preview
|
||||
std::map<std::filesystem::path, sf::Texture> markerPreviews;
|
||||
@ -297,6 +298,7 @@ int main() {
|
||||
* F keys
|
||||
*/
|
||||
case sf::Keyboard::F3:
|
||||
/*
|
||||
if (beatTick.toggle()) {
|
||||
notificationsQueue.push(std::make_shared<TextNotification>(
|
||||
"Beat tick : on"));
|
||||
@ -304,8 +306,10 @@ int main() {
|
||||
notificationsQueue.push(std::make_shared<TextNotification>(
|
||||
"Beat tick : off"));
|
||||
}
|
||||
*/
|
||||
break;
|
||||
case sf::Keyboard::F4:
|
||||
/*
|
||||
if (event.key.shift) {
|
||||
if (chordTick.toggle()) {
|
||||
noteTick.shouldPlay = true;
|
||||
@ -325,11 +329,12 @@ int main() {
|
||||
"Note tick : off"));
|
||||
}
|
||||
}
|
||||
*/
|
||||
break;
|
||||
case sf::Keyboard::Space:
|
||||
if (not ImGui::GetIO().WantTextInput) {
|
||||
if (editor_state) {
|
||||
editor_state->playing = not editor_state->playing;
|
||||
editor_state->toggle_playback();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -416,34 +421,13 @@ int main() {
|
||||
// Audio playback management
|
||||
if (editor_state) {
|
||||
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->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();
|
||||
break;
|
||||
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();
|
||||
}
|
||||
}
|
||||
editor_state->playback_position = editor_state->get_precise_playback_position();
|
||||
// editor_state->playback_position = editor_state->current_time() + delta * (editor_state->get_speed() / 10.f);
|
||||
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;
|
||||
editor_state->pause();
|
||||
}
|
||||
} else if (editor_state->get_status() == sf::SoundSource::Playing) {
|
||||
editor_state->pause();
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,24 +479,18 @@ int main() {
|
||||
} else {
|
||||
chartPropertiesDialog.should_refresh_values = true;
|
||||
}
|
||||
|
||||
if (editor_state->showSoundSettings) {
|
||||
ImGui::Begin("Sound Settings", &editor_state->showSoundSettings, ImGuiWindowFlags_AlwaysAutoResize);
|
||||
{
|
||||
if (ImGui::TreeNode("Beat Tick")) {
|
||||
beatTick.displayControls();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Note Tick")) {
|
||||
noteTick.displayControls();
|
||||
ImGui::Checkbox("Chord sound", &chordTick.shouldPlay);
|
||||
ImGui::Begin("Sound Settings", &editor_state->showSoundSettings, ImGuiWindowFlags_AlwaysAutoResize); {
|
||||
if (ImGui::TreeNode("Note Clap")) {
|
||||
static auto play_chords = editor_state->note_claps->play_chords.load();
|
||||
if (ImGui::Checkbox("Play on chords", &play_chords)) {
|
||||
editor_state->note_claps->play_chords.store(play_chords);
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
} else {
|
||||
bg.render(window);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user