diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 749d4098d..b3fc92c81 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -649,7 +649,7 @@ struct Data { bool SuggestEmoji = true; bool SuggestStickersByEmoji = true; base::Observable ReplaceEmojiChanged; - float VoiceMsgPlaybackSpeed = 1.f; + float64 VoiceMsgPlaybackSpeed = 1.; bool SoundNotify = true; bool DesktopNotify = true; bool RestoreSoundNotifyFromTray = false; @@ -779,7 +779,7 @@ DefineVar(Global, bool, ReplaceEmoji); DefineVar(Global, bool, SuggestEmoji); DefineVar(Global, bool, SuggestStickersByEmoji); DefineRefVar(Global, base::Observable, ReplaceEmojiChanged); -DefineVar(Global, float, VoiceMsgPlaybackSpeed); +DefineVar(Global, float64, VoiceMsgPlaybackSpeed); DefineVar(Global, bool, SoundNotify); DefineVar(Global, bool, DesktopNotify); DefineVar(Global, bool, RestoreSoundNotifyFromTray); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index b257918b0..e1100fbcc 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -304,7 +304,7 @@ DeclareVar(bool, ReplaceEmoji); DeclareVar(bool, SuggestEmoji); DeclareVar(bool, SuggestStickersByEmoji); DeclareRefVar(base::Observable, ReplaceEmojiChanged); -DeclareVar(float, VoiceMsgPlaybackSpeed); +DeclareVar(float64, VoiceMsgPlaybackSpeed); DeclareVar(bool, SoundNotify); DeclareVar(bool, DesktopNotify); DeclareVar(bool, RestoreSoundNotifyFromTray); diff --git a/Telegram/SourceFiles/media/media_audio.cpp b/Telegram/SourceFiles/media/media_audio.cpp index a7496755c..3fbcdf3c9 100644 --- a/Telegram/SourceFiles/media/media_audio.cpp +++ b/Telegram/SourceFiles/media/media_audio.cpp @@ -318,14 +318,16 @@ Mixer *mixer() { return Audio::MixerInstance; } -void Mixer::Track::createStream() { +void Mixer::Track::createStream(AudioMsgId::Type type) { alGenSources(1, &stream.source); alSourcef(stream.source, AL_PITCH, 1.f); alSource3f(stream.source, AL_POSITION, 0, 0, 0); alSource3f(stream.source, AL_VELOCITY, 0, 0, 0); alSourcei(stream.source, AL_LOOPING, 0); alGenBuffers(3, stream.buffers); - mixer()->updatePlaybackSpeed(); + if (type == AudioMsgId::Type::Voice) { + mixer()->updatePlaybackSpeed(this); + } } void Mixer::Track::destroyStream() { @@ -344,7 +346,7 @@ void Mixer::Track::reattach(AudioMsgId::Type type) { return; } - createStream(); + createStream(type); for (auto i = 0; i != kBuffersCount; ++i) { if (!samplesCount[i]) { break; @@ -415,9 +417,9 @@ bool Mixer::Track::isStreamCreated() const { return alIsSource(stream.source); } -void Mixer::Track::ensureStreamCreated() { +void Mixer::Track::ensureStreamCreated(AudioMsgId::Type type) { if (!isStreamCreated()) { - createStream(); + createStream(type); } } @@ -1019,26 +1021,30 @@ void Mixer::stop(const AudioMsgId &audio, State state) { if (current) emit updated(current); } -void Mixer::updatePlaybackSpeed() -{ - const auto track = trackForType(AudioMsgId::Type::Voice); - if (!track || track->state.id.type() != AudioMsgId::Type::Voice || !track->isStreamCreated()) { +// Thread: Any. Must be locked: AudioMutex. +void Mixer::updatePlaybackSpeed(Track *track) { + const auto doubled = (_voicePlaybackSpeed.loadAcquire() == 2); + updatePlaybackSpeed(track, doubled); +} + +void Mixer::updatePlaybackSpeed(Track *track, bool doubled) { + if (!track->isStreamCreated()) { return; } - const auto src = track->stream.source; + const auto source = track->stream.source; // Note: This alters the playback speed AND the pitch - alSourcef(src, AL_PITCH, Global::VoiceMsgPlaybackSpeed()); + alSourcef(source, AL_PITCH, doubled ? 2. : 1.); // fix the pitch using effects and filters - if (Global::VoiceMsgPlaybackSpeed() > 1.f) { + if (doubled) { // connect the effect slot with the stream - alSource3i(src, AL_AUXILIARY_SEND_FILTER, Media::Audio::_playbackSpeedData.uiEffectSlot, 0, 0); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, Media::Audio::_playbackSpeedData.uiEffectSlot, 0, 0); // connect the filter with the stream - alSourcei(src, AL_DIRECT_FILTER, Media::Audio::_playbackSpeedData.uiFilter); + alSourcei(source, AL_DIRECT_FILTER, Media::Audio::_playbackSpeedData.uiFilter); } else { // disconnect the effect slot - alSource3i(src, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, 0); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, 0, 0); // disconnect the filter - alSourcei(src, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); } } @@ -1143,6 +1149,17 @@ void Mixer::reattachTracks() { _videoTrack.reattach(AudioMsgId::Type::Video); } +// Thread: Any. Locks AudioMutex. +void Mixer::setVoicePlaybackSpeed(float64 speed) { + const auto doubled = (std::round(speed) == 2); + _voicePlaybackSpeed.storeRelease(doubled ? 2 : 1); + + QMutexLocker lock(&AudioMutex); + for (auto &track : _audioTracks) { + updatePlaybackSpeed(&track, doubled); + } +} + void Mixer::setSongVolume(float64 volume) { _volumeSong.storeRelease(qRound(volume * kVolumeRound)); } diff --git a/Telegram/SourceFiles/media/media_audio.h b/Telegram/SourceFiles/media/media_audio.h index 016c26e85..d5341d869 100644 --- a/Telegram/SourceFiles/media/media_audio.h +++ b/Telegram/SourceFiles/media/media_audio.h @@ -117,8 +117,6 @@ public: void stop(const AudioMsgId &audio); void stop(const AudioMsgId &audio, State state); - void updatePlaybackSpeed(); - // Video player audio stream interface. void feedFromVideo(VideoSoundPart &&part); int64 getVideoCorrectedTime(const AudioMsgId &id, TimeMs frameMs, TimeMs systemMs); @@ -144,6 +142,9 @@ public: void setVideoVolume(float64 volume); float64 getVideoVolume() const; + // Thread: Any. Locks AudioMutex. + void setVoicePlaybackSpeed(float64 speed); + ~Mixer(); private slots: @@ -183,7 +184,7 @@ private: void started(); bool isStreamCreated() const; - void ensureStreamCreated(); + void ensureStreamCreated(AudioMsgId::Type type); int getNotQueuedBufferIndex(); @@ -215,7 +216,7 @@ private: TimeMs lastUpdateCorrectedMs = 0; private: - void createStream(); + void createStream(AudioMsgId::Type type); void destroyStream(); void resetStream(); @@ -223,6 +224,8 @@ private: // Thread: Any. Must be locked: AudioMutex. void setStoppedState(Track *current, State state = State::Stopped); + void updatePlaybackSpeed(Track *track); + void updatePlaybackSpeed(Track *track, bool doubled); Track *trackForType(AudioMsgId::Type type, int index = -1); // -1 uses currentIndex(type) const Track *trackForType(AudioMsgId::Type type, int index = -1) const; @@ -239,6 +242,7 @@ private: QAtomicInt _volumeVideo; QAtomicInt _volumeSong; + QAtomicInt _voicePlaybackSpeed; friend class Fader; friend class Loaders; diff --git a/Telegram/SourceFiles/media/media_audio_loaders.cpp b/Telegram/SourceFiles/media/media_audio_loaders.cpp index 7d62955ea..f41850b1c 100644 --- a/Telegram/SourceFiles/media/media_audio_loaders.cpp +++ b/Telegram/SourceFiles/media/media_audio_loaders.cpp @@ -206,7 +206,7 @@ void Loaders::loadData(AudioMsgId audio, TimeMs positionMs) { track->fadeStartPosition = position; } if (samplesCount) { - track->ensureStreamCreated(); + track->ensureStreamCreated(type); auto bufferIndex = track->getNotQueuedBufferIndex(); diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp index 9baa44ee7..cf7fc32b0 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.cpp +++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp @@ -133,10 +133,11 @@ Widget::Widget(QWidget *parent) : RpWidget(parent) updatePlaybackSpeedIcon(); _playbackSpeed->setClickedCallback([=] { - Global::SetVoiceMsgPlaybackSpeed(Global::VoiceMsgPlaybackSpeed() == 1.f ? 2.f : 1.f); - mixer()->updatePlaybackSpeed(); + const auto updated = (3. - Global::VoiceMsgPlaybackSpeed()); + Global::SetVoiceMsgPlaybackSpeed(updated); + mixer()->setVoicePlaybackSpeed(updated); updatePlaybackSpeedIcon(); - Local::writeSettings(); + Local::writeUserSettings(); }); subscribe(instance()->repeatChangedNotifier(), [this](AudioMsgId::Type type) { @@ -369,10 +370,9 @@ void Widget::updateRepeatTrackIcon() { _repeatTrack->setRippleColorOverride(repeating ? nullptr : &st::mediaPlayerRepeatDisabledRippleBg); } -void Widget::updatePlaybackSpeedIcon() -{ +void Widget::updatePlaybackSpeedIcon() { const auto playbackSpeed = Global::VoiceMsgPlaybackSpeed(); - const auto isDefaultSpeed = playbackSpeed == 1.f; + const auto isDefaultSpeed = std::round(playbackSpeed) == 1.f; _playbackSpeed->setIconOverride(isDefaultSpeed ? &st::mediaPlayerSpeedDisabledIcon : nullptr, isDefaultSpeed ? &st::mediaPlayerSpeedDisabledIconOver : nullptr); _playbackSpeed->setRippleColorOverride(isDefaultSpeed ? &st::mediaPlayerSpeedDisabledRippleBg : nullptr); } diff --git a/Telegram/SourceFiles/messenger.cpp b/Telegram/SourceFiles/messenger.cpp index 8ab59e4d6..e8307a0b0 100644 --- a/Telegram/SourceFiles/messenger.cpp +++ b/Telegram/SourceFiles/messenger.cpp @@ -510,6 +510,9 @@ void Messenger::startMtp() { if (_authSession) { // Skip all pending self updates so that we won't Local::writeSelf. Notify::peerUpdatedSendDelayed(); + + Media::Player::mixer()->setVoicePlaybackSpeed( + Global::VoiceMsgPlaybackSpeed()); } } @@ -1114,6 +1117,8 @@ void Messenger::loggedOut() { } clearPasscodeLock(); Media::Player::mixer()->stopAndClear(); + Global::SetVoiceMsgPlaybackSpeed(1.); + Media::Player::mixer()->setVoicePlaybackSpeed(1.); if (const auto w = getActiveWindow()) { w->tempDirDelete(Local::ClearManagerAll); w->setupIntro(); diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 22f354064..f067fef93 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -1751,11 +1751,11 @@ bool _readSetting(quint32 blockId, QDataStream &stream, int version, ReadSetting } break; case dbiPlaybackSpeed: { - quint32 v; + qint32 v; stream >> v; if (!_checkStreamStatus(stream)) return false; - Global::SetVoiceMsgPlaybackSpeed(v); + Global::SetVoiceMsgPlaybackSpeed((v == 2) ? 2. : 1.); } break; default: @@ -1975,7 +1975,7 @@ void _writeUserSettings() { ? userDataInstance->serialize() : QByteArray(); - uint32 size = 22 * (sizeof(quint32) + sizeof(qint32)); + uint32 size = 23 * (sizeof(quint32) + sizeof(qint32)); size += sizeof(quint32) + Serialize::stringSize(Global::AskDownloadPath() ? QString() : Global::DownloadPath()) + Serialize::bytearraySize(Global::AskDownloadPath() ? QByteArray() : Global::DownloadPathBookmark()); size += sizeof(quint32) + sizeof(qint32); @@ -2028,6 +2028,7 @@ void _writeUserSettings() { if (!userData.isEmpty()) { data.stream << quint32(dbiAuthSessionSettings) << userData; } + data.stream << quint32(dbiPlaybackSpeed) << qint32(std::round(Global::VoiceMsgPlaybackSpeed())); { data.stream << quint32(dbiRecentEmoji) << recentEmojiPreloadData; @@ -2605,7 +2606,6 @@ void writeSettings() { data.stream << quint32(dbiLoggedPhoneNumber) << cLoggedPhoneNumber(); data.stream << quint32(dbiTxtDomainString) << Global::TxtDomainString(); data.stream << quint32(dbiAnimationsDisabled) << qint32(anim::Disabled() ? 1 : 0); - data.stream << quint32(dbiPlaybackSpeed) << quint32(Global::VoiceMsgPlaybackSpeed()); data.stream << quint32(dbiConnectionType) << qint32(dbictProxiesList); data.stream << qint32(proxies.size());