More things working with claps

This commit is contained in:
Stepland 2022-06-09 00:28:21 +02:00
parent d22d80a3e5
commit b6e8d2b622
8 changed files with 53 additions and 70 deletions

View File

@ -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',

View File

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

View File

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

View File

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

View File

@ -49,7 +49,7 @@ struct InternalStream {
struct AddStream {
std::string name;
std::shared_ptr<PreciseSoundStream> s;
std::shared_ptr<PreciseSoundStream> stream;
};
struct RemoveStream {

View File

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

View File

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

View File

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