mirror of
https://gitlab.com/square-game-liberation-front/F.E.I.S.git
synced 2025-02-28 15:30:32 +01:00
I don't understand a single *THING* that's happenning but the reported times are wrong and always have something to do with the pitch being multiplied one extra time
This commit is contained in:
parent
54aef06e04
commit
6555cb168e
@ -10,18 +10,18 @@
|
||||
BeatTicks::BeatTicks(
|
||||
const better::Timing* timing_,
|
||||
const std::filesystem::path& assets,
|
||||
float pitch
|
||||
float pitch_
|
||||
) :
|
||||
FakePitchedSoundStream(assets / "sounds" / "beat.wav", pitch),
|
||||
FakePitchedSoundStream(assets / "sounds" / "beat.wav", pitch_),
|
||||
timing(timing_)
|
||||
{}
|
||||
|
||||
BeatTicks::BeatTicks(
|
||||
const better::Timing* timing_,
|
||||
std::shared_ptr<sf::SoundBuffer> beat_tick,
|
||||
float pitch
|
||||
float pitch_
|
||||
) :
|
||||
FakePitchedSoundStream(beat_tick, pitch),
|
||||
FakePitchedSoundStream(beat_tick, pitch_),
|
||||
timing(timing_)
|
||||
{}
|
||||
|
||||
@ -29,11 +29,11 @@ void BeatTicks::set_timing(const better::Timing* timing_) {
|
||||
timing = timing_;
|
||||
}
|
||||
|
||||
std::shared_ptr<BeatTicks> BeatTicks::with_pitch(float pitch) {
|
||||
std::shared_ptr<BeatTicks> BeatTicks::with_pitch(float new_pitch) {
|
||||
return std::make_shared<BeatTicks>(
|
||||
timing,
|
||||
sample,
|
||||
pitch
|
||||
new_pitch
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <SFML/System/Time.hpp>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
|
||||
@ -19,6 +20,16 @@ struct PreciseSoundStream : public OpenSoundStream {
|
||||
};
|
||||
|
||||
template<class T>
|
||||
sf::Uint64 timeToSamples(sf::Time position, T sample_rate, T channel_count) {
|
||||
sf::Uint64 time_to_samples(sf::Time position, T sample_rate, T channel_count) {
|
||||
return ((static_cast<sf::Uint64>(position.asMicroseconds()) * sample_rate * channel_count) + 500000) / 1000000;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
sf::Time samples_to_time(std::int64_t samples, T sample_rate, T channel_count) {
|
||||
// Make sure we don't divide by 0
|
||||
if (sample_rate != 0 && channel_count != 0) {
|
||||
return sf::microseconds((samples * 1000000) / (channel_count * sample_rate));
|
||||
} else {
|
||||
return sf::Time::Zero;
|
||||
}
|
||||
};
|
@ -14,8 +14,10 @@
|
||||
#include <variant>
|
||||
|
||||
#include "../variant_visitor.hpp"
|
||||
#include "../toolbox.hpp"
|
||||
#include "al_check.hpp"
|
||||
#include "audio_device.hpp"
|
||||
#include "imgui.h"
|
||||
#include "precise_sound_stream.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -155,6 +157,11 @@ void SyncedSoundStreams::play() {
|
||||
|
||||
// Start updating the stream in a separate thread to avoid blocking the application
|
||||
launchStreamingThread(sf::SoundSource::Playing);
|
||||
|
||||
// Set lag values
|
||||
for (const auto& [_, s]: streams) {
|
||||
s.stream->lag = s.stream->alSecOffsetLatencySoft()[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -219,7 +226,11 @@ void SyncedSoundStreams::setPlayingOffset(sf::Time timeOffset) {
|
||||
for (auto& [_, s]: streams) {
|
||||
s.stream->public_seek_callback(timeOffset);
|
||||
// Restart streaming
|
||||
s.buffers.m_samplesProcessed = timeToSamples(timeOffset, s.buffers.m_sampleRate, s.buffers.m_channelCount);
|
||||
if (s.reconstruct_on_pitch_change) {
|
||||
timeOffset /= pitch;
|
||||
}
|
||||
|
||||
s.buffers.m_samplesProcessed = time_to_samples(timeOffset, s.buffers.m_sampleRate, s.buffers.m_channelCount);
|
||||
}
|
||||
|
||||
if (oldStatus == sf::SoundSource::Stopped) {
|
||||
@ -234,18 +245,19 @@ sf::Time SyncedSoundStreams::getPlayingOffset() const {
|
||||
if (streams.empty()) {
|
||||
return sf::Time::Zero;
|
||||
}
|
||||
const auto& s = streams.begin()->second;
|
||||
return getPlayingOffset(streams.begin()->second);
|
||||
}
|
||||
|
||||
sf::Time SyncedSoundStreams::getPlayingOffset(const InternalStream& s) const {
|
||||
if (not (s.buffers.m_sampleRate && s.buffers.m_channelCount)) {
|
||||
return sf::Time::Zero;
|
||||
}
|
||||
|
||||
ALfloat secs = 0.f;
|
||||
alCheck(alGetSourcef(s.stream->get_source(), AL_SEC_OFFSET, &secs));
|
||||
const auto openal_seconds = sf::seconds(
|
||||
secs
|
||||
+ static_cast<float>(s.buffers.m_samplesProcessed)
|
||||
/ static_cast<float>(s.buffers.m_sampleRate)
|
||||
/ static_cast<float>(s.buffers.m_channelCount)
|
||||
const auto openal_seconds = sf::seconds(secs) + samples_to_time(
|
||||
s.buffers.m_samplesProcessed,
|
||||
s.buffers.m_sampleRate,
|
||||
s.buffers.m_channelCount
|
||||
);
|
||||
if (s.reconstruct_on_pitch_change) {
|
||||
return openal_seconds * pitch;
|
||||
@ -255,14 +267,14 @@ sf::Time SyncedSoundStreams::getPlayingOffset() const {
|
||||
}
|
||||
|
||||
sf::Time SyncedSoundStreams::getPrecisePlayingOffset() const {
|
||||
const auto base = getPlayingOffset();
|
||||
if (streams.empty()) {
|
||||
return base;
|
||||
}
|
||||
const auto& s = streams.begin()->second;
|
||||
if (not (s.buffers.m_sampleRate && s.buffers.m_channelCount)) {
|
||||
return base;
|
||||
return sf::Time::Zero;
|
||||
}
|
||||
return getPrecisePlayingOffset(streams.begin()->second);
|
||||
}
|
||||
|
||||
sf::Time SyncedSoundStreams::getPrecisePlayingOffset(const InternalStream& s) const {
|
||||
const auto base = getPlayingOffset(s);
|
||||
const auto correction = (
|
||||
s.stream->alSecOffsetLatencySoft()[1] - s.stream->lag
|
||||
);
|
||||
@ -288,6 +300,94 @@ bool SyncedSoundStreams::getLoop() const {
|
||||
return m_loop;
|
||||
}
|
||||
|
||||
void SyncedSoundStreams::display_debug() const {
|
||||
if (ImGui::BeginTable("SSS debug props", streams.size() + 1, ImGuiTableFlags_Borders)) {
|
||||
ImGui::TableSetupColumn("");
|
||||
for (const auto& [name, _] : streams) {
|
||||
ImGui::TableSetupColumn(name.c_str());
|
||||
}
|
||||
ImGui::TableHeadersRow();
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted("reconstruct on pitch change");
|
||||
for (const auto& [_, s] : streams) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(fmt::format("{}", s.reconstruct_on_pitch_change).c_str());
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted("SyncedSoundStreams offset");
|
||||
for (const auto& [_, s] : streams) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(Toolbox::to_string(getPlayingOffset(s)).c_str());
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted("internal stream offset");
|
||||
for (const auto& [_, s] : streams) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(Toolbox::to_string(s.stream->getPlayingOffset()).c_str());
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted("SyncedSoundStreams offset (precise)");
|
||||
for (const auto& [_, s] : streams) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(Toolbox::to_string(getPrecisePlayingOffset(s)).c_str());
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted("internal stream offset (precise)");
|
||||
for (const auto& [_, s] : streams) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(Toolbox::to_string(s.stream->getPrecisePlayingOffset()).c_str());
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted("stream info in .buffers");
|
||||
for (const auto& [_, s] : streams) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(fmt::format("{}Hz * {}ch", s.buffers.m_sampleRate, s.buffers.m_channelCount).c_str());
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted("stream info in .stream");
|
||||
for (const auto& [_, s] : streams) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(fmt::format("{}Hz * {}ch", s.stream->getSampleRate(), s.stream->getChannelCount()).c_str());
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted("internal stream pitch");
|
||||
for (const auto& [_, s] : streams) {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(fmt::format("x{}", s.stream->getPitch()).c_str());
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted("AL_SEC_OFFSET");
|
||||
for (const auto& [_, s] : streams) {
|
||||
ImGui::TableNextColumn();
|
||||
ALfloat secs = 0.f;
|
||||
alCheck(alGetSourcef(s.stream->get_source(), AL_SEC_OFFSET, &secs));
|
||||
ImGui::TextUnformatted(Toolbox::to_string(sf::seconds(secs)).c_str());
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted("samples_to_time()");
|
||||
for (const auto& [_, s] : streams) {
|
||||
ImGui::TableNextColumn();
|
||||
const auto time = samples_to_time(
|
||||
s.buffers.m_samplesProcessed,
|
||||
s.buffers.m_sampleRate,
|
||||
s.buffers.m_channelCount
|
||||
);
|
||||
ImGui::TextUnformatted(Toolbox::to_string(time).c_str());
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SyncedSoundStreams::setProcessingInterval(sf::Time interval) {
|
||||
m_processingInterval = interval;
|
||||
|
@ -77,6 +77,8 @@ public:
|
||||
void setLoop(bool loop);
|
||||
bool getLoop() const;
|
||||
|
||||
void display_debug() const;
|
||||
|
||||
protected:
|
||||
void setProcessingInterval(sf::Time interval);
|
||||
|
||||
@ -94,6 +96,9 @@ private:
|
||||
void unsafe_update_streams();
|
||||
void reload_sources();
|
||||
|
||||
sf::Time getPlayingOffset(const InternalStream& s) const;
|
||||
sf::Time getPrecisePlayingOffset(const InternalStream& s) const;
|
||||
|
||||
float pitch = 1.f;
|
||||
std::thread m_thread; // Thread running the background tasks
|
||||
mutable std::recursive_mutex m_threadMutex; // Thread mutex
|
||||
|
@ -124,6 +124,7 @@ void EditorState::toggle_beat_ticks() {
|
||||
if (audio.contains_stream(beat_tick_stream)) {
|
||||
audio.remove_stream(beat_tick_stream);
|
||||
} else {
|
||||
beat_ticks = beat_ticks->with_pitch(get_pitch());
|
||||
audio.add_stream(beat_tick_stream, {beat_ticks, true});
|
||||
}
|
||||
}
|
||||
@ -158,6 +159,10 @@ void EditorState::set_pitch(float pitch) {
|
||||
audio.setPitch(pitch);
|
||||
}
|
||||
|
||||
float EditorState::get_pitch() const {
|
||||
return speed / 10.f;
|
||||
}
|
||||
|
||||
void EditorState::set_playback_position(std::variant<sf::Time, Fraction> newPosition) {
|
||||
const auto clamp_ = VariantVisitor {
|
||||
[this](const sf::Time& seconds) {
|
||||
@ -515,6 +520,8 @@ void EditorState::display_status() {
|
||||
"No jacket loaded");
|
||||
}
|
||||
}
|
||||
|
||||
audio.display_debug();
|
||||
}
|
||||
ImGui::End();
|
||||
};
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
const std::string music_stream = "music";
|
||||
const std::string note_clap_stream = "note_clap";
|
||||
const std::string note_clap_stream = "aaa_note_clap";
|
||||
const std::string beat_tick_stream = "beat_tick";
|
||||
|
||||
/*
|
||||
@ -86,6 +86,7 @@ public:
|
||||
void stop();
|
||||
sf::SoundSource::Status get_status();
|
||||
void set_pitch(float pitch);
|
||||
float get_pitch() const;
|
||||
void set_playback_position(std::variant<sf::Time, Fraction> newPosition);
|
||||
sf::Time get_precise_playback_position();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user