diff --git a/src/audio/AL/ALAudio.cpp b/src/audio/AL/ALAudio.cpp index 19998c0f..25aed995 100644 --- a/src/audio/AL/ALAudio.cpp +++ b/src/audio/AL/ALAudio.cpp @@ -83,6 +83,7 @@ void ALStream::bindSpeaker(speakerid_t speaker) { sp = audio::get_speaker(speaker); if (sp) { auto alspeaker = dynamic_cast(sp); + alspeaker->stream = this; alspeaker->duration = source->getTotalDuration(); } } @@ -101,13 +102,23 @@ void ALStream::update(double delta) { return; } ALSpeaker* alspeaker = dynamic_cast(speaker); - uint source = alspeaker->source; - uint processed = AL::getSourcei(source, AL_BUFFERS_PROCESSED); + uint alsource = alspeaker->source; + uint processed = AL::getSourcei(alsource, AL_BUFFERS_PROCESSED); while (processed--) { uint buffer; - AL_CHECK(alSourceUnqueueBuffers(source, 1, &buffer)); + AL_CHECK(alSourceUnqueueBuffers(alsource, 1, &buffer)); unusedBuffers.push(buffer); + + uint bps = source->getBitsPerSample()/8; + uint channels = source->getChannels(); + + ALint bufferSize; + alGetBufferi(buffer, AL_SIZE, &bufferSize); + totalPlayedSamples += bufferSize / bps / channels; + if (source->isSeekable()) { + totalPlayedSamples %= source->getTotalSamples(); + } } uint preloaded = 0; @@ -116,7 +127,7 @@ void ALStream::update(double delta) { if (preloadBuffer(buffer, loop)) { preloaded++; unusedBuffers.pop(); - AL_CHECK(alSourceQueueBuffers(source, 1, &buffer)); + AL_CHECK(alSourceQueueBuffers(alsource, 1, &buffer)); } } if (speaker->isStopped() && !alspeaker->stopped) { @@ -128,6 +139,19 @@ void ALStream::update(double delta) { } } +duration_t ALStream::getTime() const { + uint total = totalPlayedSamples; + auto alspeaker = dynamic_cast(audio::get_speaker(this->speaker)); + if (alspeaker) { + uint alsource = alspeaker->source; + total += static_cast(AL::getSourcef(alsource, AL_SAMPLE_OFFSET)); + if (source->isSeekable()) { + total %= source->getTotalSamples(); + } + } + return total / static_cast(source->getSampleRate()); +} + void ALStream::setTime(duration_t time) { // TODO: implement } @@ -212,6 +236,9 @@ void ALSpeaker::stop() { } duration_t ALSpeaker::getTime() const { + if (stream) { + return stream->getTime(); + } return static_cast(AL::getSourcef(source, AL_SEC_OFFSET)); } diff --git a/src/audio/AL/ALAudio.h b/src/audio/AL/ALAudio.h index 94a1e3ba..3383b4d7 100644 --- a/src/audio/AL/ALAudio.h +++ b/src/audio/AL/ALAudio.h @@ -56,6 +56,8 @@ namespace audio { bool preloadBuffer(uint buffer, bool loop); public: + size_t totalPlayedSamples = 0; + ALStream(ALAudio* al, std::shared_ptr source, bool keepSource); ~ALStream(); @@ -64,6 +66,8 @@ namespace audio { Speaker* createSpeaker(bool loop, int channel) override; speakerid_t getSpeaker() const override; void update(double delta) override; + + duration_t getTime() const override; void setTime(duration_t time) override; static inline constexpr uint STREAM_BUFFERS = 3; @@ -76,6 +80,7 @@ namespace audio { int channel; float volume = 0.0f; public: + ALStream* stream = nullptr; bool stopped = true; bool paused = false; uint source; diff --git a/src/audio/NoAudio.h b/src/audio/NoAudio.h index 37c72113..3029adea 100644 --- a/src/audio/NoAudio.h +++ b/src/audio/NoAudio.h @@ -53,6 +53,10 @@ namespace audio { void update(double delta) override { } + duration_t getTime() const override { + return 0.0; + } + void setTime(duration_t time) override { } }; diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index af852f2a..b5e61b15 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -347,6 +347,14 @@ Channel* audio::get_channel(int index) { return channels.at(index).get(); } +std::shared_ptr audio::get_associated_stream(speakerid_t id) { + auto found = streams.find(id); + if (found != streams.end()) { + return found->second; + } + return nullptr; +} + size_t audio::count_speakers() { return speakers.size(); } diff --git a/src/audio/audio.h b/src/audio/audio.h index 67358173..61609b41 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -182,6 +182,9 @@ namespace audio { /// @param delta time elapsed since the last update virtual void update(double delta) = 0; + /// @brief Get current stream time + virtual duration_t getTime() const = 0; + /// @brief Set playhead to the selected time /// @param time selected time virtual void setTime(duration_t time) = 0; @@ -473,6 +476,11 @@ namespace audio { /// @return channel or nullptr extern Channel* get_channel(int index); + /// @brief Get stream associated with speaker + /// @param id speaker id + /// @return stream or nullptr + extern std::shared_ptr get_associated_stream(speakerid_t id); + /// @brief Get alive speakers number (including paused) extern size_t count_speakers();