diff --git a/au4/src/au3wrap/CMakeLists.txt b/au4/src/au3wrap/CMakeLists.txt
index 1be7b848dbb5d6e1b5a8d8611d516908bcf6b06f..6275a7f4b312b8126990dc6864a1acfc20a64644 100644
--- a/au4/src/au3wrap/CMakeLists.txt
+++ b/au4/src/au3wrap/CMakeLists.txt
@@ -31,6 +31,8 @@ set(MODULE_SRC
     ${CMAKE_CURRENT_LIST_DIR}/audacity3playback.cpp
     ${CMAKE_CURRENT_LIST_DIR}/audacity3playback.h
     ${CMAKE_CURRENT_LIST_DIR}/iau3wavepainter.h
+    ${CMAKE_CURRENT_LIST_DIR}/iaudacity3playback.h
+    ${CMAKE_CURRENT_LIST_DIR}/iaudacity3audiooutput.h
 
     ${CMAKE_CURRENT_LIST_DIR}/mocks/au3settingsmock.cpp
     ${CMAKE_CURRENT_LIST_DIR}/mocks/au3settingsmock.h
@@ -47,6 +49,8 @@ set(MODULE_SRC
     ${CMAKE_CURRENT_LIST_DIR}/internal/au3wavepainter.h
     ${CMAKE_CURRENT_LIST_DIR}/internal/WaveformScale.cpp
     ${CMAKE_CURRENT_LIST_DIR}/internal/WaveformScale.h
+    ${CMAKE_CURRENT_LIST_DIR}/internal/audacity3audiooutput.cpp
+    ${CMAKE_CURRENT_LIST_DIR}/internal/audacity3audiooutput.h
     )
 
 # ==================================
diff --git a/au4/src/au3wrap/au3wrapmodule.cpp b/au4/src/au3wrap/au3wrapmodule.cpp
index 0712bd38544da1fc2dbc6bf5b852376e426e6f12..139dfe386a1b183b6930309a1817e149edc674d9 100644
--- a/au4/src/au3wrap/au3wrapmodule.cpp
+++ b/au4/src/au3wrap/au3wrapmodule.cpp
@@ -69,6 +69,8 @@ void Au3WrapModule::onInit(const muse::IApplication::RunMode&)
     if (!ok) {
         LOGE() << "failed init sql";
     }
+
+    m_playback->init();
 }
 
 void Au3WrapModule::onDeinit()
diff --git a/au4/src/au3wrap/audacity3playback.cpp b/au4/src/au3wrap/audacity3playback.cpp
index 5da201f0ee388351e3dc63a9e26f005c07ce8f05..a6858fbfd5ef2cd2121dba84e2c7f00524b3edeb 100644
--- a/au4/src/au3wrap/audacity3playback.cpp
+++ b/au4/src/au3wrap/audacity3playback.cpp
@@ -14,10 +14,17 @@
 
 #include "wxtypes_convert.h"
 
+#include "internal/audacity3audiooutput.h"
+
 #include "log.h"
 
 using namespace au::au3;
 
+void Audacity3Playback::init()
+{
+    m_audioOutputPtr = std::make_shared<Audacity3AudioOutput>();
+}
+
 void Audacity3Playback::play()
 {
     //! NOTE: copied from ProjectAudioManager::PlayPlayRegion
@@ -264,6 +271,11 @@ muse::async::Channel<au::audio::PlaybackStatus> Audacity3Playback::playbackStatu
     return m_playbackStatusChanged;
 }
 
