diff --git a/src/custom_sfml_audio/al_resource.cpp b/src/custom_sfml_audio/al_resource.cpp new file mode 100644 index 0000000..f1d7fcc --- /dev/null +++ b/src/custom_sfml_audio/al_resource.cpp @@ -0,0 +1,41 @@ +#include "al_resource.hpp" + +#include +#include + +#include "audio_device.hpp" + +namespace { + // OpenAL resources counter and its mutex + unsigned int count = 0; + std::recursive_mutex mutex; + + // The audio device is instantiated on demand rather than at global startup, + // which solves a lot of weird crashes and errors. + // It is destroyed when it is no longer needed. + std::unique_ptr globalDevice; +} + +AlResource::AlResource() { + // Protect from concurrent access + std::scoped_lock lock(mutex); + + // If this is the very first resource, trigger the global device initialization + if (count == 0) + globalDevice = std::make_unique(); + + // Increment the resources counter + ++count; +} + +AlResource::~AlResource() { + // Protect from concurrent access + std::scoped_lock lock(mutex); + + // Decrement the resources counter + --count; + + // If there's no more resource alive, we can destroy the device + if (count == 0) + globalDevice.reset(); +} diff --git a/src/custom_sfml_audio/al_resource.hpp b/src/custom_sfml_audio/al_resource.hpp new file mode 100644 index 0000000..55a27be --- /dev/null +++ b/src/custom_sfml_audio/al_resource.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +class AlResource { +protected: + AlResource(); + ~AlResource(); +}; diff --git a/src/custom_sfml_audio/beat_tick_player.hpp b/src/custom_sfml_audio/beat_tick_player.hpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/custom_sfml_audio/clap_player.cpp b/src/custom_sfml_audio/clap_player.cpp index 45d761e..f2a2359 100644 --- a/src/custom_sfml_audio/clap_player.cpp +++ b/src/custom_sfml_audio/clap_player.cpp @@ -1,20 +1,26 @@ #include "clap_player.hpp" #include +#include #include "../better_note.hpp" ClapPlayer::ClapPlayer( const better::Notes* notes_, const better::Timing* timing_, - const sf::SoundBuffer& note_clap_, - const sf::SoundBuffer& chord_clap_ + const std::filesystem::path& assets ) : notes(notes_), timing(timing_), - note_clap(note_clap_), - chord_clap(chord_clap_) + note_clap(), + chord_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); } diff --git a/src/custom_sfml_audio/clap_player.hpp b/src/custom_sfml_audio/clap_player.hpp index 02f606c..387a3c7 100644 --- a/src/custom_sfml_audio/clap_player.hpp +++ b/src/custom_sfml_audio/clap_player.hpp @@ -8,15 +8,14 @@ #include "../better_notes.hpp" #include "../better_timing.hpp" -#include "open_sound_stream.hpp" +#include "precise_sound_stream.hpp" -class ClapPlayer: public OpenSoundStream { +class ClapPlayer: public PreciseSoundStream { public: ClapPlayer( const better::Notes* notes_, const better::Timing* timing_, - const sf::SoundBuffer& note_clap_, - const sf::SoundBuffer& chord_clap_ + const std::filesystem::path& assets ); void set_notes_and_timing(const better::Notes* notes, const better::Timing* timing); @@ -35,6 +34,6 @@ private: const better::Notes* notes; const better::Timing* timing; - const sf::SoundBuffer& note_clap; - const sf::SoundBuffer& chord_clap; + sf::SoundBuffer note_clap; + sf::SoundBuffer chord_clap; }; \ No newline at end of file diff --git a/src/custom_sfml_audio/meson.build b/src/custom_sfml_audio/meson.build index 91905cc..9e1aedc 100644 --- a/src/custom_sfml_audio/meson.build +++ b/src/custom_sfml_audio/meson.build @@ -1,10 +1,10 @@ sources += files([ 'al_check.cpp', + 'al_resource.cpp', 'audio_device.cpp', - 'beat_tick_player.cpp', 'clap_player.cpp', 'open_music.cpp', - 'open_soud_stream.cpp', + 'open_sound_stream.cpp', 'precise_sound_stream.cpp', 'synced_sound_streams.cpp' ]) \ No newline at end of file diff --git a/src/custom_sfml_audio/open_music.cpp b/src/custom_sfml_audio/open_music.cpp index b658c23..1da750a 100644 --- a/src/custom_sfml_audio/open_music.cpp +++ b/src/custom_sfml_audio/open_music.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "al_check.hpp" @@ -19,10 +20,13 @@ #endif #endif -OpenMusic::OpenMusic() : +OpenMusic::OpenMusic(const std::filesystem::path& filename) : m_file(), - m_loopSpan(0, 0) { - + m_loopSpan(0, 0) +{ + if (not openFromFile(filename)) { + throw std::runtime_error("Could not open "+filename.string()); + } } @@ -47,36 +51,6 @@ bool OpenMusic::openFromFile(const std::filesystem::path& filename) { } -bool OpenMusic::openFromMemory(const void* data, std::size_t sizeInBytes) { - // First stop the music if it was already running - stop(); - - // Open the underlying sound file - if (!m_file.openFromMemory(data, sizeInBytes)) { - return false; - } - - // Perform common initializations - initialize(); - return true; -} - - -bool OpenMusic::openFromStream(sf::InputStream& stream) { - // First stop the music if it was already running - stop(); - - // Open the underlying sound file - if (!m_file.openFromStream(stream)) - return false; - - // Perform common initializations - initialize(); - - return true; -} - - sf::Time OpenMusic::getDuration() const { return m_file.getDuration(); } diff --git a/src/custom_sfml_audio/open_music.hpp b/src/custom_sfml_audio/open_music.hpp index cd4b174..c7e2f17 100644 --- a/src/custom_sfml_audio/open_music.hpp +++ b/src/custom_sfml_audio/open_music.hpp @@ -15,11 +15,9 @@ class OpenMusic : public PreciseSoundStream { public: using TimeSpan = sf::Music::Span; - OpenMusic(); + OpenMusic(const std::filesystem::path& filename); ~OpenMusic() override; [[nodiscard]] bool openFromFile(const std::filesystem::path& filename); - [[nodiscard]] bool openFromMemory(const void* data, std::size_t sizeInBytes); - [[nodiscard]] bool openFromStream(sf::InputStream& stream); sf::Time getDuration() const; TimeSpan getLoopPoints() const; void setLoopPoints(TimeSpan timePoints); diff --git a/src/custom_sfml_audio/precise_sound_stream.cpp b/src/custom_sfml_audio/precise_sound_stream.cpp index 4f45fea..e41d589 100644 --- a/src/custom_sfml_audio/precise_sound_stream.cpp +++ b/src/custom_sfml_audio/precise_sound_stream.cpp @@ -1,11 +1,14 @@ #include #include "precise_sound_stream.hpp" +PreciseSoundStream::PreciseSoundStream() { + initialize_open_al_extension(); +} + void PreciseSoundStream::initialize_open_al_extension() { if (not alIsExtensionPresent("AL_SOFT_source_latency")) { throw std::runtime_error("Error: AL_SOFT_source_latency not supported"); } - alGetSourcedvSOFT = reinterpret_cast(alGetProcAddress("alGetSourcedvSOFT")); } @@ -22,10 +25,10 @@ void PreciseSoundStream::play() { sf::Time PreciseSoundStream::getPrecisePlayingOffset() const { if (getStatus() != sf::SoundStream::Playing) { - return sf::SoundStream::getPlayingOffset(); + return getPlayingOffset(); } else { return ( - sf::SoundStream::getPlayingOffset() + getPlayingOffset() - (alSecOffsetLatencySoft()[1] * getPitch()) + (lag * getPitch()) ); diff --git a/src/custom_sfml_audio/precise_sound_stream.hpp b/src/custom_sfml_audio/precise_sound_stream.hpp index e52f8b2..262c1f9 100644 --- a/src/custom_sfml_audio/precise_sound_stream.hpp +++ b/src/custom_sfml_audio/precise_sound_stream.hpp @@ -8,14 +8,12 @@ #include "open_sound_stream.hpp" -class PreciseSoundStream : public OpenSoundStream { -public: +struct PreciseSoundStream : public OpenSoundStream { + PreciseSoundStream(); sf::Time getPrecisePlayingOffset() const; void play(); -protected: void initialize_open_al_extension(); LPALGETSOURCEDVSOFT alGetSourcedvSOFT; -private: std::array alSecOffsetLatencySoft() const; sf::Time lag = sf::Time::Zero; }; \ No newline at end of file diff --git a/src/custom_sfml_audio/synced_sound_streams.cpp b/src/custom_sfml_audio/synced_sound_streams.cpp index 843ef64..5fb1025 100644 --- a/src/custom_sfml_audio/synced_sound_streams.cpp +++ b/src/custom_sfml_audio/synced_sound_streams.cpp @@ -1,5 +1,6 @@ #include "synced_sound_streams.hpp" +#include #include #include #include @@ -12,6 +13,7 @@ #include "al_check.hpp" #include "audio_device.hpp" +#include "src/custom_sfml_audio/precise_sound_stream.hpp" #ifdef _MSC_VER #pragma warning(disable: 4355) // 'this' used in base member initializer list @@ -56,7 +58,7 @@ SyncedSoundStreams::~SyncedSoundStreams() { } -void SyncedSoundStreams::add_stream(const std::string& name, std::shared_ptr s) { +void SyncedSoundStreams::add_stream(const std::string& name, std::shared_ptr s) { InternalStream internal_stream{s, {}}; internal_stream.buffers.m_channelCount = s->getChannelCount(); internal_stream.buffers.m_sampleRate = s->getSampleRate(); @@ -201,12 +203,23 @@ sf::Time SyncedSoundStreams::getPlayingOffset() const { ALfloat secs = 0.f; alCheck(alGetSourcef(s.stream->get_source(), AL_SEC_OFFSET, &secs)); - return sf::seconds( + auto base = sf::seconds( secs + static_cast(s.buffers.m_samplesProcessed) / static_cast(s.buffers.m_sampleRate) / static_cast(s.buffers.m_channelCount) ); + auto correction = ( + (s.stream->alSecOffsetLatencySoft()[1] * s.stream->getPitch()) + - (s.stream->lag * s.stream->getPitch()) + ); + return base - correction; +} + +void SyncedSoundStreams::setPitch(float pitch) { + for (auto& [_, s] : streams) { + s.stream->setPitch(pitch); + } } diff --git a/src/custom_sfml_audio/synced_sound_streams.hpp b/src/custom_sfml_audio/synced_sound_streams.hpp index fcfb40b..3e2811c 100644 --- a/src/custom_sfml_audio/synced_sound_streams.hpp +++ b/src/custom_sfml_audio/synced_sound_streams.hpp @@ -12,7 +12,8 @@ #include #include -#include "open_sound_stream.hpp" +#include "al_resource.hpp" +#include "precise_sound_stream.hpp" // Number of audio buffers used by the streaming loop @@ -38,17 +39,18 @@ struct Buffers { }; struct InternalStream { - std::shared_ptr stream; + std::shared_ptr stream; Buffers buffers; void clear_queue(); }; -class SyncedSoundStreams { +class SyncedSoundStreams : public AlResource { public: + SyncedSoundStreams(); ~SyncedSoundStreams(); - void add_stream(const std::string& name, std::shared_ptr s); + void add_stream(const std::string& name, std::shared_ptr s); void remove_stream(const std::string& name); void play(); @@ -60,11 +62,12 @@ public: void setPlayingOffset(sf::Time timeOffset); sf::Time getPlayingOffset() const; + void setPitch(float pitch); + void setLoop(bool loop); bool getLoop() const; protected: - SyncedSoundStreams(); void setProcessingInterval(sf::Time interval); private: diff --git a/src/editor_state.cpp b/src/editor_state.cpp index 8ec4966..a52ae6f 100644 --- a/src/editor_state.cpp +++ b/src/editor_state.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,7 @@ #include "variant_visitor.hpp" EditorState::EditorState(const std::filesystem::path& assets_) : - note_claps(assets_), + clap_player(std::make_shared(nullptr, nullptr, assets_)), playfield(assets_), linear_view(assets_), applicable_timing(song.timing), @@ -42,6 +43,7 @@ EditorState::EditorState(const std::filesystem::path& assets_) : { reload_music(); reload_jacket(); + audio.add_stream(note_clap_stream, clap_player); }; EditorState::EditorState( @@ -51,7 +53,7 @@ EditorState::EditorState( ) : song(song_), song_path(song_path), - note_claps(assets_), + clap_player(std::make_shared(nullptr, nullptr, assets_)), playfield(assets_), linear_view(assets_), applicable_timing(song.timing), @@ -63,6 +65,7 @@ EditorState::EditorState( } reload_music(); reload_jacket(); + audio.add_stream(note_clap_stream, clap_player); }; int EditorState::get_volume() const { @@ -71,7 +74,9 @@ int EditorState::get_volume() const { void EditorState::set_volume(int newMusicVolume) { volume = std::clamp(newMusicVolume, 0, 10); - audio.setMusicVolume(Toolbox::convertVolumeToNormalizedDB(volume)*100.f); + if (music.has_value()) { + (**music).setVolume(Toolbox::convertVolumeToNormalizedDB(volume)*100.f); + } } void EditorState::volume_up() { @@ -117,7 +122,7 @@ void EditorState::stop() { audio.stop(); } -SyncedSoundStreams::Status EditorState::get_status() { +sf::SoundSource::Status EditorState::get_status() { return audio.getStatus(); } @@ -158,7 +163,11 @@ void EditorState::set_playback_position(std::variant newPosi }; sf::Time EditorState::get_playback_position() { - return audio.getPrecisePlayingOffset(); + if (music.has_value()) { + return audio.getPlayingOffset(); + } else { + return current_time(); + } } Fraction EditorState::current_exact_beats() const { @@ -384,7 +393,7 @@ void EditorState::display_properties() { if (feis::InputTextColored( "Audio", &song.metadata.audio, - audio.music_is_loaded(), + music.has_value(), "Invalid Audio Path" )) { reload_music(); @@ -417,9 +426,9 @@ void EditorState::display_properties() { Decimal{0}, song.metadata.preview_loop.start ); - if (audio.music_is_loaded()) { + if (music.has_value()) { song.metadata.preview_loop.start = std::min( - Decimal{audio.getMusicDuration().asMicroseconds()} / 1000000, + Decimal{(**music).getDuration().asMicroseconds()} / 1000000, song.metadata.preview_loop.start ); } @@ -429,12 +438,12 @@ void EditorState::display_properties() { Decimal{0}, song.metadata.preview_loop.duration ); - if (audio.music_is_loaded()) { + if (music.has_value()) { song.metadata.preview_loop.start = std::min( ( Decimal{ - audio - .getMusicDuration() + (**music) + .getDuration() .asMicroseconds() } / 1000000 - song.metadata.preview_loop.start @@ -457,7 +466,7 @@ status of the editor. Will appear in the "Editor Status" window void EditorState::display_status() { ImGui::Begin("Status", &showStatus, ImGuiWindowFlags_AlwaysAutoResize); { - if (not audio.music_is_loaded()) { + if (not music.has_value()) { if (not song.metadata.audio.empty()) { ImGui::TextColored( ImVec4(1, 0.42, 0.41, 1), @@ -520,10 +529,10 @@ void EditorState::display_playback_status() { ImGui::SameLine(); ImGui::TextUnformatted(fmt::format("{:.3f}", static_cast(current_exact_beats())).c_str()); ImGui::SameLine(); - if (audio.music_is_loaded()) { + if (music.has_value()) { ImGui::TextDisabled("Music File Offset :"); ImGui::SameLine(); - ImGui::TextUnformatted(Toolbox::to_string(audio.getPrecisePlayingOffset()).c_str()); + ImGui::TextUnformatted(Toolbox::to_string(audio.getPlayingOffset()).c_str()); ImGui::SameLine(); } ImGui::TextDisabled("Timeline Position :"); @@ -786,7 +795,7 @@ void EditorState::open_chart(const std::string& name) { chart_state.emplace(chart, name_ref, assets); reload_editable_range(); reload_applicable_timing(); - note_claps.set_notes_and_timing(&chart.notes, &applicable_timing); + clap_player->set_notes_and_timing(&chart.notes, &applicable_timing); }; void EditorState::update_visible_notes() { @@ -809,10 +818,10 @@ void EditorState::reload_editable_range() { Interval EditorState::choose_editable_range() { Interval new_range{sf::Time::Zero, sf::Time::Zero}; - if (audio.music_is_loaded()) { + if (music.has_value()) { // If there is music, allow editing up to the end, but no further // You've put notes *after* the end of the music ? fuck 'em. - new_range += audio.getMusicDuration(); + new_range += (**music).getDuration(); return new_range; } else { // If there is no music : @@ -857,14 +866,16 @@ void EditorState::reload_jacket() { */ void EditorState::reload_music() { if (not song_path.has_value() or song.metadata.audio.empty()) { - audio.clear_music(); + music.reset(); return; } const auto absolute_music_path = song_path->parent_path() / song.metadata.audio; - if (not audio.openFromFile(absolute_music_path)) { - audio.clear_music(); - }; + try { + music.emplace(std::make_shared(absolute_music_path)); + } catch (const std::exception& e) { + music.reset(); + } reload_editable_range(); playback_position = std::clamp( @@ -874,6 +885,11 @@ void EditorState::reload_music() { ); previous_playback_position = playback_position; set_speed(speed); + if (music.has_value()) { + audio.add_stream(music_stream, *music); + } else { + audio.remove_stream(music_stream); + } }; void EditorState::reload_preview_audio() { diff --git a/src/editor_state.hpp b/src/editor_state.hpp index 0023231..0c7854b 100644 --- a/src/editor_state.hpp +++ b/src/editor_state.hpp @@ -1,11 +1,17 @@ #pragma once +#include +#include + #include #include #include -#include +#include "custom_sfml_audio/clap_player.hpp" +#include "custom_sfml_audio/open_music.hpp" +#include "custom_sfml_audio/synced_sound_streams.hpp" +#include "widgets/linear_view.hpp" #include "better_note.hpp" #include "better_song.hpp" #include "chart_state.hpp" @@ -15,11 +21,11 @@ #include "notes_clipboard.hpp" #include "notifications_queue.hpp" #include "playfield.hpp" -#include "custom_sfml_audio/synced_sound_streams.hpp" -#include "custom_sfml_audio/clap_player.hpp" -#include "widgets/linear_view.hpp" +const std::string music_stream = "music"; +const std::string note_clap_stream = "note_clap"; + /* * The god class, holds everything there is to know about the currently open * file @@ -40,7 +46,8 @@ public: std::optional chart_state; SyncedSoundStreams audio; - ClapPlayer clap_player; + std::shared_ptr clap_player; + std::optional> music = {}; int get_volume() const; void set_volume(int newMusicVolume); diff --git a/src/main.cpp b/src/main.cpp index aeb5b3f..b90b872 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -418,6 +418,7 @@ int main() { editor_state->update_visible_notes(); if (editor_state->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: @@ -441,7 +442,7 @@ int main() { editor_state->playing = false; editor_state->playback_position = editor_state->get_editable_range().end; } - } else if (editor_state->get_status() == SyncedSoundStreams::Playing) { + } else if (editor_state->get_status() == sf::SoundSource::Playing) { editor_state->pause(); } } diff --git a/src/meson.build b/src/meson.build index 279172c..df837f2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -21,13 +21,10 @@ sources += files( 'marker.cpp', 'mp3_reader.cpp', 'note.cpp', - 'note_claps.cpp', 'notes_clipboard.cpp', 'notification.cpp', 'notifications_queue.cpp', 'playfield.cpp', - 'precise_music.cpp', - 'precise_sound_stream.cpp', 'preferences.cpp', 'sound_effect.cpp', 'special_numeric_types.cpp', diff --git a/src/note_claps.cpp b/src/note_claps.cpp deleted file mode 100644 index 9acf43e..0000000 --- a/src/note_claps.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "note_claps.hpp" - -NoteClaps::NoteClaps(const std::filesystem::path& assets) { - const auto path = assets / "sounds" / "note.wav"; - if (not clap.loadFromFile(path)) { - throw std::runtime_error("Could not open "+path.string()); - } - output_buffer.resize(clap.getSampleRate()*clap.getChannelCount(), 0); - initialize(clap.getChannelCount(), clap.getSampleRate()); - initialize_open_al_extension(); -} - -void NoteClaps::set_notes_and_timing(const better::Notes* notes_, const better::Timing* timing_) { - notes = notes_; - timing = timing_; -} - -bool NoteClaps::onGetData(sf::SoundStream::Chunk& data) { - output_buffer.assign(output_buffer.size(), 0); - if (timing != nullptr and notes != nullptr) { - const auto start_sample = current_sample; - const auto end_sample = current_sample + static_cast(output_buffer.size()); - const auto start_time = samplesToTime(start_sample); - const auto end_time = samplesToTime(end_sample); - const auto start_beat = timing->beats_at(start_time); - const auto end_beat = timing->beats_at(end_time); - - notes->in(start_beat, end_beat, [&](const better::Notes::const_iterator& it){ - const auto beat = it->second.get_time(); - const auto time = timing->time_at(beat); - const auto sample = static_cast(timeToSamples(time)); - notes_at_sample[sample] += 1; - }); - - for (auto it = notes_at_sample.begin(); it != notes_at_sample.end();) { - // Should we still be playing the clap ? - const auto next = std::next(it); - const auto last_audible_start = start_sample - static_cast(clap.getSampleCount()); - if (it->first <= last_audible_start) { - it = notes_at_sample.erase(it); - } else { - const auto full_clap_start_in_buffer = static_cast(it->first) - static_cast(start_sample); - const auto slice_start_in_buffer = std::max(std::int64_t(0), full_clap_start_in_buffer); - const auto full_clap_end_in_buffer = full_clap_start_in_buffer + static_cast(clap.getSampleCount()); - auto slice_end_in_buffer = full_clap_end_in_buffer; - bool clap_finished_playing_in_current_buffer = true; - if (next != notes_at_sample.end()) { - slice_end_in_buffer = std::min( - slice_end_in_buffer, - static_cast(next->first) - static_cast(start_sample) - ); - } else if (slice_end_in_buffer > static_cast(output_buffer.size())) { - clap_finished_playing_in_current_buffer = false; - slice_end_in_buffer = static_cast(output_buffer.size()); - } - auto slice_start_in_clap = slice_start_in_buffer - full_clap_start_in_buffer; - auto slice_size = std::min( - slice_end_in_buffer - slice_start_in_buffer, - static_cast(clap.getSampleCount()) - slice_start_in_clap - ); - for (std::int64_t i = 0; i < slice_size; i++) { - output_buffer[slice_start_in_buffer + i] = clap.getSamples()[slice_start_in_clap + i]; - } - if (clap_finished_playing_in_current_buffer) { - it = notes_at_sample.erase(it); - } else { - ++it; - } - } - } - } - - data.samples = output_buffer.data(); - data.sampleCount = output_buffer.size(); - current_sample += output_buffer.size(); - - return true; -} - -void NoteClaps::onSeek(sf::Time timeOffset) { - current_sample = timeToSamples(timeOffset); - notes_at_sample.clear(); -} - -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 - // We refactor it to keep Int64 as the data type throughout the whole operation. - return ((static_cast(position.asMicroseconds()) * getSampleRate() * getChannelCount()) + 500000) / 1000000; -} - - -//////////////////////////////////////////////////////////// -sf::Time NoteClaps::samplesToTime(std::int64_t samples) const -{ - sf::Time position = sf::Time::Zero; - - // Make sure we don't divide by 0 - if (clap.getSampleRate() != 0 && clap.getChannelCount() != 0) - position = sf::microseconds(static_cast((samples * 1000000) / (getChannelCount() * getSampleRate()))); - - return position; -} \ No newline at end of file diff --git a/src/note_claps.hpp b/src/note_claps.hpp deleted file mode 100644 index ec7e04c..0000000 --- a/src/note_claps.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include - -#include -#include - -#include "better_notes.hpp" -#include "better_timing.hpp" -#include "src/precise_sound_stream.hpp" - -class NoteClaps: public PreciseSoundStream { -public: - NoteClaps(const std::filesystem::path& assets); - void set_notes_and_timing(const better::Notes* notes, const better::Timing* timing); -protected: - bool onGetData(sf::SoundStream::Chunk& data) override; - void onSeek(sf::Time timeOffset) override; - - std::int64_t timeToSamples(sf::Time position) const; - sf::Time samplesToTime(std::int64_t samples) const; - - const better::Notes* notes = nullptr; - const better::Timing* timing = nullptr; -private: - sf::SoundBuffer clap; - std::vector output_buffer; - - std::int64_t current_sample = 0; - std::map notes_at_sample; -}; \ No newline at end of file