+IAudacity3AudioOutputPtr Audacity3Playback::audioOutput() const
+{
+    return m_audioOutputPtr;
+}
+
 AudacityProject& Audacity3Playback::projectRef() const
 {
     AudacityProject* project = reinterpret_cast<AudacityProject*>(globalContext()->currentProject()->au3ProjectPtr());
diff --git a/au4/src/au3wrap/audacity3playback.h b/au4/src/au3wrap/audacity3playback.h
index dd998d893e850f8a20d928db1d06cc85bf678125..18d849849cef49914c0ef2ec12e2220444daa30c 100644
--- a/au4/src/au3wrap/audacity3playback.h
+++ b/au4/src/au3wrap/audacity3playback.h
@@ -11,6 +11,7 @@
 #include "context/iglobalcontext.h"
 
 #include "iaudacity3playback.h"
+#include "iaudacity3audiooutput.h"
 
 class AudacityProject;
 class TrackList;
@@ -22,6 +23,8 @@ class Audacity3Playback : public IAudacity3Playback, public muse::async::Asyncab
     muse::Inject<au::context::IGlobalContext> globalContext;
 
 public:
+    void init();
+
     void play() override;
     void seek(const audio::msecs_t newPositionMsecs) override;
     void stop() override;
@@ -35,6 +38,8 @@ public:
     muse::async::Channel<audio::msecs_t> playbackPositionMsecs() const override;
     muse::async::Channel<audio::PlaybackStatus> playbackStatusChanged() const override;
 
+    IAudacity3AudioOutputPtr audioOutput() const override;
+
 private:
     AudacityProject& projectRef() const;
 
@@ -43,6 +48,8 @@ private:
 
     mutable muse::async::Channel<audio::msecs_t> m_playbackPositionMsecsChanged;
     mutable muse::async::Channel<audio::PlaybackStatus> m_playbackStatusChanged;
+
+    IAudacity3AudioOutputPtr m_audioOutputPtr;
 };
 }
 
diff --git a/au4/src/au3wrap/iaudacity3audiooutput.h b/au4/src/au3wrap/iaudacity3audiooutput.h
new file mode 100644
index 0000000000000000000000000000000000000000..2500fcd1bb5f03e5a2d4ee05441178beae8b8e2e
--- /dev/null
+++ b/au4/src/au3wrap/iaudacity3audiooutput.h
@@ -0,0 +1,31 @@
+/*
+* Audacity: A Digital Audio Editor
+*/
+
+#ifndef AU_AU3WRAP_IAUDACITYAUDIOOUTPUT_H
+#define AU_AU3WRAP_IAUDACITYAUDIOOUTPUT_H
+
+#include <memory>
+
+#include "global/async/promise.h"
+#include "global/async/channel.h"
+
+#include "playback/audiotypes.h"
+
+namespace au::au3 {
+class IAudacity3AudioOutput
+{
+public:
+    virtual ~IAudacity3AudioOutput() = default;
+
+    virtual muse::async::Promise<float> playbackVolume() const = 0;
+    virtual void setPlaybackVolume(float volume) = 0;
+    virtual muse::async::Channel<float> playbackVolumeChanged() const = 0;
+
+    virtual muse::async::Promise<au::audio::AudioSignalChanges> playbackSignalChanges() const = 0;
+};
+
+using IAudacity3AudioOutputPtr = std::shared_ptr<IAudacity3AudioOutput>;
+}
+
+#endif // AU_AU3WRAP_IAUDACITYAUDIOOUTPUT_H
diff --git a/au4/src/au3wrap/iaudacity3playback.h b/au4/src/au3wrap/iaudacity3playback.h
index 2ccd6563b7496ec8bf233169e6c39fe10e5a7bfd..1cddd4c73f07c2b7dfd567140debe6358d6f61fb 100644
--- a/au4/src/au3wrap/iaudacity3playback.h
+++ b/au4/src/au3wrap/iaudacity3playback.h
@@ -11,7 +11,7 @@
 
 #include "playback/audiotypes.h"
 
-class AudacityProject;
+#include "iaudacity3audiooutput.h"
 
 namespace au::au3 {
 class IAudacity3Playback : MODULE_EXPORT_INTERFACE
@@ -32,6 +32,8 @@ public:
 
     virtual muse::async::Channel<audio::msecs_t> playbackPositionMsecs() const = 0;
     virtual muse::async::Channel<audio::PlaybackStatus> playbackStatusChanged() const = 0;
+
+    virtual std::shared_ptr<IAudacity3AudioOutput> audioOutput() const = 0;
 };
 using IAudacity3PlaybackPtr = std::shared_ptr<IAudacity3Playback>;
 }
diff --git a/au4/src/au3wrap/internal/audacity3audiooutput.cpp b/au4/src/au3wrap/internal/audacity3audiooutput.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..71f33102442e339ed27117e4ed38ae5b8cc610f0
--- /dev/null
+++ b/au4/src/au3wrap/internal/audacity3audiooutput.cpp
@@ -0,0 +1,59 @@
+/*
+* Audacity: A Digital Audio Editor
+*/
+
+#include "audacity3audiooutput.h"
+
+#include "types/ret.h"
+#include "global/async/async.h"
+
+#include "libraries/lib-audio-io/AudioIO.h"
+
+#include "log.h"
+
+using namespace muse;
+using namespace muse::async;
+using namespace au::au3;
+
+muse::async::Promise<au::audio::volume_dbfs_t> Audacity3AudioOutput::playbackVolume() const
+{
+    return muse::async::Promise<float>([](auto resolve, auto /*reject*/) {
+        float inputVolume;
+        float outputVolume;
+        int inputSource;
+
+        auto gAudioIO = AudioIO::Get();
+        gAudioIO->GetMixer(&inputSource, &inputVolume, &outputVolume);
+
+        return resolve(outputVolume);
+    });
+}
+
+void Audacity3AudioOutput::setPlaybackVolume(float volume)
+{
+    muse::async::Async::call(this, [this, volume]() {
+        float inputVolume;
+        float outputVolume;
+        int inputSource;
+
+        auto gAudioIO = AudioIO::Get();
+        gAudioIO->GetMixer(&inputSource, &inputVolume, &outputVolume);
+
+        gAudioIO->SetMixer(inputSource, inputVolume, volume);
+
+        m_playbackVolumeChanged.send(volume);
+    });
+}
+
+muse::async::Channel<au::audio::volume_dbfs_t> Audacity3AudioOutput::playbackVolumeChanged() const
+{
+    return m_playbackVolumeChanged;
+}
+
+muse::async::Promise<au::audio::AudioSignalChanges> Audacity3AudioOutput::playbackSignalChanges() const
+{
+    return muse::async::Promise<audio::AudioSignalChanges>([](auto, auto reject) {
+        muse::Ret ret = make_ret(muse::Ret::Code::NotImplemented);
+        return reject(ret.code(), ret.text());
+    });
+}
diff --git a/au4/src/au3wrap/internal/audacity3audiooutput.h b/au4/src/au3wrap/internal/audacity3audiooutput.h
new file mode 100644
index 0000000000000000000000000000000000000000..0d71433acd2563362c9cd625b7bbefdd10ee4cea
--- /dev/null
+++ b/au4/src/au3wrap/internal/audacity3audiooutput.h
@@ -0,0 +1,27 @@
+/*
+* Audacity: A Digital Audio Editor
+*/
+
+#ifndef AU_AU3WRAP_AUDIOOUTPUT_H
+#define AU_AU3WRAP_AUDIOOUTPUT_H
+
+#include "global/async/asyncable.h"
+
+#include "../iaudacity3audiooutput.h"
+
+namespace au::au3 {
+class Audacity3AudioOutput : public IAudacity3AudioOutput, public muse::async::Asyncable
+{
+public:
+    muse::async::Promise<float> playbackVolume() const override;
+    void setPlaybackVolume(float volume) override;
+    muse::async::Channel<float> playbackVolumeChanged() const override;
+
+    muse::async::Promise<au::audio::AudioSignalChanges> playbackSignalChanges() const override;
+
+private:
+    mutable muse::async::Channel<float> m_playbackVolumeChanged;
+};
+}
+
+#endif // AU_AU3WRAP_AUDIOOUTPUT_H
diff --git a/au4/src/playback/qml/Audacity/Playback/PlaybackToolBar.qml b/au4/src/playback/qml/Audacity/Playback/PlaybackToolBar.qml
index fac3914e542f274a489b753494343a33ead714d8..cf17b7f5730b04d09d74049e52f97b0050affbf8 100644
--- a/au4/src/playback/qml/Audacity/Playback/PlaybackToolBar.qml
+++ b/au4/src/playback/qml/Audacity/Playback/PlaybackToolBar.qml
@@ -157,8 +157,6 @@ Item {
                         Connections {
                             target: btn.mouseArea
 
-                            // Make sure we only connect to `pressAndHold` if necessary
-                            // See https://github.com/musescore/MuseScore/issues/16012
                             enabled: btn.hasMenu && !menuLoader.isMenuOpened
 
                             function onPressAndHold() {
@@ -210,7 +208,13 @@ Item {
                     id: playbackLevelComp
 
                     PlaybackLevel {
+                        property var item: loader.itemData
+
                         width: 128
+
+                        onVolumeLevelChangeRequested: function(level) {
+                            item.level = level
+                        }
                     }
                 }
             }
diff --git a/au4/src/playback/qml/Audacity/Playback/internal/PlaybackLevel.qml b/au4/src/playback/qml/Audacity/Playback/internal/PlaybackLevel.qml
index 3ae99a9df6ae9b076114f3c66f1e2e50c7c0d2d8..e442cf28b7da6323d05e344b25bd3dcfdf765626 100644
--- a/au4/src/playback/qml/Audacity/Playback/internal/PlaybackLevel.qml
+++ b/au4/src/playback/qml/Audacity/Playback/internal/PlaybackLevel.qml
@@ -15,6 +15,8 @@ Item {
 
     height: 32
 
+    signal volumeLevelChangeRequested(var level)
+
     RowLayout {
         anchors.fill: parent
         anchors.margins: 6
@@ -35,7 +37,7 @@ Item {
             Layout.alignment: Qt.AlighVCenter
 
             onVolumeLevelMoved: function(level) {
-                volumeLevel = Math.round(level * 10) / 10
+                root.volumeLevelChangeRequested(Math.round(level * 10) / 10)
             }
         }
     }
diff --git a/au4/src/playback/qml/Audacity/Playback/internal/VolumeSlider.qml b/au4/src/playback/qml/Audacity/Playback/internal/VolumeSlider.qml
index da21eeb1a902dd027a92477c00c4166ee8d811dc..b302f7b6765ed26bed0d552314b944cd53bb06a4 100644
--- a/au4/src/playback/qml/Audacity/Playback/internal/VolumeSlider.qml
+++ b/au4/src/playback/qml/Audacity/Playback/internal/VolumeSlider.qml
@@ -1,24 +1,6 @@
 /*
- * SPDX-License-Identifier: GPL-3.0-only
- * MuseScore-CLA-applies
- *
- * MuseScore
- * Music Composition & Notation
- *
- * Copyright (C) 2021 MuseScore BVBA and others
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
+* Audacity: A Digital Audio Editor
+*/
 
 import QtQuick 2.15
 import QtQuick.Controls 2.15
@@ -69,7 +51,7 @@ Slider {
         readonly property real indicatorHeight: 6
 
         readonly property real rulerLineWidth: root.width - handleWidth
-        readonly property real rulerLineHeight: 2 // todo
+        readonly property real rulerLineHeight: 2
 
         readonly property int rulerYPos: margin + indicatorHeight + spacing / 2
 
@@ -84,7 +66,7 @@ Slider {
 
     NavigationControl {
         id: navCtrl
-        name: root.objectName != "" ? root.objectName : "VolumeSlider"
+        name: root.objectName !== "" ? root.objectName : "VolumeSlider"
         enabled: root.enabled && root.visible
 
         accessible.role: MUAccessible.Range
@@ -201,8 +183,7 @@ Slider {
     onMoved: {
         navigation.requestActiveByInteraction()
 
-        var newLevel = convertor.volumeLevelFromLocal(value)
-        root.volumeLevelMoved(newLevel)
+        root.volumeLevelMoved(value)
     }
 
     Component.onCompleted: {
diff --git a/au4/src/playback/view/toolbars/playbacktoolbarlevelitem.cpp b/au4/src/playback/view/toolbars/playbacktoolbarlevelitem.cpp
index 3ae7102a222dc351787ed08f8e1dcc6cf4df61d4..3639154e1ff33711be3b30e8befe9ac96268db9f 100644
--- a/au4/src/playback/view/toolbars/playbacktoolbarlevelitem.cpp
+++ b/au4/src/playback/view/toolbars/playbacktoolbarlevelitem.cpp
@@ -24,10 +24,43 @@
 #include <QVariantMap>
 
 using namespace au::playback;
+using namespace au::au3;
+
+static int au3VolumeToLocal(float volume)
+{
+    //! convert from range 0-1 to -60-0
+    float old_max = 1;
+    float old_min = 0;
+    int old_range = old_max - old_min;
+
+    int new_max = 0;
+    int new_min = -60;
+    int new_range = new_max - new_min;
+
+    return (((volume - old_min) * new_range) / old_range) + new_min;
+}
+
+static float localVolumeToAu3(int volume)
+{
+    //! convert from range -60-0 to 0-1
+    float old_max = 0;
+    float old_min = -60;
+    int old_range = old_max - old_min;
+
+    int new_max = 1;
+    int new_min = 0;
+    int new_range = new_max - new_min;
+
+    return (((volume - old_min) * new_range) / old_range) + new_min;
+}
 
 PlaybackToolBarLevelItem::PlaybackToolBarLevelItem(const muse::ui::UiAction& action, const ItemType& type, QObject* parent)
     : PlaybackToolBarAbstractItem(action, type, parent)
 {
+    playback()->audioOutput()->playbackVolumeChanged().onReceive(this, [this](audio::volume_dbfs_t volume){
+        m_level = au3VolumeToLocal(volume);
+        emit levelChanged();
+    });
 }
 
 int PlaybackToolBarLevelItem::level() const
@@ -41,6 +74,5 @@ void PlaybackToolBarLevelItem::setLevel(int newLevel)
         return;
     }
 
-    m_level = newLevel;
-    emit levelChanged();
+    playback()->audioOutput()->setPlaybackVolume(localVolumeToAu3(newLevel));
 }
diff --git a/au4/src/playback/view/toolbars/playbacktoolbarlevelitem.h b/au4/src/playback/view/toolbars/playbacktoolbarlevelitem.h
index 8fe2453a809b7cd97963705985f7f4249b768f42..8ee35fc1cba2103b5786698c400b3438b16d2c52 100644
--- a/au4/src/playback/view/toolbars/playbacktoolbarlevelitem.h
+++ b/au4/src/playback/view/toolbars/playbacktoolbarlevelitem.h
@@ -6,6 +6,9 @@
 
 #include <QString>
 
+#include "modularity/ioc.h"
+#include "au3wrap/iaudacity3playback.h"
+
 #include "playbacktoolbarabstractitem.h"
 
 namespace au::playback {
@@ -15,6 +18,8 @@ class PlaybackToolBarLevelItem : public PlaybackToolBarAbstractItem
 
     Q_PROPERTY(int level READ level WRITE setLevel NOTIFY levelChanged FINAL)
 
+    muse::Inject<au3::IAudacity3Playback> playback;
+
 public:
     explicit PlaybackToolBarLevelItem(const muse::ui::UiAction& action, const ItemType& type, QObject* parent = nullptr);
 
diff --git a/au4/src/playback/view/toolbars/playbacktoolbarmodel.cpp b/au4/src/playback/view/toolbars/playbacktoolbarmodel.cpp
index a4a2d43383c78aaeb48d7dbfadb8e9b3fe4a1260..e5cb829ad89363284cf43d9b73cdd9d50ba4a77c 100644
--- a/au4/src/playback/view/toolbars/playbacktoolbarmodel.cpp
+++ b/au4/src/playback/view/toolbars/playbacktoolbarmodel.cpp
@@ -6,6 +6,7 @@
 #include "internal/playbackuiactions.h"
 
 #include "view/toolbars/playbacktoolbarabstractitem.h"
+#include "view/toolbars/playbacktoolbarlevelitem.h"
 
 using namespace muse::uicomponents;
 using namespace muse::ui;
@@ -82,8 +83,8 @@ QVariant PlaybackToolBarModel::data(const QModelIndex& index, int role) const
         return QVariant();
     }
 
-    const PlaybackToolBarAbstractItem* item = m_items[row];
-    const ActionCode actionCode = item->action().code;
+    PlaybackToolBarAbstractItem* item = m_items[row];
+    ActionCode actionCode = item->action().code;
 
     switch (role) {
     case ItemRole: return QVariant::fromValue(item);
@@ -149,13 +150,12 @@ void PlaybackToolBarModel::updateActions()
     muse::ui::ToolConfig playbackConfig
         = uiConfiguration()->toolConfig(TOOLBAR_NAME, PlaybackUiActions::defaultPlaybackToolConfig());
 
-    int section = 0;
     for (const muse::ui::ToolConfig::Item& citem : playbackConfig.items) {
         if (!citem.show) {
             continue;
         }
 
-        PlaybackToolBarAbstractItem* item = makeItem(uiActionsRegister()->action(citem.action), QString::number(section));
+        PlaybackToolBarAbstractItem* item = makeItem(uiActionsRegister()->action(citem.action));
 
         if (citem.action == PLAY_ACTION_CODE) {
             item->setAction(playAction());
@@ -176,11 +176,17 @@ bool PlaybackToolBarModel::isMenuSecondary(const muse::actions::ActionCode& acti
     return false;
 }
 
-PlaybackToolBarAbstractItem* PlaybackToolBarModel::makeItem(const muse::ui::UiAction& action, const QString& section)
+PlaybackToolBarAbstractItem* PlaybackToolBarModel::makeItem(const muse::ui::UiAction& action)
 {
-    PlaybackToolBarAbstractItem* item = new PlaybackToolBarAbstractItem(action, itemType(action.code), this);
-    item->setSection(section);
-    return item;
+    PlaybackToolBarAbstractItem::ItemType type = itemType(action.code);
+
+    switch (type) {
+    case PlaybackToolBarAbstractItem::PLAYBACK_LEVEL: return new PlaybackToolBarLevelItem(action, type, this);
+    default:
+        break;
+    }
+
+    return new PlaybackToolBarAbstractItem(action, type, this);
 }
 
 UiAction PlaybackToolBarModel::playAction() const
diff --git a/au4/src/playback/view/toolbars/playbacktoolbarmodel.h b/au4/src/playback/view/toolbars/playbacktoolbarmodel.h
index b3a7a12e3d2c3d05373ded945ec9df499a0dd1a8..7813cbb21f63766ce608c2441376fefd1ab7f9e8 100644
--- a/au4/src/playback/view/toolbars/playbacktoolbarmodel.h
+++ b/au4/src/playback/view/toolbars/playbacktoolbarmodel.h
@@ -64,7 +64,7 @@ private:
 
     bool isMenuSecondary(const muse::actions::ActionCode& actionCode) const;
 
-    PlaybackToolBarAbstractItem* makeItem(const muse::ui::UiAction& action, const QString& section);
+    PlaybackToolBarAbstractItem* makeItem(const muse::ui::UiAction& action);
 
     muse::ui::UiAction playAction() const;