diff --git a/Jamulus.pro b/Jamulus.pro
index 3d1d5acd45..499a3dcfa8 100644
--- a/Jamulus.pro
+++ b/Jamulus.pro
@@ -1,10 +1,4 @@
-VERSION = 3.11.0dev
-
-# Using lrelease and embed_translations only works for Qt 5.12 or later.
-# See https://github.com/jamulussoftware/jamulus/pull/3288 for these changes.
-lessThan(QT_MAJOR_VERSION, 5) | equals(QT_MAJOR_VERSION, 5) : lessThan(QT_MINOR_VERSION, 12) {
- error(Jamulus requires at least Qt5.12. See https://github.com/jamulussoftware/jamulus/pull/3288)
-}
+VERSION = 3.12.0qml
# use target name which does not use a capital letter at the beginning
contains(CONFIG, "noupcasename") {
@@ -12,60 +6,23 @@ contains(CONFIG, "noupcasename") {
TARGET = jamulus
}
-# allow detailed version info for intermediate builds (#475)
-contains(VERSION, .*dev.*) {
- exists(".git/config") {
- GIT_DESCRIPTION=$$system(git describe --match=xxxxxxxxxxxxxxxxxxxx --always --abbrev --dirty) # the match should never match
- VERSION = "$$VERSION"-$$GIT_DESCRIPTION
- message("building version \"$$VERSION\" (intermediate in git repository)")
- } else {
- VERSION = "$$VERSION"-nogit
- message("building version \"$$VERSION\" (intermediate without git repository)")
- }
-} else {
- message("building version \"$$VERSION\" (release)")
-}
-
CONFIG += qt \
thread \
- lrelease \
- embed_translations \
- debug_and_release
+ lrelease
QT += network \
xml \
- concurrent
-
-contains(CONFIG, "nosound") {
- CONFIG -= "nosound"
- CONFIG += "serveronly"
- warning("\"nosound\" is deprecated: please use \"serveronly\" for a server-only build.")
-}
+ concurrent \
+ svg
contains(CONFIG, "headless") {
message(Headless mode activated.)
QT -= gui
} else {
- QT += widgets
- QT += multimedia
+ QT += qml \
+ quickcontrols2
}
-# Do not set LRELEASE_DIR explicitly when using embed_translations.
-# It doesn't work with multiple targets or architectures.
-TRANSLATIONS = src/translation/translation_de_DE.ts \
- src/translation/translation_fr_FR.ts \
- src/translation/translation_ko_KR.ts \
- src/translation/translation_pt_PT.ts \
- src/translation/translation_pt_BR.ts \
- src/translation/translation_es_ES.ts \
- src/translation/translation_nb_NO.ts \
- src/translation/translation_nl_NL.ts \
- src/translation/translation_pl_PL.ts \
- src/translation/translation_sk_SK.ts \
- src/translation/translation_it_IT.ts \
- src/translation/translation_sv_SE.ts \
- src/translation/translation_zh_CN.ts
-
INCLUDEPATH += src
INCLUDEPATH_OPUS = libs/opus/include \
@@ -75,135 +32,54 @@ INCLUDEPATH_OPUS = libs/opus/include \
libs/opus/silk/fixed \
libs/opus
-# As JACK is used in multiple OS, we declare it globally
-HEADERS_JACK = src/sound/jack/sound.h
-SOURCES_JACK = src/sound/jack/sound.cpp
-
DEFINES += APP_VERSION=\\\"$$VERSION\\\" \
CUSTOM_MODES \
_REENTRANT
-# some depreciated functions need to be kept for older versions to build
-# TODO as soon as we drop support for the old Qt version, remove the following line
-DEFINES += QT_NO_DEPRECATED_WARNINGS
-
win32 {
DEFINES -= UNICODE # fixes issue with ASIO SDK (asiolist.cpp is not unicode compatible)
- DEFINES += NOMINMAX # solves a compiler error in qdatetime.h (Qt5)
- RC_FILE = src/res/win-mainicon.rc
- mingw* {
- DEFINES += _WIN32_WINNT=0x0600 # solves missing inet_pton in CSocket::SendPacket
- LIBS += -lole32 \
- -luser32 \
- -ladvapi32 \
- -lwinmm \
- -lws2_32
- } else {
- QMAKE_LFLAGS += /DYNAMICBASE:NO # fixes crash with libjack64.dll, see https://github.com/jamulussoftware/jamulus/issues/93
- LIBS += ole32.lib \
- user32.lib \
- advapi32.lib \
- winmm.lib \
- ws2_32.lib
- greaterThan(QT_MAJOR_VERSION, 5) {
- # Qt5 had a special qtmain library which took care of forwarding the MSVC default WinMain() entrypoint to
- # the platform-agnostic main().
- # Qt6 is still supposed to have that lib under the new name QtEntryPoint. As it does not seem
- # to be effective when building with qmake, we are rather instructing MSVC to use the platform-agnostic
- # main() entrypoint directly:
- QMAKE_LFLAGS += /subsystem:windows /ENTRY:mainCRTStartup
- }
- }
-
- contains(CONFIG, "serveronly") {
- message(Restricting build to server-only due to CONFIG+=serveronly.)
- DEFINES += SERVER_ONLY
- } else {
- contains(CONFIG, "jackonwindows") {
- message(Using JACK.)
- contains(QT_ARCH, "i386") {
- exists("C:/Program Files (x86)") {
- message("Cross compilation build")
- programfilesdir = "C:/Program Files (x86)"
- } else {
- message("Native i386 build")
- programfilesdir = "C:/Program Files"
- }
- libjackname = "libjack.lib"
- } else {
- message("Native x86_64 build")
- programfilesdir = "C:/Program Files"
- libjackname = "libjack64.lib"
- }
- !exists("$${programfilesdir}/JACK2/include/jack/jack.h") {
- error("Error: jack.h was not found in the expected location ($${programfilesdir}). Ensure that the right JACK2 variant is installed (32 Bit vs. 64 Bit).")
- }
-
- HEADERS += $$HEADERS_JACK
- SOURCES += $$SOURCES_JACK
- DEFINES += WITH_JACK
- DEFINES += JACK_ON_WINDOWS
- DEFINES += _STDINT_H # supposed to solve compilation error in systemdeps.h
- INCLUDEPATH += "$${programfilesdir}/JACK2/include"
- LIBS += "$${programfilesdir}/JACK2/lib/$${libjackname}"
- } else {
- message(Using native Windows MIDI.)
+ DEFINES += NOMINMAX # solves a compiler error with std::min/max
+ # RC_FILE = src/res/win-mainicon.rc
- HEADERS += src/sound/midi-win/midi.h
- SOURCES += src/sound/midi-win/midi.cpp
+ LIBS += ole32.lib \
+ user32.lib \
+ advapi32.lib \
+ winmm.lib \
+ ws2_32.lib
- message(Using ASIO.)
- message(Please review the ASIO SDK licence.)
-
- !exists(libs/ASIOSDK2/common) {
- error("Error: ASIOSDK2 must be placed in Jamulus \\libs folder such that e.g. \\libs\ASIOSDK2\common exists.")
- }
- # Important: Keep those ASIO includes local to this build target in
- # order to avoid poisoning other builds license-wise.
- HEADERS += src/sound/asio/sound.h
- SOURCES += src/sound/asio/sound.cpp \
- libs/ASIOSDK2/common/asio.cpp \
- libs/ASIOSDK2/host/asiodrivers.cpp \
- libs/ASIOSDK2/host/pc/asiolist.cpp
- INCLUDEPATH += libs/ASIOSDK2/common \
- libs/ASIOSDK2/host \
- libs/ASIOSDK2/host/pc
- }
+ !exists(windows/ASIOSDK2) {
+ error("Error: ASIOSDK2 must be placed in reporoot windows/ folder.")
}
-} else:macx {
- contains(CONFIG, "server_bundle") {
- message(The generated application bundle will run a server instance.)
+ # Important: Keep those ASIO includes local to this build target in
+ # order to avoid poisoning other builds license-wise.
+ HEADERS += src/sound/asio/sound.h
+ SOURCES += src/sound/asio/sound.cpp \
+ windows/ASIOSDK2/common/asio.cpp \
+ windows/ASIOSDK2/host/asiodrivers.cpp \
+ windows/ASIOSDK2/host/pc/asiolist.cpp
+ INCLUDEPATH += windows/ASIOSDK2/common \
+ windows/ASIOSDK2/host \
+ windows/ASIOSDK2/host/pc
- DEFINES += SERVER_BUNDLE
- TARGET = $${TARGET}Server
- MACOSX_BUNDLE_ICON.files = src/res/mac-jamulus-server.icns
- RC_FILE = src/res/mac-jamulus-server.icns
- } else {
- MACOSX_BUNDLE_ICON.files = src/res/mac-mainicon.icns
- RC_FILE = src/res/mac-mainicon.icns
- }
+} else:macx {
+ # MACOSX_BUNDLE_ICON.files = mac/mac-mainicon.icns
HEADERS += src/mac/activity.h src/mac/badgelabel.h
OBJECTIVE_SOURCES += src/mac/activity.mm src/mac/badgelabel.mm
CONFIG += x86
- QMAKE_TARGET_BUNDLE_PREFIX = app.jamulussoftware
+ QMAKE_TARGET_BUNDLE_PREFIX = live.jamulus
+ QMAKE_INFO_PLIST = mac/Info-xcode.plist
OSX_ENTITLEMENTS.files = mac/Jamulus.entitlements
OSX_ENTITLEMENTS.path = Contents/Resources
QMAKE_BUNDLE_DATA += OSX_ENTITLEMENTS
-
- macx-xcode {
- # As of 2023-04-15 the macOS build with Xcode only fails. This is tracked in #1841
- QMAKE_INFO_PLIST = mac/Info-xcode.plist
- XCODE_ENTITLEMENTS.name = CODE_SIGN_ENTITLEMENTS
- XCODE_ENTITLEMENTS.value = mac/Jamulus.entitlements
- QMAKE_MAC_XCODE_SETTINGS += XCODE_ENTITLEMENTS
- MACOSX_BUNDLE_ICON.path = Contents/Resources
- QMAKE_BUNDLE_DATA += MACOSX_BUNDLE_ICON
- } else {
- QMAKE_INFO_PLIST = mac/Info-make.plist
- }
+ XCODE_ENTITLEMENTS.name = CODE_SIGN_ENTITLEMENTS
+ XCODE_ENTITLEMENTS.value = mac/Jamulus.entitlements
+ QMAKE_MAC_XCODE_SETTINGS += XCODE_ENTITLEMENTS
+
+ MACOSX_BUNDLE_ICON.path = Contents/Resources
+ QMAKE_BUNDLE_DATA += MACOSX_BUNDLE_ICON
LIBS += -framework CoreFoundation \
-framework CoreServices \
@@ -214,48 +90,75 @@ win32 {
-framework Foundation \
-framework AppKit
- contains(CONFIG, "jackonmac") {
- message(Using JACK.)
- !exists(/usr/include/jack/jack.h) {
- !exists(/usr/local/include/jack/jack.h) {
- error("Error: jack.h was not found at the usual place, maybe JACK is not installed")
- }
- }
- HEADERS += $$HEADERS_JACK
- SOURCES += $$SOURCES_JACK
- DEFINES += WITH_JACK
- DEFINES += JACK_REPLACES_COREAUDIO
- INCLUDEPATH += /usr/local/include
- LIBS += /usr/local/lib/libjack.dylib
- } else {
- message(Using CoreAudio.)
- HEADERS += src/sound/coreaudio-mac/sound.h
- SOURCES += src/sound/coreaudio-mac/sound.cpp
- }
+ HEADERS += src/sound/coreaudio-mac/sound.h
+ SOURCES += src/sound/coreaudio-mac/sound.cpp
} else:ios {
- QMAKE_ASSET_CATALOGS += src/res/iOSIcons.xcassets
- QMAKE_INFO_PLIST = ios/Info.plist
- OBJECTIVE_SOURCES += src/ios/ios_app_delegate.mm
- HEADERS += src/ios/ios_app_delegate.h
+ # reset TARGET for iOS only since rename
+ TARGET = Jamulus
+ QMAKE_INFO_PLIST = ios/Info-xcode.plist
+ QMAKE_ASSET_CATALOGS += ios/Images.xcassets
+ QMAKE_ASSET_CATALOGS_APP_ICON = "AppIcon"
+ ios_icon.files = $$files($$PWD/ios/AppIcon*.png)
+ QMAKE_BUNDLE_DATA += ios_icon
+
HEADERS += src/sound/coreaudio-ios/sound.h
OBJECTIVE_SOURCES += src/sound/coreaudio-ios/sound.mm
- QMAKE_TARGET_BUNDLE_PREFIX = app.jamulussoftware
+
+ # PRODUCT_BUNDLE_IDENTIFIER is set like
+ # ${PRODUCT_BUNDLE_IDENTIFIER} = QMAKE_TARGET_BUNDLE_PREFIX.QMAKE_BUNDLE
+ QMAKE_TARGET_BUNDLE_PREFIX = live.jamulus
+ QMAKE_BUNDLE = Jamulus
+
LIBS += -framework AVFoundation \
-framework AudioToolbox
+
} else:android {
- ANDROID_ABIS = armeabi-v7a arm64-v8a x86 x86_64
+ # ANDROID_ABIS = armeabi-v7a arm64-v8a x86 x86_64
+ # Build all targets, as per: https://developer.android.com/topic/arc/device-support
+
+ # get ANDROID_ABIS from environment - passed directly to qmake
+ ANDROID_ABIS = $$getenv(ANDROID_ABIS)
+
+ # if ANDROID_ABIS is passed as env var to qmake, will override this
+ # !defined(ANDROID_ABIS, var):ANDROID_ABIS = arm64-v8a
+
+ # by default is 23 = Android 6 !
+ # Update: try with min Android 8.1 - sdk27
+ ANDROID_MIN_SDK_VERSION = 27
+ ANDROID_TARGET_SDK_VERSION = 32
ANDROID_VERSION_NAME = $$VERSION
- ANDROID_VERSION_CODE = $$system(git log --oneline | wc -l)
+
+ ## FOR LOCAL DEV USE:
+ equals(QMAKE_HOST.os, Windows) {
+ ANDROID_ABIS = x86_64
+ ANDROID_VERSION_CODE = 1234 # dummy int value
+ } else {
+ # date-based unique integer value for Play Store submission
+ !defined(ANDROID_VERSION_CODE, var):ANDROID_VERSION_CODE = $$system(date +%s | cut -c 2-)
+ }
+
+ # make separate version codes for each abi build otherwise Play Store rejects
+ contains (ANDROID_ABIS, armeabi-v7a) {
+ ANDROID_VERSION_CODE = $$num_add($$ANDROID_VERSION_CODE, 1)
+ message("Setting for armeabi-v7a: ANDROID_VERSION_CODE=$${ANDROID_VERSION_CODE}")
+ }
+ contains (ANDROID_ABIS, x86) {
+ ANDROID_VERSION_CODE = $$num_add($$ANDROID_VERSION_CODE, 2)
+ message("Setting for x86: ANDROID_VERSION_CODE=$${ANDROID_VERSION_CODE}")
+ }
+ contains (ANDROID_ABIS, x86_64) {
+ ANDROID_VERSION_CODE = $$num_add($$ANDROID_VERSION_CODE, 3)
+ message("Setting for x86_64: ANDROID_VERSION_CODE=$${ANDROID_VERSION_CODE}")
+ }
+
message("Setting ANDROID_VERSION_NAME=$${ANDROID_VERSION_NAME} ANDROID_VERSION_CODE=$${ANDROID_VERSION_CODE}")
# liboboe requires C++17 for std::timed_mutex
CONFIG += c++17
- QT += androidextras
-
# enabled only for debugging on android devices
- DEFINES += ANDROIDDEBUG
+ #DEFINES += ANDROIDDEBUG
target.path = /tmp/your_executable # path on device
INSTALLS += target
@@ -286,15 +189,9 @@ win32 {
HEADERS += $$OBOE_HEADERS
SOURCES += $$OBOE_SOURCES
DISTFILES += $$DISTFILES_OBOE
-} else:unix {
- # we want to compile with C++11
- CONFIG += c++11
- # --as-needed avoids linking the final binary against unnecessary runtime
- # libs. Most g++ versions already do that by default.
- # However, Debian buster does not and would link against libQt5Concurrent
- # unnecessarily without this workaround (#741):
- QMAKE_LFLAGS += -Wl,--as-needed
+} else:unix {
+ CONFIG += c++17
# we assume to have lrintf() one moderately modern linux distributions
# would be better to have that tested, though
@@ -310,17 +207,12 @@ win32 {
} else {
message(JACK Audio Interface Enabled.)
- HEADERS += $$HEADERS_JACK
- SOURCES += $$SOURCES_JACK
-
- contains(CONFIG, "raspijamulus") {
- message(Using JACK Audio in raspijamulus.sh mode.)
- LIBS += -ljack
- } else {
- CONFIG += link_pkgconfig
- PKGCONFIG += jack
- }
+ HEADERS += src/sound/jack/sound.h
+ SOURCES += src/sound/jack/sound.cpp
+ CONFIG += link_pkgconfig
+ PKGCONFIG += jack
+
DEFINES += WITH_JACK
}
@@ -334,59 +226,17 @@ win32 {
BINDIR = $$absolute_path($$BINDIR, $$PREFIX)
target.path = $$BINDIR
- contains(CONFIG, "headless") {
- INSTALLS += target
- } else {
- isEmpty(APPSDIR) {
- APPSDIR = share/applications
- }
- APPSDIR = $$absolute_path($$APPSDIR, $$PREFIX)
- desktop.path = $$APPSDIR
- QMAKE_SUBSTITUTES += linux/jamulus.desktop.in linux/jamulus-server.desktop.in
- desktop.files = linux/jamulus.desktop linux/jamulus-server.desktop
-
- isEmpty(ICONSDIR) {
- ICONSDIR = share/icons/hicolor/512x512/apps
- }
- ICONSDIR = $$absolute_path($$ICONSDIR, $$PREFIX)
- icons.path = $$ICONSDIR
- icons.files = src/res/io.jamulus.jamulus.png
-
- isEmpty(ICONSDIR_SVG) {
- ICONSDIR_SVG = share/icons/hicolor/scalable/apps/
- }
- ICONSDIR_SVG = $$absolute_path($$ICONSDIR_SVG, $$PREFIX)
- icons_svg.path = $$ICONSDIR_SVG
- icons_svg.files = src/res/io.jamulus.jamulus.svg src/res/io.jamulus.jamulusserver.svg
-
- isEmpty(MANDIR) {
- MANDIR = share/man/man1
- }
- MANDIR = $$absolute_path($$MANDIR, $$PREFIX)
- man.path = $$MANDIR
- man.files = linux/Jamulus.1
-
- INSTALLS += target desktop icons icons_svg man
- }
+ INSTALLS += target
}
-# Do not set RCC_DIR explicitly when using embed_translations.
-# It doesn't work with multiple targets or architectures.
+RCC_DIR = src/res
RESOURCES += src/resources.qrc
-FORMS_GUI = src/aboutdlgbase.ui \
- src/serverdlgbase.ui
+#FORMS_GUI = src/serverdlgbase.ui
-!contains(CONFIG, "serveronly") {
- FORMS_GUI += src/clientdlgbase.ui \
- src/clientsettingsdlgbase.ui \
- src/chatdlgbase.ui \
- src/connectdlgbase.ui
-}
-
-HEADERS += src/plugins/audioreverb.h \
- src/buffer.h \
+HEADERS += src/buffer.h \
src/channel.h \
+ src/chatbox.h \
src/global.h \
src/protocol.h \
src/recorder/jamcontroller.h \
@@ -401,6 +251,7 @@ HEADERS += src/plugins/audioreverb.h \
src/recorder/creaperproject.h \
src/recorder/cwavestream.h \
src/signalhandler.h
+ # src/messagereceiver.h
!contains(CONFIG, "serveronly") {
HEADERS += src/client.h \
@@ -408,17 +259,12 @@ HEADERS += src/plugins/audioreverb.h \
src/testbench.h
}
-HEADERS_GUI = src/serverdlg.h
+#HEADERS_GUI = src/serverdlg.h
!contains(CONFIG, "serveronly") {
HEADERS_GUI += src/audiomixerboard.h \
- src/chatdlg.h \
- src/clientsettingsdlg.h \
- src/connectdlg.h \
- src/clientdlg.h \
src/levelmeter.h \
- src/analyzerconsole.h \
- src/multicolorled.h
+ # src/analyzerconsole.h \
}
HEADERS_OPUS = libs/opus/celt/arch.h \
@@ -492,9 +338,9 @@ HEADERS_OPUS_X86 = libs/opus/celt/x86/celt_lpc_sse.h \
libs/opus/celt/x86/x86cpu.h \
$$files(libs/opus/silk/x86/*.h)
-SOURCES += src/plugins/audioreverb.cpp \
- src/buffer.cpp \
+SOURCES += src/buffer.cpp \
src/channel.cpp \
+ src/chatbox.cpp \
src/main.cpp \
src/protocol.cpp \
src/recorder/jamcontroller.cpp \
@@ -508,23 +354,22 @@ SOURCES += src/plugins/audioreverb.cpp \
src/recorder/jamrecorder.cpp \
src/recorder/creaperproject.cpp \
src/recorder/cwavestream.cpp
+ # src/messagereceiver.cpp
!contains(CONFIG, "serveronly") {
SOURCES += src/client.cpp \
src/sound/soundbase.cpp \
}
-SOURCES_GUI = src/serverdlg.cpp
+#SOURCES_GUI = src/serverdlg.cpp
!contains(CONFIG, "serveronly") {
SOURCES_GUI += src/audiomixerboard.cpp \
- src/chatdlg.cpp \
- src/clientsettingsdlg.cpp \
- src/connectdlg.cpp \
- src/clientdlg.cpp \
- src/multicolorled.cpp \
+ # src/clientdlg.cpp \
+ # src/clientsettingsdlg.cpp \
+ # src/multicolorled.cpp \
src/levelmeter.cpp \
- src/analyzerconsole.cpp
+ # src/analyzerconsole.cpp
}
SOURCES_OPUS = libs/opus/celt/bands.c \
@@ -1173,11 +1018,6 @@ contains(CONFIG, "opus_shared_lib") {
}
}
-# disable version check if requested (#370)
-contains(CONFIG, "disable_version_check") {
- message(The version check is disabled.)
- DEFINES += DISABLE_VERSION_CHECK
-}
# Enable formatting all code via `make clang_format`.
# Note: When extending the list of file extensions or when adding new code directories,
diff --git a/src/AppWindow.qml b/src/AppWindow.qml
new file mode 100644
index 0000000000..07e943e0eb
--- /dev/null
+++ b/src/AppWindow.qml
@@ -0,0 +1,98 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+ApplicationWindow {
+ visible: true
+ minimumWidth: 600
+ minimumHeight: 490
+ title: qsTr("Jamulus")
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ // Tab Bar
+ TabBar {
+ id: tabBar
+ Layout.fillWidth: true
+
+ TabButton {
+ text: qsTr("Home")
+ checked: stackLayout.currentIndex === 0
+ onClicked: stackLayout.currentIndex = 0
+ }
+
+ TabButton {
+ text: qsTr("Settings")
+ checked: stackLayout.currentIndex === 1
+ onClicked: stackLayout.currentIndex = 1
+ }
+ }
+
+ // Stack Layout for Tab Content
+ StackLayout {
+ id: stackLayout
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ // Home Tab Content
+ Item {
+ id: homeTab
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ MainView {
+ anchors.fill: parent
+ }
+ }
+
+ // Settings Tab Content
+ Item {
+ id: settingsTab
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ SettingsView {
+ // anchors.fill: parent
+ }
+ }
+ }
+
+ Popup {
+ id: userPopup
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 300
+ height: 150
+ visible: _main.userMsg !== "" // Show the popup when there's a message
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
+
+ Rectangle {
+ anchors.fill: parent
+ color: "white"
+
+ Label {
+ id: userMessage
+ text: _main.userMsg // Display the message from _main
+ anchors.centerIn: parent
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ width: parent.width - 20 // Ensure some padding from the edges
+ }
+ }
+
+ onVisibleChanged: {
+ if (!visible) {
+ _main.userMsg = ""
+ }
+ }
+ }
+ }
+
+ // React to changes in _client.userMsg
+ function onUserMsgChanged(newMsg) {
+ if (newMsg !== "") {
+ userPopup.open()
+ }
+ }
+}
diff --git a/src/ChannelFader.qml b/src/ChannelFader.qml
new file mode 100644
index 0000000000..c19c9ca19a
--- /dev/null
+++ b/src/ChannelFader.qml
@@ -0,0 +1,169 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+Rectangle {
+ id: channelFader
+ border.width: 2
+ radius: 5
+ border.color: "#d9d9d9"
+
+ property var channelModel
+ // use ? and ?? operators to suppress errors when channelModel is null
+ property string channelUserName: channelModel?.channelUserName ?? "" // channelUserNameText.text
+ property double channelLevel: channelModel?.channelMeter.doubleVal ?? 0
+ property bool channelClipStatus: channelModel?.channelMeter.clipStatus ?? false
+ property double faderLevel: channelModel?.faderLevel ?? 0 // volumeFader.value
+ property double panLevel: channelModel?.panLevel ?? 0 // panKnob.value
+ property bool isMuted: channelModel?.isMuted ?? 0 // muteButton.checked
+ property bool isSolo: channelModel?.isSolo ?? 0 // soloButton.checked
+ property int groupID: channelModel?.groupID ?? 0 // groupId
+
+ ColumnLayout {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ anchors.centerIn: parent
+ spacing: 3
+
+ Text {
+ id: panKnobLabel
+ text: "PAN"
+ }
+
+ // Pan Knob
+ Dial {
+ id: panKnob
+ from: 0
+ to: 100
+ value: panLevel // default - set to AUD_MIX_PAN_MAX / 2
+ stepSize: 1
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: 32
+ Layout.preferredHeight: 32
+ Layout.bottomMargin: 4
+ background: Rectangle {
+ // color: "white"
+ border.width: 1
+ border.color: "#4e4e4e"
+ radius: width / 2
+ }
+
+ onMoved: {
+ channelModel.setPanLevel(value)
+ }
+ }
+
+ RowLayout {
+ spacing: 5
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredHeight: 200
+ Layout.preferredWidth: 15
+
+ // Level Meter
+ SingleLevelMeter {
+ id: levelMeterRectangleUser
+ heightPercentage: channelLevel
+ chanClipStatus: channelClipStatus
+ }
+
+ // Fader
+ Slider {
+ id: volumeFader
+ orientation: Qt.Vertical
+ from: 0.0
+ to: 100.0
+ value: faderLevel // FIXME - set to AUD_MIX_FADER_MAX
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredHeight: parent.height
+
+ onValueChanged: {
+ channelModel.setFaderLevel(value)
+ }
+ }
+ }
+
+ // GRPMTSOLO box
+ ColumnLayout {
+ Layout.alignment: Qt.AlignHCenter
+ spacing: 5
+
+ RowLayout {
+ spacing: 5
+ Layout.alignment: Qt.AlignHCenter
+
+ Button {
+ id: muteButton
+ checkable: true
+ text: "M"
+ Layout.preferredWidth: 30
+ Layout.preferredHeight: 30
+ font.bold: true
+ checked: isMuted
+ onClicked: {
+ channelModel.setIsMuted(!isMuted)
+ }
+ }
+
+ Button {
+ id: soloButton
+ checkable: true
+ text: "S"
+ Layout.preferredWidth: 30
+ Layout.preferredHeight: 30
+ font.bold: true
+ checked: isSolo
+ onClicked: {
+ channelModel.setIsSolo(!isSolo)
+ }
+ }
+ }
+
+ Button {
+ id: groupChooser
+ text: groupID > 0 ? groupID.toString() : "GRP"
+ Layout.preferredWidth: 50
+ Layout.preferredHeight: 25
+ Layout.alignment: Qt.AlignHCenter
+ font.bold: true
+ onClicked: menu.open()
+
+ Menu {
+ id: menu
+ y: groupChooser.height
+
+ Repeater {
+ model: 9 // Total number of items
+ delegate: MenuItem {
+ property int groupId: index
+ text: index === 0 ? "No group" : "Group " + index
+ onTriggered: channelModel.setGroupID(groupId)
+ }
+ }
+ }
+ }
+
+ }
+
+ // Username label
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 50
+ Layout.alignment: Qt.AlignHCenter
+ border.color: "#d9d9d9"
+ border.width: 1
+ radius: 3
+
+ Label {
+ id: channelUserNameText
+ anchors.fill: parent
+ text: channelUserName
+ font.bold: true
+ wrapMode: Text.WordWrap
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ }
+}
+
diff --git a/src/ChatBox.qml b/src/ChatBox.qml
new file mode 100644
index 0000000000..48346fe316
--- /dev/null
+++ b/src/ChatBox.qml
@@ -0,0 +1,75 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+Item {
+ id: chatBox
+ width: 400
+ height: 300
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 6
+
+ ScrollView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ TextArea {
+ id: chatArea
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ readOnly: true
+ wrapMode: TextEdit.Wrap
+ textFormat: TextEdit.RichText // Enable HTML rendering
+ text: _chatBox.chatHistory
+ font.pixelSize: 12
+
+ // Add padding for better text display
+ leftPadding: 10
+ rightPadding: 10
+ topPadding: 10
+ bottomPadding: 10
+
+ // Auto-scroll to bottom when new messages arrive
+ onTextChanged: {
+ cursorPosition = length
+ if (length > 0) {
+ // ensure cursor is visible
+ chatArea.flickableItem.contentY = chatArea.flickableItem.contentHeight - chatArea.flickableItem.height
+ }
+ }
+ }
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: 4
+
+ TextField {
+ id: chatInput
+ Layout.fillWidth: true
+ placeholderText: qsTr("Type a message…")
+ onAccepted: {
+ _chatBox.sendMessage(text)
+ text = ""
+ }
+ }
+
+ Button {
+ text: qsTr("Send")
+ onClicked: {
+ _chatBox.sendMessage(chatInput.text)
+ chatInput.text = ""
+ }
+ }
+ }
+
+ Button {
+ text: qsTr("Clear Chat")
+ onClicked: {
+ _chatBox.clearChat()
+ }
+ }
+ }
+}
diff --git a/src/MainView.qml b/src/MainView.qml
new file mode 100644
index 0000000000..e56d9a6170
--- /dev/null
+++ b/src/MainView.qml
@@ -0,0 +1,346 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import "."
+
+Rectangle {
+ anchors.fill: parent
+
+ RowLayout {
+ anchors.fill: parent
+ spacing: 0
+
+ // Left Control Panel
+ Rectangle {
+ Layout.preferredWidth: 150
+ radius: 10
+ border.color: "#d9d9d9"
+ Layout.fillHeight: true
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ Text {
+ text: "INPUT"
+ font.pixelSize: 14
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ // input meter section
+ Rectangle {
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredHeight: 200
+ Layout.preferredWidth: 20
+
+ StereoLevelMeter {
+ id: levelMeterRectangle
+ anchors.fill: parent
+ Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter
+ levelValueL: _main.inputMeterL.doubleVal
+ levelValueR: _main.inputMeterR.doubleVal
+ }
+ }
+
+ // mute / pan section
+ GridLayout {
+ Layout.alignment: Qt.AlignHCenter
+ columns: 2
+
+ Button {
+ text: "M"
+ Layout.preferredWidth: 40
+ Layout.preferredHeight: 40
+ Layout.alignment: Qt.AlignHCenter
+ font.bold: true
+ checkable: true
+ checked: _main.muteOut
+ onClicked: _main.muteOut = checked
+ }
+
+ Dial {
+ id: inPanDial
+ Layout.preferredWidth: 45
+ Layout.preferredHeight: 45
+ from: 0 // FIXME set from defines
+ to: 100
+ value: _main.audioInPan
+ onMoved: _main.audioInPan = value
+
+ //TODO: customise Dial something like this - need to set dimensions correctly
+ // background: Rectangle {
+ // x: inPanDial.width / 2 - width / 2
+ // y: inPanDial.height / 2 - height / 2
+ // implicitWidth: 140
+ // implicitHeight: 140
+ // width: Math.max(64, Math.min(inPanDial.width, inPanDial.height))
+ // height: width
+ // color: "transparent"
+ // radius: width / 2
+ // border.color: inPanDial.pressed ? "#17a81a" : "#21be2b"
+ // opacity: inPanDial.enabled ? 1 : 0.3
+ // }
+
+ // handle: Rectangle {
+ // id: handleItem
+ // x: inPanDial.background.x + inPanDial.background.width / 2 - width / 2
+ // y: inPanDial.background.y + inPanDial.background.height / 2 - height / 2
+ // width: 16
+ // height: 16
+ // color: inPanDial.pressed ? "#17a81a" : "#21be2b"
+ // radius: 8
+ // antialiasing: true
+ // opacity: inPanDial.enabled ? 1 : 0.3
+ // transform: [
+ // Translate {
+ // y: -Math.min(inPanDial.background.width, inPanDial.background.height) * 0.4 + handleItem.height / 2
+ // },
+ // Rotation {
+ // angle: inPanDial.angle
+ // origin.x: handleItem.width / 2
+ // origin.y: handleItem.height / 2
+ // }
+ // ]
+ // }
+
+ }
+
+ Text {
+ text: "mute"
+ font.pixelSize: 10
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ Text {
+ text: "pan"
+ font.pixelSize: 10
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ }
+
+ // Network Check Section
+ GridLayout {
+ Layout.alignment: Qt.AlignCenter
+ columns: 2
+ Layout.leftMargin: 5
+
+ Text {
+ text: "PING"
+ }
+ Rectangle {
+ Layout.preferredWidth: 40
+ Layout.preferredHeight: 15
+ color: "#000000"
+ Label {
+ anchors.centerIn: parent
+ text: _main.pingVal
+ color: { _main.pingVal < 40 ? "green" : "red" }
+ font.bold: true
+ }
+ }
+
+ Text {
+ text: "DELAY"
+ }
+ Rectangle {
+ Layout.preferredWidth: 40
+ Layout.preferredHeight: 15
+ color: "#000000"
+ Label {
+ anchors.centerIn: parent
+ color: _main.delayVal <= 43 ? "green" :
+ _main.delayVal <= 68 ? "yellow" :
+ "red"
+ text: _main.delayVal
+ font.bold: true
+ }
+ }
+
+ Text {
+ text: "JITTER"
+ }
+ Rectangle {
+ Layout.preferredWidth: 40
+ Layout.preferredHeight: 15
+ color: "#000000"
+ Rectangle {
+ anchors.centerIn: parent
+ visible: _main.jitterWarn
+ width: 20
+ height: 8
+ radius: 2
+ color: _main.jitterWarn ? "red" : "#000000"
+ }
+ }
+ }
+
+ GridLayout {
+ id: sessionLinkInputBox
+ Layout.alignment: Qt.AlignHCenter
+ columns: 1
+
+ TextField {
+ id: sessionlinkText
+ Layout.preferredWidth: 110
+ text: _main.sessionlinkText
+ onTextChanged: _main.sessionlinkText = text;
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ Button {
+ id: connectButton
+ text: "Connect"
+ Layout.preferredWidth: 80
+ Layout.preferredHeight: 30
+ Layout.alignment: Qt.AlignHCenter
+ font.bold: true
+ onClicked: _main.onConnectButtonClicked()
+ visible: !_main.bConnected
+ }
+
+ Button {
+ id: disconnectButton
+ text: "Disconnect"
+ Layout.preferredWidth: 80
+ Layout.preferredHeight: 30
+ Layout.alignment: Qt.AlignHCenter
+ font.bold: true
+ onClicked: _main.onDisconnectButtonClicked()
+ visible: _main.bConnected
+ }
+ }
+ }
+ }
+
+ // Main Area
+ Rectangle {
+ radius: 10
+ border.color: "#d9d9d9"
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 20
+
+ // Connect / control area
+ RowLayout {
+ Layout.preferredHeight: 80
+ spacing: 10
+
+ // Status area
+ Rectangle {
+ id: statusView
+ Layout.preferredHeight: 30
+ Layout.alignment: Qt.AlignLeft
+ Layout.leftMargin: 5
+ border.width: 1
+ border.color: "#d9d9d9"
+
+ GridLayout {
+ columns: 2
+
+ Text {
+ text: "Session Status: "
+ }
+ Text {
+ text: _main.sessionStatus
+ }
+
+ Text {
+ text: "Session Server: "
+ }
+ Text {
+ text: _main.sessionName
+ }
+
+ Text {
+ text: "Recording: "
+ }
+ Text {
+ text: _main.recordingStatus
+ }
+ }
+ }
+
+ }
+
+ Item {
+ // spacer item
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Rectangle {
+ anchors.fill: parent;
+ color: "white"
+ } // to visualize the spacer
+ }
+
+ // Mixerboard area
+ Rectangle {
+ id: mixerboardView
+ Layout.fillWidth: true
+ Layout.preferredHeight: 385
+ border.color: "#d9d9d9"
+ border.width: 2
+ Layout.alignment: Qt.AlignBottom
+
+ ListView {
+ id: listView
+ anchors.fill: parent
+ orientation: ListView.Horizontal
+ spacing: 5
+ // snapMode: ListView.NoSnap
+ // boundsBehavior: Flickable.StopAtBounds
+
+ model: _audioMixerBoard.channels
+
+ delegate: ChannelFader {
+ id: channelFader
+ width: 85
+ height: listView.height
+ channelModel: modelData
+ }
+ }
+ }
+
+ }
+ }
+
+ // // Splitter for resizing
+ // SplitHandle {
+ // id: splitter
+ // Layout.fillHeight: true
+ // Layout.preferredWidth: 4
+ // // color: "#d9d9d9"
+ // }
+
+ // Chat Panel
+ Rectangle {
+ id: chatPanel
+ Layout.fillHeight: true
+ Layout.preferredWidth: 300
+ Layout.minimumWidth: 200
+ Layout.maximumWidth: parent.width * 0.4
+ visible: !btnShowChat.checked
+ radius: 10
+ border.color: "#d9d9d9"
+
+ ChatBox {
+ anchors.fill: parent
+ anchors.margins: 10
+ }
+ }
+
+ }
+
+ // Toggle button
+ Button {
+ id: btnShowChat
+ text: checked ? qsTr("Show Chat") : qsTr("Hide Chat")
+ anchors.top: parent.top
+ anchors.right: parent.right
+ checkable: true
+ checked: false
+ onCheckedChanged: chatPanel.visible = !checked
+ }
+}
diff --git a/src/SettingsView.qml b/src/SettingsView.qml
new file mode 100644
index 0000000000..307c8d7ed4
--- /dev/null
+++ b/src/SettingsView.qml
@@ -0,0 +1,290 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+Item {
+ id: root
+ anchors.fill: parent
+
+ ScrollView {
+ anchors.fill: parent
+
+ ColumnLayout {
+ id: mainColumn
+ anchors.fill: parent
+ spacing: 10
+
+ // 1)
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 150
+ border.color: "black"
+ border.width: 2
+ radius: 10
+
+ // Stack items vertically inside
+ ColumnLayout {
+ id: profileColumn
+ anchors.centerIn: parent
+ anchors.margins: 10
+ spacing: 10
+
+ Text {
+ text: "GENERAL"
+ Layout.alignment: Qt.AlignHCenter
+ font.bold: true
+ }
+
+ GridLayout {
+ columns: 2
+ rowSpacing: 6
+ columnSpacing: 10
+
+ Text { text: "Username" }
+ TextField {
+ id: inputField
+ width: 200
+ placeholderText: "Enter alias here"
+ text: _settings.pedtAlias
+ onTextChanged: _settings.pedtAlias = text
+ }
+
+ Text { text: "Mixer Rows count" }
+ SpinBox {
+ id: spnMixerRows
+ value: _settings.spnMixerRows
+ onValueChanged: _settings.spnMixerRows = value
+ }
+ }
+ }
+ }
+
+ // 2)
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 400
+ border.color: "black"
+ border.width: 2
+ radius: 10
+
+ ColumnLayout {
+ anchors.centerIn: parent
+ anchors.margins: 10
+ spacing: 10
+
+ Text {
+ text: "AUDIO"
+ Layout.alignment: Qt.AlignHCenter
+ font.bold: true
+ }
+
+ GridLayout {
+ columns: 2
+ rowSpacing: 6
+ columnSpacing: 10
+
+ Text { text: "Audio Device" }
+ ComboBox {
+ id: cbxSoundcard
+ model: _settings.slSndCrdDevNames
+ Component.onCompleted: {
+ let idx = _settings.slSndCrdDevNames.indexOf(_settings.slSndCrdDev)
+ if (idx !== -1) currentIndex = idx
+ }
+ onCurrentIndexChanged: {
+ if (currentIndex >= 0 && currentIndex < _settings.slSndCrdDevNames.length) {
+ _settings.slSndCrdDev = _settings.slSndCrdDevNames[currentIndex]
+ }
+ }
+ }
+ Connections {
+ target: _settings
+ function onSlSndCrdDevChanged() {
+ let newIdx = _settings.slSndCrdDevNames.indexOf(_settings.slSndCrdDev)
+ if (newIdx !== -1 && newIdx !== cbxSoundcard.currentIndex) {
+ cbxSoundcard.currentIndex = newIdx
+ }
+ }
+ }
+
+ // Channel Mappings
+ Text { text: "Input channel - LEFT" }
+ ComboBox {
+ id: cbxLInChan
+ model: _settings.sndCrdInputChannelNames
+ displayText: _settings.sndCardLInChannel
+ onCurrentTextChanged: _settings.sndCardLInChannel = currentText
+ }
+
+ Text { text: "Input channel - RIGHT" }
+ ComboBox {
+ id: cbxRInChan
+ model: _settings.sndCrdInputChannelNames
+ displayText: _settings.sndCardRInChannel
+ onCurrentTextChanged: _settings.sndCardRInChannel = currentText
+ }
+
+ Text { text: "Output channel - LEFT" }
+ ComboBox {
+ id: cbxLOutChan
+ model: _settings.sndCrdOutputChannelNames
+ displayText: _settings.sndCardLOutChannel
+ onCurrentTextChanged: _settings.sndCardLOutChannel = currentText
+ }
+
+ Text { text: "Output channel - RIGHT" }
+ ComboBox {
+ id: cbxROutChan
+ model: _settings.sndCrdOutputChannelNames
+ displayText: _settings.sndCardROutChannel
+ onCurrentTextChanged: _settings.sndCardRoutChannel = currentText
+ }
+
+ Text { text: "Mono/Stereo mode" }
+ ComboBox {
+ id: cbxAudioChannels
+ model: ListModel {
+ ListElement { text: "Mono" }
+ ListElement { text: "Mono-in/Stereo-out" }
+ ListElement { text: "Stereo" }
+ }
+ currentIndex: _settings.cbxAudioChannels
+ onCurrentIndexChanged: _settings.cbxAudioChannels = currentIndex
+ }
+
+ Text { text: "Audio quality" }
+ ComboBox {
+ id: cbxAudioQuality
+ model: ListModel {
+ ListElement { text: "Low" }
+ ListElement { text: "Normal" }
+ ListElement { text: "High" }
+ }
+ currentIndex: _settings.cbxAudioQuality
+ onActivated: _settings.cbxAudioQuality = currentIndex
+ }
+
+ Text { text: "New client level: " + _settings.edtNewClientLevel }
+ Slider {
+ id: newInputLevelDial
+ from: 0
+ to: 100
+ value: _settings.edtNewClientLevel
+ onMoved: _settings.edtNewClientLevel = value
+ }
+
+ Text { text: "Feedback Detection" }
+ CheckBox {
+ id: chbDetectFeedback
+ checked: _settings.chbDetectFeedback
+ }
+
+ Text { text: "Buffer Size: " + _settings.bufSize }
+ ColumnLayout {
+ spacing: 4
+ ButtonGroup {
+ id: bufferDelayGroup
+ exclusive: true
+ buttons: [
+ rbtBufferDelayPreferred,
+ rbtBufferDelayDefault,
+ rbtBufferDelaySafe
+ ]
+ }
+ RadioButton {
+ id: rbtBufferDelayPreferred
+ text: _settings.sndCrdBufferDelayPreferred
+ enabled: _settings.fraSiFactPrefSupported
+ checked: _settings.rbtBufferDelayPreferred
+ onClicked: _settings.rbtBufferDelayPreferred = true
+ }
+ RadioButton {
+ id: rbtBufferDelayDefault
+ text: _settings.sndCrdBufferDelayDefault
+ enabled: _settings.fraSiFactDefSupported
+ checked: _settings.rbtBufferDelayDefault
+ onClicked: _settings.rbtBufferDelayDefault = true
+ }
+ RadioButton {
+ id: rbtBufferDelaySafe
+ text: _settings.sndCrdBufferDelaySafe
+ enabled: _settings.fraSiFactSafeSupported
+ checked: _settings.rbtBufferDelaySafe
+ onClicked: _settings.rbtBufferDelaySafe = true
+ }
+ }
+ }
+ }
+
+
+ }
+
+ // 3)
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 200
+ border.color: "black"
+ border.width: 2
+ radius: 10
+
+ ColumnLayout {
+ anchors.centerIn: parent
+ anchors.margins: 10
+ spacing: 10
+
+ Text {
+ text: "NETWORK"
+ Layout.alignment: Qt.AlignHCenter
+ font.bold: true
+ }
+
+ GridLayout {
+ columns: 2
+ rowSpacing: 6
+ columnSpacing: 10
+
+ Text { text: "Jitter Buffer" }
+ CheckBox {
+ id: chbAutoJitBuf
+ checked: _settings.chbAutoJitBuf
+ onCheckedChanged: _settings.chbAutoJitBuf = checked
+ text: "Auto"
+ }
+
+ Text { text: "Client buffer: " + _settings.sldNetBuf }
+ Slider {
+ id: sldNetBuf
+ from: _settings.sldNetBufMin
+ to: _settings.sldNetBufMax
+ value: _settings.sldNetBuf
+ onMoved: _settings.sldNetBuf = value
+ enabled: !chbAutoJitBuf.checked
+ }
+
+ Text { text: "Server Buffer: " + _settings.sldNetBufServer }
+ Slider {
+ id: sldNetBufServer
+ from: _settings.sldNetBufMin
+ to: _settings.sldNetBufMax
+ value: _settings.sldNetBufServer
+ onMoved: _settings.sldNetBufServer = value
+ enabled: !chbAutoJitBuf.checked
+ }
+
+ Text { text: "Small network buffers" }
+ CheckBox {
+ id: chbEnableOPUS64
+ checked: _settings.chbEnableOPUS64
+ onCheckStateChanged: _settings.chbEnableOPUS64 = checkState
+ }
+
+ Text { text: "Upload rate:" }
+ Text {
+ text: _main.bConnected ? (_settings.uploadRate + " kbps") : "--"
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/SingleLevelMeter.qml b/src/SingleLevelMeter.qml
new file mode 100644
index 0000000000..cedaa08bd7
--- /dev/null
+++ b/src/SingleLevelMeter.qml
@@ -0,0 +1,34 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+Item {
+ id: singleLevelMeter
+ width: 10 // Set default width
+ height: 200 // Set default height
+
+ property real heightPercentage: 0
+ property bool chanClipStatus: false
+
+ Rectangle {
+ id: backgroundBar
+ anchors.fill: parent
+ color: "black"
+ radius: 2
+ }
+
+ Rectangle {
+ id: levelBar
+ width: parent.width
+ height: parent.height * Math.min(heightPercentage, 1)
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ radius: 1
+ // When chanClipStatus is true, show a thick red border
+ border.color: chanClipStatus ? "red" : "transparent"
+ border.width: chanClipStatus ? 4 : 0
+ color: heightPercentage > 0.95 ? "#FF260A" :
+ heightPercentage > 0.85 ? "#FF8C0A" :
+ "#3AF864"
+ }
+}
diff --git a/src/SplitHandle.qml b/src/SplitHandle.qml
new file mode 100644
index 0000000000..7d43419c91
--- /dev/null
+++ b/src/SplitHandle.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.15
+
+Rectangle {
+ id: handle
+ property int minimumX: 200
+ property int maximumX: parent.width - 200
+
+ MouseArea {
+ anchors.fill: parent
+ anchors.margins: -5
+ cursorShape: Qt.SplitHCursor
+ drag {
+ target: parent
+ axis: Drag.XAxis
+ minimumX: handle.minimumX
+ maximumX: handle.maximumX
+ }
+ }
+}
diff --git a/src/StereoLevelMeter.qml b/src/StereoLevelMeter.qml
new file mode 100644
index 0000000000..b7ea2d2175
--- /dev/null
+++ b/src/StereoLevelMeter.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import "." // Ensure SingleLevelMeter.qml is in the import path
+
+Rectangle {
+ id: levelContainer
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ color: "black"
+ radius: 2
+
+ property real levelValueL: 0
+ property real levelValueR: 0
+
+ RowLayout {
+ id: levelBarsLayout
+ anchors.fill: parent
+ spacing: 0
+
+ SingleLevelMeter {
+ id: levelBarL
+ heightPercentage: levelValueL
+ }
+
+ SingleLevelMeter {
+ id: levelBarR
+ heightPercentage: levelValueR
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/aboutdlgbase.ui b/src/aboutdlgbase.ui
deleted file mode 100644
index 229ef78e62..0000000000
--- a/src/aboutdlgbase.ui
+++ /dev/null
@@ -1,236 +0,0 @@
-
-
- CAboutDlgBase
-
-
-
- 0
- 0
- 630
- 465
-
-
-
-
- 0
- 0
-
-
-
- About
-
-
-
- :/png/main/res/fronticon.png:/png/main/res/fronticon.png
-
-
- true
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- :/png/main/res/fronticon.png
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- 0
-
-
-
-
-
- TextLabelVersion
-
-
- false
-
-
- 2
-
-
-
- -
-
-
- Copyright © 2005-2024 The Jamulus Development Team
-
-
- false
-
-
- 2
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
- 0
-
-
-
- A&bout
-
-
-
-
-
-
- true
-
-
-
-
-
-
-
- &Libraries
-
-
- -
-
-
- true
-
-
-
-
-
-
-
- &Contributors
-
-
- -
-
-
- true
-
-
-
-
-
-
-
- &Translation
-
-
- -
-
-
- true
-
-
-
-
-
-
-
- -
-
-
- 6
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Expanding
-
-
-
- 20
- 20
-
-
-
-
- -
-
-
- &OK
-
-
- true
-
-
- true
-
-
-
-
-
-
-
-
- buttonOk
-
-
-
-
-
-
- buttonOk
- clicked()
- CAboutDlgBase
- accept()
-
-
- 20
- 20
-
-
- 20
- 20
-
-
-
-
-
diff --git a/src/audiomixerboard.cpp b/src/audiomixerboard.cpp
index db6cab14e4..afb4826044 100644
--- a/src/audiomixerboard.cpp
+++ b/src/audiomixerboard.cpp
@@ -25,388 +25,156 @@
#include "audiomixerboard.h"
/******************************************************************************\
-* CChanneFader *
+* CChannelFader *
\******************************************************************************/
-CChannelFader::CChannelFader ( QWidget* pNW ) :
- eDesign ( GD_STANDARD ),
- BitmapMutedIcon ( QString::fromUtf8 ( ":/png/fader/res/mutediconorange.png" ) ),
+CChannelFader::CChannelFader ( QObject* parent ) :
+ QObject(parent),
+ m_faderLevel(AUD_MIX_FADER_MAX),
+ m_panLevel(AUD_MIX_PAN_MAX / 2),
+ m_isMuted(false),
+ m_isSolo(false),
bMIDICtrlUsed ( false )
{
- // create new GUI control objects and store pointers to them (note that
- // QWidget takes the ownership of the pMainGrid so that this only has
- // to be created locally in this constructor)
- pFrame = new QFrame ( pNW );
-
- pLevelsBox = new QWidget ( pFrame );
- plbrChannelLevel = new CLevelMeter ( pLevelsBox );
- pFader = new QSlider ( Qt::Vertical, pLevelsBox );
- pPan = new QDial ( pLevelsBox );
- pPanLabel = new QLabel ( tr ( "Pan" ), pLevelsBox );
- pInfoLabel = new QLabel ( "", pLevelsBox );
-
- pMuteSoloBox = new QWidget ( pFrame );
- pcbMute = new QCheckBox ( tr ( "Mute" ), pMuteSoloBox );
- pcbSolo = new QCheckBox ( tr ( "Solo" ), pMuteSoloBox );
- pcbGroup = new QCheckBox ( "", pMuteSoloBox );
-
- pLabelInstBox = new QGroupBox ( pFrame );
- plblLabel = new QLabel ( "", pFrame );
- plblInstrument = new QLabel ( pFrame );
- plblCountryFlag = new QLabel ( pFrame );
-
- QVBoxLayout* pMainGrid = new QVBoxLayout ( pFrame );
- QHBoxLayout* pLevelsGrid = new QHBoxLayout ( pLevelsBox );
- QVBoxLayout* pMuteSoloGrid = new QVBoxLayout ( pMuteSoloBox );
- pLabelGrid = new QHBoxLayout ( pLabelInstBox );
- pLabelPictGrid = new QVBoxLayout();
- QVBoxLayout* pPanGrid = new QVBoxLayout();
- QHBoxLayout* pPanInfoGrid = new QHBoxLayout();
-
- // define the popup menu for the group checkbox
- pGroupPopupMenu = new QMenu ( "", pcbGroup );
- pGroupPopupMenu->addAction ( tr ( "&No grouping" ), this, [=] { OnGroupMenuGrp ( INVALID_INDEX ); } );
- for ( int iGrp = 0; iGrp < MAX_NUM_FADER_GROUPS; iGrp++ )
- {
- pGroupPopupMenu->addAction ( tr ( "Assign to group" ) + ( QString ( " &%1" ).arg ( iGrp + 1 ) ), this, [=] { OnGroupMenuGrp ( iGrp ); } );
- }
-#if ( MAX_NUM_FADER_GROUPS != 8 )
-# error "MAX_NUM_FADER_GROUPS must be set to 8, see implementation in CChannelFader()"
-#endif
-
- // setup channel level
- plbrChannelLevel->setContentsMargins ( 0, 3, 2, 3 );
-
- // setup slider
- pFader->setPageStep ( 1 );
- pFader->setRange ( 0, AUD_MIX_FADER_MAX );
- pFader->setTickInterval ( AUD_MIX_FADER_MAX / 9 );
-
- // setup panning control and info label
- pPan->setRange ( 0, AUD_MIX_PAN_MAX );
- pPan->setValue ( AUD_MIX_PAN_MAX / 2 );
- pPan->setNotchesVisible ( true );
- pInfoLabel->setMinimumHeight ( 14 ); // prevents jitter when muting/unmuting (#811)
- pInfoLabel->setAlignment ( Qt::AlignTop );
- pPanInfoGrid->addWidget ( pPanLabel, 0, Qt::AlignLeft | Qt::AlignTop );
- pPanInfoGrid->addWidget ( pInfoLabel, 0, Qt::AlignHCenter | Qt::AlignTop );
- pPanGrid->addLayout ( pPanInfoGrid );
- pPanGrid->addWidget ( pPan, 0, Qt::AlignHCenter );
-
- // setup fader tag label (black bold text which is centered)
- plblLabel->setTextFormat ( Qt::PlainText );
- plblLabel->setAlignment ( Qt::AlignHCenter | Qt::AlignVCenter );
-
- // set margins of the layouts to zero to get maximum space for the controls
- pMainGrid->setContentsMargins ( 0, 0, 0, 0 );
-
- pPanGrid->setContentsMargins ( 0, 0, 0, 0 );
- pPanGrid->setSpacing ( 0 ); // only minimal space
-
- pLevelsGrid->setContentsMargins ( 0, 0, 0, 0 );
- pLevelsGrid->setSpacing ( 0 ); // only minimal space
-
- pMuteSoloGrid->setContentsMargins ( 0, 0, 0, 0 );
- pMuteSoloGrid->setSpacing ( 0 ); // only minimal space
-
- pLabelGrid->setContentsMargins ( 0, 0, 0, 0 );
- pLabelGrid->setSpacing ( 2 ); // only minimal space between picture and text
-
- // add user controls to the grids
- pLabelPictGrid->addWidget ( plblCountryFlag, 0, Qt::AlignHCenter );
- pLabelPictGrid->addWidget ( plblInstrument, 0, Qt::AlignHCenter );
-
- pLabelGrid->addLayout ( pLabelPictGrid );
- pLabelGrid->addWidget ( plblLabel, 0, Qt::AlignVCenter ); // note: just initial add, may be changed later
-
- pLevelsGrid->addWidget ( plbrChannelLevel, 0, Qt::AlignRight );
- pLevelsGrid->addWidget ( pFader, 0, Qt::AlignLeft );
-
- pMuteSoloGrid->addWidget ( pcbGroup, 0, Qt::AlignLeft );
- pMuteSoloGrid->addWidget ( pcbMute, 0, Qt::AlignLeft );
- pMuteSoloGrid->addWidget ( pcbSolo, 0, Qt::AlignLeft );
-
- pMainGrid->addLayout ( pPanGrid );
- pMainGrid->addWidget ( pLevelsBox, 0, Qt::AlignHCenter );
- pMainGrid->addWidget ( pMuteSoloBox, 0, Qt::AlignHCenter );
- pMainGrid->addWidget ( pLabelInstBox );
-
- // reset current fader
- strGroupBaseText = "Grp"; // this will most probably overwritten by SetGUIDesign()
- iInstrPicMaxWidth = INVALID_INDEX; // this will most probably overwritten by SetGUIDesign()
- Reset();
+ // create levelmeter for this channelstrip
+ m_channelMeter = new CLevelMeter ( this );
- // add help text to controls
- plbrChannelLevel->setWhatsThis ( "" + tr ( "Channel Level" ) + ": " +
- tr ( "Displays the pre-fader audio level of this channel. All clients connected to the "
- "server will be assigned an audio level, the same value for every client." ) );
- plbrChannelLevel->setAccessibleName ( tr ( "Input level of the current audio "
- "channel at the server" ) );
-
- pFader->setWhatsThis ( "" + tr ( "Mixer Fader" ) + ": " +
- tr ( "Adjusts the audio level of this channel. All clients connected to the server "
- "will be assigned an audio fader, displayed at each client, to adjust the local mix." ) );
- pFader->setAccessibleName ( tr ( "Local mix level setting of the current audio "
- "channel at the server" ) );
-
- pInfoLabel->setWhatsThis ( "" + tr ( "Status Indicator" ) + ": " +
- tr ( "Shows a status indication about the client which is assigned to this channel. "
- "Supported indicators are:" ) +
- "
- " + tr ( "Speaker with cancellation stroke: Indicates that another client has muted you." ) + "
" );
- pInfoLabel->setAccessibleName ( tr ( "Status indicator label" ) );
-
- pPan->setWhatsThis ( "" + tr ( "Panning" ) + ": " +
- tr ( "Sets the pan from Left to Right of the channel. "
- "Works only in stereo or preferably mono in/stereo out mode." ) );
- pPan->setAccessibleName ( tr ( "Local panning position of the current audio channel at the server" ) );
-
- pcbMute->setWhatsThis ( "" + tr ( "Mute" ) + ": " + tr ( "With the Mute checkbox, the audio channel can be muted." ) );
- pcbMute->setAccessibleName ( tr ( "Mute button" ) );
-
- pcbSolo->setWhatsThis ( "" + tr ( "Solo" ) + ": " +
- tr ( "With the Solo checkbox, the "
- "audio channel can be set to solo which means that all other channels "
- "except the soloed channel are muted. It is possible to set more than "
- "one channel to solo." ) );
- pcbSolo->setAccessibleName ( tr ( "Solo button" ) );
-
- pcbGroup->setWhatsThis ( "" + tr ( "Group" ) + ": " +
- tr ( "With the Grp checkbox, a "
- "group of audio channels can be defined. All channel faders in a group are moved "
- "in proportional synchronization if any one of the group faders are moved." ) );
- pcbGroup->setAccessibleName ( tr ( "Group button" ) );
-
- QString strFaderText = "" + tr ( "Fader Tag" ) + ": " +
- tr ( "The fader tag "
- "identifies the connected client. The tag name, a picture of your "
- "instrument and the flag of your location can be set in the main window." );
-
- plblInstrument->setWhatsThis ( strFaderText );
- plblInstrument->setAccessibleName ( tr ( "Mixer channel instrument picture" ) );
- plblLabel->setWhatsThis ( strFaderText );
- plblLabel->setAccessibleName ( tr ( "Mixer channel label (fader tag)" ) );
- plblCountryFlag->setWhatsThis ( strFaderText );
- plblCountryFlag->setAccessibleName ( tr ( "Mixer channel country/region flag" ) );
-
- // Connections -------------------------------------------------------------
- QObject::connect ( pFader, &QSlider::valueChanged, this, &CChannelFader::OnLevelValueChanged );
-
- QObject::connect ( pPan, &QDial::valueChanged, this, &CChannelFader::OnPanValueChanged );
-
- QObject::connect ( pcbMute, &QCheckBox::stateChanged, this, &CChannelFader::OnMuteStateChanged );
-
- QObject::connect ( pcbSolo, &QCheckBox::stateChanged, this, &CChannelFader::soloStateChanged );
-
- QObject::connect ( pcbGroup, &QCheckBox::stateChanged, this, &CChannelFader::OnGroupStateChanged );
+ Reset();
}
-void CChannelFader::SetGUIDesign ( const EGUIDesign eNewDesign )
+QString CChannelFader::channelUserName() const
{
- eDesign = eNewDesign;
+ return this->cReceivedChanInfo.strName;
+}
- switch ( eNewDesign )
+void CChannelFader::setchannelUserName(const QString& name)
+{
+ if (this->cReceivedChanInfo.strName != name)
{
- case GD_ORIGINAL:
- pFader->setStyleSheet ( "QSlider { width: 45px;"
- " border-image: url(:/png/fader/res/faderbackground.png) repeat;"
- " border-top: 10px transparent;"
- " border-bottom: 10px transparent;"
- " border-left: 20px transparent;"
- " border-right: -25px transparent; }"
- "QSlider::groove { image: url(:/png/fader/res/transparent1x1.png);"
- " padding-left: -34px;"
- " padding-top: -10px;"
- " padding-bottom: -15px; }"
- "QSlider::handle { image: url(:/png/fader/res/faderhandle.png); }" );
-
- pLabelGrid->addWidget ( plblLabel, 0, Qt::AlignVCenter ); // label next to icons
- pLabelInstBox->setMinimumHeight ( 52 ); // maximum height of the instrument+flag pictures
- pPan->setFixedSize ( 50, 50 );
- pPanLabel->setText ( tr ( "PAN" ) );
- pcbMute->setText ( tr ( "MUTE" ) );
- pcbSolo->setText ( tr ( "SOLO" ) );
- strGroupBaseText = tr ( "GRP" );
- iInstrPicMaxWidth = INVALID_INDEX; // no instrument picture scaling
- break;
-
- case GD_SLIMFADER:
- pLabelPictGrid->addWidget ( plblLabel, 0, Qt::AlignHCenter ); // label below icons
- pLabelInstBox->setMinimumHeight ( 130 ); // maximum height of the instrument+flag+label
- pPan->setFixedSize ( 28, 28 );
- pFader->setTickPosition ( QSlider::NoTicks );
- pFader->setStyleSheet ( "" );
- pPanLabel->setText ( tr ( "Pan" ) );
- pcbMute->setText ( tr ( "M" ) );
- pcbSolo->setText ( tr ( "S" ) );
- strGroupBaseText = tr ( "G" );
- iInstrPicMaxWidth = 18; // scale instrument picture to avoid enlarging the width by the picture
- break;
-
- default:
- // reset style sheet and set original parameters
- pFader->setTickPosition ( QSlider::TicksBothSides );
- pFader->setStyleSheet ( "" );
- pLabelGrid->addWidget ( plblLabel, 0, Qt::AlignVCenter ); // label next to icons
- pLabelInstBox->setMinimumHeight ( 52 ); // maximum height of the instrument+flag pictures
- pPan->setFixedSize ( 50, 50 );
- pPanLabel->setText ( tr ( "Pan" ) );
- pcbMute->setText ( tr ( "Mute" ) );
- pcbSolo->setText ( tr ( "Solo" ) );
- strGroupBaseText = tr ( "Grp" );
- iInstrPicMaxWidth = INVALID_INDEX; // no instrument picture scaling
- break;
+ this->cReceivedChanInfo.strName = name;
+ emit channelUserNameChanged();
}
-
- // we need to update since we changed the checkbox text
- UpdateGroupIDDependencies();
-
- // the instrument picture might need scaling after a style change
- SetChannelInfos ( cReceivedChanInfo );
}
-void CChannelFader::SetMeterStyle ( const EMeterStyle eNewMeterStyle )
+double CChannelFader::faderLevel() const
{
- eMeterStyle = eNewMeterStyle;
+ return m_faderLevel;
+}
- switch ( eNewMeterStyle )
+void CChannelFader::setFaderLevel( const double dLevel )
+{
+ // user has moved fader slider
+ if (!qFuzzyCompare(m_faderLevel, dLevel))
{
- case MT_BAR_NARROW:
- plbrChannelLevel->SetLevelMeterType ( CLevelMeter::MT_BAR_NARROW );
- // Fader height controls the distribution of the LEDs, if the value is too small the fader might not be movable
- pFader->setMinimumHeight ( 85 );
- break;
-
- case MT_BAR_WIDE:
- plbrChannelLevel->SetLevelMeterType ( CLevelMeter::MT_BAR_WIDE );
- // Fader height controls the distribution of the LEDs, if the value is too small the fader might not be movable
- pFader->setMinimumHeight ( 120 );
- break;
-
- case MT_LED_ROUND_SMALL:
- plbrChannelLevel->SetLevelMeterType ( CLevelMeter::MT_LED_ROUND_SMALL );
- // Fader height controls the distribution of the LEDs, if the value is too small the fader might not be movable
- pFader->setMinimumHeight ( 85 );
- break;
-
- case MT_LED_ROUND_BIG:
- plbrChannelLevel->SetLevelMeterType ( CLevelMeter::MT_LED_ROUND_BIG );
- // Fader height controls the distribution of the LEDs, if the value is too small the fader might not be movable
- pFader->setMinimumHeight ( 162 );
- break;
-
- default:
- // reset style sheet and set original parameters
- plbrChannelLevel->SetLevelMeterType ( CLevelMeter::MT_LED_STRIPE );
- // Fader height controls the distribution of the LEDs, if the value is too small the fader might not be movable
- pFader->setMinimumHeight ( 120 );
- break;
+ m_faderLevel = std::min ( AUD_MIX_FADER_MAX, MathUtils::round ( dLevel ) );
+ emit faderLevelChanged();
+ qDebug() << this->cReceivedChanInfo.strName << ": setFaderLevel: " << m_faderLevel;
}
+
+ SendFaderLevelToServer ( dLevel,
+ QGuiApplication::keyboardModifiers() ==
+ Qt::ShiftModifier ); /* isolate a channel from the group temporarily with shift-click-drag (#695) */
+
}
-void CChannelFader::SetDisplayChannelLevel ( const bool eNDCL ) { plbrChannelLevel->setHidden ( !eNDCL ); }
+void CChannelFader::setFaderLevelNoSend( const double dLevel )
+{
+ // slider is being auto-moved
+ if (!qFuzzyCompare(m_faderLevel, dLevel))
+ {
+ m_faderLevel = std::min ( AUD_MIX_FADER_MAX, MathUtils::round ( dLevel ) );
+ emit faderLevelChanged();
+ qDebug() << this->cReceivedChanInfo.strName << ": setFaderLevelNoSend: " << m_faderLevel ;
+ }
-bool CChannelFader::GetDisplayChannelLevel() { return !plbrChannelLevel->isHidden(); }
+}
-void CChannelFader::SetDisplayPans ( const bool eNDP )
+double CChannelFader::panLevel() const
{
- pPanLabel->setHidden ( !eNDP );
- pPan->setHidden ( !eNDP );
+ return m_panLevel;
}
-void CChannelFader::SetupFaderTag ( const ESkillLevel eSkillLevel )
+void CChannelFader::setPanLevel(double level)
{
- // Should never happen here
- if ( iGroupID >= MAX_NUM_FADER_GROUPS )
+ if (!qFuzzyCompare(m_panLevel, level))
{
- SetGroupID ( INVALID_INDEX );
+ m_panLevel = level;
+ emit panLevelChanged();
+ qDebug() << this->cReceivedChanInfo.strName << ": setPanLevel: changing level to : " << level;
+
+ SendPanValueToServer ( level );
}
+}
- // the group ID defines the border color and style
- QString strBorderColor = "black";
- QString strBorderStyle = "solid";
+bool CChannelFader::isMuted() const
+{
+ return m_isMuted;
+}
- if ( iGroupID != INVALID_INDEX )
+void CChannelFader::setIsMuted(bool muted)
+{
+ qDebug() << "setIsMuted for channel: " << this->cReceivedChanInfo.strName << ": " << muted;
+ if (m_isMuted != muted)
{
- switch ( iGroupID % 4 )
- {
- case 0:
- strBorderColor = "#C43AC5";
- break;
-
- case 1:
- strBorderColor = "#2B93D4";
- break;
+ m_isMuted = muted;
+ SetMute(muted);
+ emit isMutedChanged();
+ }
+}
- case 2:
- strBorderColor = "#3BC53A";
- break;
+bool CChannelFader::isSolo() const
+{
+ return m_isSolo;
+}
- case 3:
- strBorderColor = "#D46C2B";
- break;
+void CChannelFader::setIsSolo(bool solo)
+{
+ qDebug() << "setIsSolo for channel: " << this->cReceivedChanInfo.strName << ": " << solo;
+ if (m_isSolo != solo)
+ {
+ m_isSolo = solo;
+ emit isSoloChanged();
- default:
- break;
- }
+ emit soloStateChanged();
+ }
+}
- switch ( iGroupID / 4 )
- {
- case 0:
- strBorderStyle = "solid";
- break;
+int CChannelFader::groupID() const
+{
+ return this->iGroupID;
+}
- case 1:
- strBorderStyle = "dashed";
- break;
+void CChannelFader::setGroupID ( const int iNGroupID )
+{
+ iGroupID = iNGroupID;
- case 2:
- strBorderStyle = "dotted";
- break;
+ UpdateGroupIDDependencies();
- case 3:
- strBorderStyle = "double";
- break;
+ emit groupIDChanged();
+}
- default:
- break;
- }
- }
+bool CChannelFader::isRemoteMuted() const
+{
+ return m_isRemoteMuted;
+}
- // setup group box for label/instrument picture: set a thick black border
- // with nice round edges
- QString strStile = "QGroupBox { border: 2px " + strBorderStyle + " " + strBorderColor +
- ";"
- " border-radius: 4px;"
- " padding: 3px;";
+void CChannelFader::setIsRemoteMuted( const bool remoteMuted )
+{
+ if (isRemoteMuted() == remoteMuted)
+ return;
+ m_isRemoteMuted = remoteMuted;
+ emit isRemoteMutedChanged();
+}
- // the background color depends on the skill level
- switch ( eSkillLevel )
- {
- case SL_BEGINNER:
- strStile +=
- QString ( "background-color: rgb(%1, %2, %3); }" ).arg ( RGBCOL_R_SL_BEGINNER ).arg ( RGBCOL_G_SL_BEGINNER ).arg ( RGBCOL_B_SL_BEGINNER );
- break;
-
- case SL_INTERMEDIATE:
- strStile += QString ( "background-color: rgb(%1, %2, %3); }" )
- .arg ( RGBCOL_R_SL_INTERMEDIATE )
- .arg ( RGBCOL_G_SL_INTERMEDIATE )
- .arg ( RGBCOL_B_SL_INTERMEDIATE );
- break;
-
- case SL_PROFESSIONAL:
- strStile += QString ( "background-color: rgb(%1, %2, %3); }" )
- .arg ( RGBCOL_R_SL_SL_PROFESSIONAL )
- .arg ( RGBCOL_G_SL_SL_PROFESSIONAL )
- .arg ( RGBCOL_B_SL_SL_PROFESSIONAL );
- break;
-
- default:
- strStile +=
- QString ( "background-color: rgb(%1, %2, %3); }" ).arg ( RGBCOL_R_SL_NOT_SET ).arg ( RGBCOL_G_SL_NOT_SET ).arg ( RGBCOL_B_SL_NOT_SET );
- break;
- }
+int CChannelFader::channelID() const
+{
+ return this->cReceivedChanInfo.iChanID;
+}
- pLabelInstBox->setStyleSheet ( strStile );
+void CChannelFader::setChannelID(int id)
+{
+ if ( channelID() == id )
+ return;
+ this->cReceivedChanInfo.iChanID = id;
}
void CChannelFader::Reset()
@@ -418,31 +186,12 @@ void CChannelFader::Reset()
SetRemoteFaderIsMute ( false );
// init gain and pan value -> maximum value as definition according to server
- pFader->setValue ( AUD_MIX_FADER_MAX );
dPreviousFaderLevel = AUD_MIX_FADER_MAX;
- pPan->setValue ( AUD_MIX_PAN_MAX / 2 );
// reset mute/solo/group check boxes and level meter
- pcbMute->setChecked ( false );
- pcbSolo->setChecked ( false );
- plbrChannelLevel->SetValue ( 0 );
- plbrChannelLevel->ClipReset();
-
- // clear instrument picture, country flag, tool tips and label text
- plblLabel->setText ( "" );
- plblLabel->setToolTip ( "" );
- plblInstrument->setVisible ( false );
- plblInstrument->setToolTip ( "" );
- plblCountryFlag->setVisible ( false );
- plblCountryFlag->setToolTip ( "" );
- cReceivedChanInfo = CChannelInfo();
- SetupFaderTag ( SL_NOT_SET );
+ m_channelMeter->ClipReset();
- // set a defined tool tip time out
- const int iToolTipDurMs = 30000;
- plblLabel->setToolTipDuration ( iToolTipDurMs );
- plblInstrument->setToolTipDuration ( iToolTipDurMs );
- plblCountryFlag->setToolTipDuration ( iToolTipDurMs );
+ cReceivedChanInfo = CChannelInfo();
bOtherChannelIsSolo = false;
bIsMyOwnFader = false;
@@ -452,17 +201,24 @@ void CChannelFader::Reset()
UpdateGroupIDDependencies();
}
+void CChannelFader::SetPanValue ( const int iPan )
+{
+ // first make a range check
+ if ( ( iPan >= 0 ) && ( iPan <= AUD_MIX_PAN_MAX ) )
+ {
+ // set new pan level in GUI
+ setPanLevel( iPan );
+ }
+}
+
void CChannelFader::SetFaderLevel ( const double dLevel, const bool bIsGroupUpdate )
{
// first make a range check
if ( dLevel >= 0 )
{
// we set the new fader level in the GUI (slider control) and also tell the
- // server about the change (block the signal of the fader since we want to
- // call SendFaderLevelToServer with a special additional parameter)
- pFader->blockSignals ( true );
- pFader->setValue ( std::min ( AUD_MIX_FADER_MAX, MathUtils::round ( dLevel ) ) );
- pFader->blockSignals ( false );
+ // server about the change
+ setFaderLevelNoSend( dLevel );
SendFaderLevelToServer ( std::min ( static_cast ( AUD_MIX_FADER_MAX ), dLevel ), bIsGroupUpdate );
@@ -477,41 +233,19 @@ void CChannelFader::SetFaderLevel ( const double dLevel, const bool bIsGroupUpda
}
}
-void CChannelFader::SetPanValue ( const int iPan )
-{
- // first make a range check
- if ( ( iPan >= 0 ) && ( iPan <= AUD_MIX_PAN_MAX ) )
- {
- // we set the new fader level in the GUI (slider control) which then
- // emits to signal to tell the server about the change (implicitly)
- pPan->setValue ( iPan );
- pPan->setAccessibleName ( QString::number ( iPan ) );
- }
-}
-
void CChannelFader::SetFaderIsSolo ( const bool bIsSolo )
{
- // changing the state automatically emits the signal, too
- pcbSolo->setChecked ( bIsSolo );
+ setIsSolo( bIsSolo );
}
void CChannelFader::SetFaderIsMute ( const bool bIsMute )
{
- // changing the state automatically emits the signal, too
- pcbMute->setChecked ( bIsMute );
+ setIsMuted( bIsMute );
}
void CChannelFader::SetRemoteFaderIsMute ( const bool bIsMute )
{
- if ( bIsMute )
- {
- // show muted icon orange
- pInfoLabel->setPixmap ( BitmapMutedIcon );
- }
- else
- {
- pInfoLabel->setPixmap ( QPixmap() );
- }
+ setIsRemoteMuted( bIsMute );
}
void CChannelFader::SendFaderLevelToServer ( const double dLevel, const bool bIsGroupUpdate )
@@ -519,7 +253,7 @@ void CChannelFader::SendFaderLevelToServer ( const double dLevel, const bool bIs
// if mute flag is set or other channel is on solo, do not apply the new
// fader value to the server (exception: we are on solo, in that case we
// ignore the "other channel is on solo" flag)
- const bool bSuppressServerUpdate = !( ( pcbMute->checkState() == Qt::Unchecked ) && ( !bOtherChannelIsSolo || IsSolo() ) );
+ const bool bSuppressServerUpdate = !( ( m_isMuted == false ) && ( !bOtherChannelIsSolo || isSolo() ) );
// emit signal for new fader gain value
emit gainValueChanged ( MathUtils::CalcFaderGain ( static_cast ( dLevel ) ),
@@ -539,93 +273,27 @@ void CChannelFader::SendFaderLevelToServer ( const double dLevel, const bool bIs
void CChannelFader::SendPanValueToServer ( const int iPan ) { emit panValueChanged ( static_cast ( iPan ) / AUD_MIX_PAN_MAX ); }
-void CChannelFader::OnPanValueChanged ( int value )
-{
- // on shift-click the pan shall reset to 0 L/R (#707)
- if ( QGuiApplication::keyboardModifiers() == Qt::ShiftModifier )
- {
- // correct the value to the center position
- value = AUD_MIX_PAN_MAX / 2;
-
- // set the GUI control in the center position while deactivating
- // the signals to avoid an infinite loop
- pPan->blockSignals ( true );
- pPan->setValue ( value );
- pPan->blockSignals ( false );
- }
-
- pPan->setAccessibleName ( QString::number ( value ) );
- SendPanValueToServer ( value );
-}
-
-void CChannelFader::OnMuteStateChanged ( int value )
-{
- // call muting function
- SetMute ( static_cast ( value ) == Qt::Checked );
-}
-
-void CChannelFader::SetGroupID ( const int iNGroupID )
-{
- iGroupID = iNGroupID;
- UpdateGroupIDDependencies();
-}
-
void CChannelFader::UpdateGroupIDDependencies()
{
- // update the group checkbox according the current group ID setting
- pcbGroup->blockSignals ( true ); // make sure no signals are fired
- if ( iGroupID == INVALID_INDEX )
- {
- pcbGroup->setCheckState ( Qt::Unchecked );
- }
- else
- {
- pcbGroup->setCheckState ( Qt::Checked );
- }
- pcbGroup->blockSignals ( false );
-
- // update group checkbox text
- if ( iGroupID != INVALID_INDEX )
- {
- pcbGroup->setText ( strGroupBaseText + QString::number ( iGroupID + 1 ) );
- }
- else
- {
- pcbGroup->setText ( strGroupBaseText );
- }
-
// if the group is disable for this fader, reset the previous fader level
if ( iGroupID == INVALID_INDEX )
{
// for the special case that the fader is all the way down, use a small
// value instead
- if ( GetFaderLevel() > 0 )
+ if ( faderLevel() > 0 )
{
- dPreviousFaderLevel = GetFaderLevel();
+ dPreviousFaderLevel = faderLevel();
}
else
{
dPreviousFaderLevel = 1; // small value
}
}
-
- // the fader tag border color is set according to the selected group
- SetupFaderTag ( cReceivedChanInfo.eSkillLevel );
-}
-
-void CChannelFader::OnGroupStateChanged ( int )
-{
- // we want a popup menu shown if the user presses the group checkbox but
- // we want to make sure that the checkbox state represents the current group
- // setting and not the current click state since the user might not click
- // on the menu but at one other place and then the popup menu disappears but
- // the checkobx state would be on an invalid state
- UpdateGroupIDDependencies();
- pGroupPopupMenu->popup ( QCursor::pos() );
}
void CChannelFader::SetMute ( const bool bState )
{
+ qDebug() << "SetMute for channel: " << this->cReceivedChanInfo.strName << ": " << bState;
if ( bState )
{
if ( !bIsMutedAtServer )
@@ -637,11 +305,11 @@ void CChannelFader::SetMute ( const bool bState )
}
else
{
- // only unmute if we are not solot but an other channel is on solo
- if ( ( !bOtherChannelIsSolo || IsSolo() ) && bIsMutedAtServer )
+ // only unmute if we are solo OR another channel is NOT solo .... right ? // not solot but an other channel is on solo
+ if ( ( !bOtherChannelIsSolo || isSolo() ) && bIsMutedAtServer )
{
// mute was unchecked, get current fader value and apply
- emit gainValueChanged ( MathUtils::CalcFaderGain ( GetFaderLevel() ),
+ emit gainValueChanged ( MathUtils::CalcFaderGain ( faderLevel() ),
bIsMyOwnFader,
false,
false,
@@ -657,26 +325,24 @@ void CChannelFader::UpdateSoloState ( const bool bNewOtherSoloState )
bOtherChannelIsSolo = bNewOtherSoloState;
// mute overwrites solo -> if mute is active, do not change anything
- if ( !pcbMute->isChecked() )
+ if ( !m_isMuted )
{
// mute channel if we are not solo but another channel is solo
- SetMute ( bOtherChannelIsSolo && !IsSolo() );
+ SetMute ( bOtherChannelIsSolo && !isSolo() );
}
}
-void CChannelFader::SetChannelLevel ( const uint16_t iLevel ) { plbrChannelLevel->SetValue ( iLevel ); }
+void CChannelFader::SetChannelLevel ( const uint16_t iLevel )
+{
+ m_channelMeter->setDoubleVal ( iLevel );
+}
void CChannelFader::SetChannelInfos ( const CChannelInfo& cChanInfo )
{
// store received channel info
cReceivedChanInfo = cChanInfo;
- // init properties for the tool tip
- int iTTInstrument = CInstPictures::GetNotUsedInstrument();
- QLocale::Country eTTCountry = QLocale::AnyCountry;
-
// Label text --------------------------------------------------------------
-
QString strModText = cChanInfo.strName;
// show channel numbers if --ctrlmidich is used (#241, #95)
@@ -684,382 +350,143 @@ void CChannelFader::SetChannelInfos ( const CChannelInfo& cChanInfo )
{
strModText.prepend ( QString().setNum ( cChanInfo.iChanID ) + ":" );
}
-
- QTextBoundaryFinder tbfName ( QTextBoundaryFinder::Grapheme, cChanInfo.strName );
- int iBreakPos;
-
- // apply break position and font size depending on the selected design
- if ( eDesign == GD_SLIMFADER )
- {
- // in slim mode use a non-bold font (smaller width font)
- plblLabel->setStyleSheet ( "QLabel { color: black; }" );
-
- // break at every 4th character
- iBreakPos = 4;
- }
- else
- {
- // in normal mode use bold font
- plblLabel->setStyleSheet ( "QLabel { color: black; font: bold; }" );
-
- // break text at predefined position
- iBreakPos = MAX_LEN_FADER_TAG / 2;
- }
-
- int iInsPos = iBreakPos;
- int iCount = 0;
- int iLineNumber = 0;
- while ( tbfName.toNextBoundary() != -1 )
- {
- ++iCount;
- if ( iCount == iInsPos && tbfName.position() + iLineNumber < strModText.length() )
- {
- strModText.insert ( tbfName.position() + iLineNumber, QString ( "\n" ) );
- iLineNumber++;
- iInsPos += iBreakPos;
- }
- }
-
- plblLabel->setText ( strModText );
-
- // Instrument picture ------------------------------------------------------
- // get the resource reference string for this instrument
- const QString strCurResourceRef = CInstPictures::GetResourceReference ( cChanInfo.iInstrument );
-
- // first check if instrument picture is used or not and if it is valid
- if ( CInstPictures::IsNotUsedInstrument ( cChanInfo.iInstrument ) || strCurResourceRef.isEmpty() )
- {
- // disable instrument picture
- plblInstrument->setVisible ( false );
- }
- else
- {
- // set correct picture
- QPixmap pixInstr ( strCurResourceRef );
-
- if ( ( iInstrPicMaxWidth != INVALID_INDEX ) && ( pixInstr.width() > iInstrPicMaxWidth ) )
- {
- // scale instrument picture on request (scale to the width with correct aspect ratio)
- plblInstrument->setPixmap ( pixInstr.scaledToWidth ( iInstrPicMaxWidth, Qt::SmoothTransformation ) );
- }
- else
- {
- plblInstrument->setPixmap ( pixInstr );
- }
- iTTInstrument = cChanInfo.iInstrument;
-
- // enable instrument picture
- plblInstrument->setVisible ( true );
- }
-
- // Country flag icon -------------------------------------------------------
- if ( cChanInfo.eCountry != QLocale::AnyCountry )
- {
- // try to load the country flag icon
- QPixmap CountryFlagPixmap ( CLocale::GetCountryFlagIconsResourceReference ( cChanInfo.eCountry ) );
-
- // first check if resource reference was valid
- if ( CountryFlagPixmap.isNull() )
- {
- // disable country flag
- plblCountryFlag->setVisible ( false );
- }
- else
- {
- // set correct picture
- plblCountryFlag->setPixmap ( CountryFlagPixmap );
- eTTCountry = cChanInfo.eCountry;
-
- // enable country flag
- plblCountryFlag->setVisible ( true );
- }
- }
- else
- {
- // disable country flag
- plblCountryFlag->setVisible ( false );
- }
-
- // Skill level background color --------------------------------------------
- SetupFaderTag ( cChanInfo.eSkillLevel );
-
- // Tool tip ----------------------------------------------------------------
- // complete musician profile in the tool tip
- QString strToolTip = "";
- QString strAliasAccessible = "";
- QString strInstrumentAccessible = "";
- QString strLocationAccessible = "";
-
- // alias/name
- if ( !cChanInfo.strName.isEmpty() )
- {
- strToolTip += "" + tr ( "Alias/Name" ) + "
" + cChanInfo.strName;
- strAliasAccessible += cChanInfo.strName;
- }
-
- // instrument
- if ( !CInstPictures::IsNotUsedInstrument ( iTTInstrument ) )
- {
- strToolTip += "" + tr ( "Instrument" ) + "
" + CInstPictures::GetName ( iTTInstrument );
-
- strInstrumentAccessible += CInstPictures::GetName ( iTTInstrument );
- }
-
- // location
- if ( ( eTTCountry != QLocale::AnyCountry ) || ( !cChanInfo.strCity.isEmpty() ) )
- {
- strToolTip += "" + tr ( "Location" ) + "
";
-
- if ( !cChanInfo.strCity.isEmpty() )
- {
- strToolTip += cChanInfo.strCity;
- strLocationAccessible += cChanInfo.strCity;
-
- if ( eTTCountry != QLocale::AnyCountry )
- {
- strToolTip += ", ";
- strLocationAccessible += ", ";
- }
- }
-
- if ( eTTCountry != QLocale::AnyCountry )
- {
- strToolTip += QLocale::countryToString ( eTTCountry );
- strLocationAccessible += QLocale::countryToString ( eTTCountry );
- }
- }
-
- // skill level
- QString strSkillLevel;
-
- switch ( cChanInfo.eSkillLevel )
- {
- case SL_BEGINNER:
- strSkillLevel = tr ( "Beginner" );
- strToolTip += "" + tr ( "Skill Level" ) + "
" + strSkillLevel;
- strInstrumentAccessible += ", " + strSkillLevel;
- break;
-
- case SL_INTERMEDIATE:
- strSkillLevel = tr ( "Intermediate" );
- strToolTip += "" + tr ( "Skill Level" ) + "
" + strSkillLevel;
- strInstrumentAccessible += ", " + strSkillLevel;
- break;
-
- case SL_PROFESSIONAL:
- strSkillLevel = tr ( "Expert" );
- strToolTip += "" + tr ( "Skill Level" ) + "
" + strSkillLevel;
- strInstrumentAccessible += ", " + strSkillLevel;
- break;
-
- case SL_NOT_SET:
- // skill level not set, do not add this entry
- break;
- }
-
- // if no information is given, leave the tool tip empty, otherwise add header
- if ( !strToolTip.isEmpty() )
- {
- strToolTip.prepend ( "" + tr ( "Musician Profile" ) + "
" );
- }
-
- plblCountryFlag->setToolTip ( strToolTip );
- plblCountryFlag->setAccessibleDescription ( strLocationAccessible );
- plblInstrument->setToolTip ( strToolTip );
- plblInstrument->setAccessibleDescription ( strInstrumentAccessible );
- plblLabel->setToolTip ( strToolTip );
- plblLabel->setAccessibleName ( strAliasAccessible );
- plblLabel->setAccessibleDescription ( tr ( "Alias" ) );
- pcbMute->setAccessibleName ( "Mute " + strAliasAccessible + ", " + strInstrumentAccessible );
- pcbSolo->setAccessibleName ( "Solo " + strAliasAccessible + ", " + strInstrumentAccessible );
- pcbGroup->setAccessibleName ( "Group " + strAliasAccessible + ", " + strInstrumentAccessible );
- dynamic_cast ( plblLabel->parent() )
- ->setAccessibleName ( strAliasAccessible + ", " + strInstrumentAccessible + ", " + strLocationAccessible );
}
+
/******************************************************************************\
* CAudioMixerBoard *
\******************************************************************************/
-CAudioMixerBoard::CAudioMixerBoard ( QWidget* parent ) :
- QGroupBox ( parent ),
- pSettings ( nullptr ),
+CAudioMixerBoard::CAudioMixerBoard ( CClientSettings* pSet, QObject* parent ) :
+ pSettings ( pSet ),
bDisplayPans ( false ),
- bIsPanSupported ( false ),
- bNoFaderVisible ( true ),
+ bIsPanSupported ( true ),
iMyChannelID ( INVALID_INDEX ),
iRunningNewClientCnt ( 0 ),
iNumMixerPanelRows ( 1 ), // pSettings->iNumMixerPanelRows is not yet available
- strServerName ( "" ),
eRecorderState ( RS_UNDEFINED ),
eChSortType ( ST_NO_SORT )
{
- // add group box and hboxlayout
- QHBoxLayout* pGroupBoxLayout = new QHBoxLayout ( this );
- QWidget* pMixerWidget = new QWidget(); // will be added to the scroll area which is then the parent
- pScrollArea = new CMixerBoardScrollArea ( this );
- pMainLayout = new QGridLayout ( pMixerWidget );
-
- setAccessibleName ( "Personal Mix at the Server groupbox" );
- setWhatsThis ( "" + tr ( "Personal Mix at the Server" ) + ": " +
- tr ( "When connected to a server, the controls here allow you to set your "
- "local mix without affecting what others hear from you. The title shows "
- "the server name and, when known, whether it is actively recording." ) );
-
- // set title text (default: no server given)
- SetServerName ( "" );
-
- // create all mixer controls and make them invisible
- vecpChanFader.Init ( MAX_NUM_CHANNELS );
-
+ // we need to init this vector
vecAvgLevels.Init ( MAX_NUM_CHANNELS, 0.0f );
+}
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
+CAudioMixerBoard::~CAudioMixerBoard()
+{
+ for (CChannelFader* channelFader : vecpChanFader)
{
- vecpChanFader[i] = new CChannelFader ( this );
- vecpChanFader[i]->Hide();
+ delete channelFader;
}
+}
- // insert horizontal spacer (at position MAX_NUM_CHANNELS+1 which is index MAX_NUM_CHANNELS)
- pMainLayout->addItem ( new QSpacerItem ( 0, 0, QSizePolicy::Expanding ), 0, MAX_NUM_CHANNELS );
-
- // set margins of the layout to zero to get maximum space for the controls
- pGroupBoxLayout->setContentsMargins ( 0, 0, 0, 1 ); // note: to avoid problems at the bottom, use a small margin for that
+// Since we don't need append and clear functions, they can be set to nullptr
+QQmlListProperty CAudioMixerBoard::channels()
+{
+ return QQmlListProperty(
+ this,
+ static_cast(this),
+ &CAudioMixerBoard::channelCount,
+ &CAudioMixerBoard::channelAt
+ );
+}
- // add the group box to the scroll area
- pScrollArea->setMinimumWidth ( 200 ); // at least two faders shall be visible
- pScrollArea->setWidget ( pMixerWidget );
- pScrollArea->setWidgetResizable ( true ); // make sure it fills the entire scroll area
- pScrollArea->setFrameShape ( QFrame::NoFrame );
- pGroupBoxLayout->addWidget ( pScrollArea );
+void CAudioMixerBoard::appendChannel(QQmlListProperty* list, CChannelFader* channel)
+{
+ CAudioMixerBoard* mixerBoard = static_cast(list->data);
+ mixerBoard->vecpChanFader.pushback(channel);
+ emit mixerBoard->channelsChanged();
+}
- // Connections -------------------------------------------------------------
- connectFaderSignalsToMixerBoardSlots();
+qsizetype CAudioMixerBoard::channelCount(QQmlListProperty* list)
+{
+ CAudioMixerBoard* mixerBoard = static_cast(list->data);
+ return static_cast(mixerBoard->vecpChanFader.size());
}
-CAudioMixerBoard::~CAudioMixerBoard()
+CChannelFader* CAudioMixerBoard::channelAt(QQmlListProperty* list, qsizetype index)
{
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
+ CAudioMixerBoard* mixerBoard = static_cast(list->data);
+ if (index >= 0 && index < static_cast(mixerBoard->vecpChanFader.size()))
{
- delete vecpChanFader[i];
+ return mixerBoard->vecpChanFader.at(static_cast(index));
}
+ return nullptr;
}
-template
-inline void CAudioMixerBoard::connectFaderSignalsToMixerBoardSlots()
+void CAudioMixerBoard::clearChannels(QQmlListProperty* list)
{
- size_t iCurChanID = slotId - 1;
-
- void ( CAudioMixerBoard::*pGainValueChanged ) ( float, bool, bool, bool, double ) = &CAudioMixerBoardSlots::OnChGainValueChanged;
-
- void ( CAudioMixerBoard::*pPanValueChanged ) ( float ) = &CAudioMixerBoardSlots::OnChPanValueChanged;
-
- QObject::connect ( vecpChanFader[iCurChanID], &CChannelFader::soloStateChanged, this, &CAudioMixerBoard::UpdateSoloStates );
-
- QObject::connect ( vecpChanFader[iCurChanID], &CChannelFader::gainValueChanged, this, pGainValueChanged );
-
- QObject::connect ( vecpChanFader[iCurChanID], &CChannelFader::panValueChanged, this, pPanValueChanged );
-
- connectFaderSignalsToMixerBoardSlots();
+ CAudioMixerBoard* mixerBoard = static_cast(list->data);
+ mixerBoard->vecpChanFader.clear();
+ emit mixerBoard->channelsChanged();
}
-template<>
-inline void CAudioMixerBoard::connectFaderSignalsToMixerBoardSlots<0>()
-{}
-void CAudioMixerBoard::SetServerName ( const QString& strNewServerName )
+void CAudioMixerBoard::addChannel(const CChannelInfo& chanInfo)
{
- // store the current server name
- strServerName = strNewServerName;
+ // Check for maximum channel limit
+ if (vecpChanFader.size() >= MAX_NUM_CHANNELS)
+ return;
- if ( strServerName.isEmpty() )
- {
- // no connection or connection was reset: show default title
- setTitle ( tr ( "Server" ) );
- }
- else
- {
- // Do not set the server name directly but first show a label which indicates
- // that we are trying to connect the server. First if a connected client
- // list was received, the connection was successful and the title is updated
- // with the correct server name. Make sure to choose a "try to connect" title
- // which is most striking (we use filled blocks and upper case letters).
- setTitle ( u8"\u2588\u2588\u2588\u2588\u2588 " + tr ( "T R Y I N G T O C O N N E C T" ) + u8" \u2588\u2588\u2588\u2588\u2588" );
- }
-}
+ CChannelFader* channelFader = new CChannelFader(this);
-void CAudioMixerBoard::SetGUIDesign ( const EGUIDesign eNewDesign )
-{
- // move the channels tighter together in slim fader mode
- if ( eNewDesign == GD_SLIMFADER )
+ // Set channel information
+ channelFader->SetChannelInfos(chanInfo);
+
+ // Apply stored settings if any
+ QString sname = channelFader->channelUserName();
+ if (m_faderSettingsMap.contains(sname))
{
- pMainLayout->setSpacing ( 2 );
+ FaderSettings settings = m_faderSettingsMap.value(sname);
+ channelFader->SetFaderLevel(settings.faderLevel); // FIXME - group update ????
+ channelFader->setIsMuted(settings.isMuted);
+ // Apply other settings if needed
}
else
{
- pMainLayout->setSpacing ( 6 ); // Qt default spacing value
+ // Set default fader level if needed
+ channelFader->SetFaderLevel(pSettings->iNewClientFaderLevel / 100.0 * AUD_MIX_FADER_MAX );
}
- // apply GUI design to child GUI controls
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
- {
- vecpChanFader[i]->SetGUIDesign ( eNewDesign );
- }
-}
+ // Connect ChannelFader signals to slots
+ // Solo requires no extra info
+ connect ( channelFader, &CChannelFader::soloStateChanged, this, &CAudioMixerBoard::UpdateSoloStates );
-void CAudioMixerBoard::SetMeterStyle ( const EMeterStyle eNewMeterStyle )
-{
- // apply GUI design to child GUI controls
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
- {
- vecpChanFader[i]->SetMeterStyle ( eNewMeterStyle );
- }
-}
-
-void CAudioMixerBoard::SetDisplayPans ( const bool eNDP )
-{
- bDisplayPans = eNDP;
+ // For Gain and Pan, first make OnChGainValueChanged and OnChPanValueChanged in CChannelFader, to pick up the channel idx before calling the slots in CAudioMixerBoard
+ connect ( channelFader, &CChannelFader::gainValueChanged, channelFader, &CChannelFader::OnChGainValueChanged );
+ connect ( channelFader, &CChannelFader::panValueChanged, channelFader, &CChannelFader::OnChPanValueChanged );
+ // now connect related "secondary" signals to slots in audiomixerboard
+ connect ( channelFader, &CChannelFader::withIdxOnChGainValueChanged, this, &CAudioMixerBoard::OnChGainValueChanged );
+ connect ( channelFader, &CChannelFader::withIdxOnChPanValueChanged, this, &CAudioMixerBoard::OnChPanValueChanged );
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
- {
- vecpChanFader[i]->SetDisplayPans ( eNDP && bIsPanSupported );
- }
-}
+ // Add to the vector
+ vecpChanFader.pushback(channelFader);
-void CAudioMixerBoard::SetPanIsSupported()
-{
- bIsPanSupported = true;
- SetDisplayPans ( bDisplayPans );
+ // Notify QML - or don't do here, do after batch update
+ // emit channelsChanged();
}
-void CAudioMixerBoard::HideAll()
+void CAudioMixerBoard::removeChannel(const QString& name)
{
- // before hiding the faders, store their settings
- StoreAllFaderSettings();
-
- // make all controls invisible
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
+ for (size_t i = 0; i < vecpChanFader.size(); ++i)
{
- vecpChanFader[i]->SetChannelLevel ( 0 );
- vecpChanFader[i]->SetDisplayChannelLevel ( false );
- vecpChanFader[i]->SetDisplayPans ( false );
- vecpChanFader[i]->Hide();
- }
-
- // initialize flags and other parameters
- bIsPanSupported = false;
- bNoFaderVisible = true;
- eRecorderState = RS_UNDEFINED;
- iMyChannelID = INVALID_INDEX;
- iRunningNewClientCnt = 0; // reset running counter on new server connection
-
- // use original order of channel (by server ID)
- ChangeFaderOrder ( ST_NO_SORT );
+ if (vecpChanFader.at(i)->channelUserName() == name)
+ {
+ // Remove from vector
+ vecpChanFader.erase(vecpChanFader.begin() + i);
+ // Optionally delete the object if not managed elsewhere
+ // delete vecpChanFader.at(i);
- // Reset recording indication styleSheet
- setStyleSheet ( "" );
+ // Notify QML - or don't do here, do after batch update ???
+ emit channelsChanged();
+ break;
+ }
+ }
+}
- // emit status of connected clients
- emit NumClientsChanged ( 0 ); // -> no clients connected
+void CAudioMixerBoard::clear()
+{
+ // remove all elements in vector and update GUI
+ this->vecpChanFader.clear();
+ emit channelsChanged();
}
void CAudioMixerBoard::SetNumMixerPanelRows ( const int iNNumMixerPanelRows )
@@ -1080,135 +507,9 @@ void CAudioMixerBoard::ChangeFaderOrder ( const EChSortType eChSortType )
{
QMutexLocker locker ( &Mutex );
- // create a pair list of lower strings and fader ID for each channel
- QList> PairList;
- int iNumVisibleFaders = 0;
- int iMyFader = -1;
-
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
- {
- if ( vecpChanFader[i]->GetIsMyOwnFader() )
- {
- iMyFader = static_cast ( i );
- }
-
- switch ( eChSortType )
- {
- case ST_BY_NAME:
- PairList << QPair ( vecpChanFader[i]->GetReceivedName().toLower(), i );
- break;
- case ST_BY_CITY:
- // sort first "by city" and second "by name" by adding the name after the city
- PairList << QPair ( vecpChanFader[i]->GetReceivedCity().toLower() + vecpChanFader[i]->GetReceivedName().toLower(), i );
- break;
- case ST_BY_INSTRUMENT:
- // sort first "by instrument" and second "by name" by adding the name after the instrument
- PairList << QPair ( CInstPictures::GetName ( vecpChanFader[i]->GetReceivedInstrument() ) +
- vecpChanFader[i]->GetReceivedName().toLower(),
- i );
- break;
- case ST_BY_GROUPID:
- // sort first "by group" and second "by name" by adding the name after the group
- if ( vecpChanFader[i]->GetGroupID() == INVALID_INDEX )
- {
- // put channels without a group at the end
- PairList << QPair ( "999" + vecpChanFader[i]->GetReceivedName().toLower(),
- i ); // worst case is one group per channel (current max is 8)
- }
- else
- {
- PairList << QPair ( QString ( "%1" ).arg ( vecpChanFader[i]->GetGroupID(), 3, 10, QLatin1Char ( '0' ) ) +
- vecpChanFader[i]->GetReceivedName().toLower(),
- i );
- }
- break;
- case ST_BY_SERVER_CHANNEL:
- PairList << QPair ( QString ( "%1" ).arg ( vecpChanFader[i]->GetReceivedChID(), 3, 10, QLatin1Char ( '0' ) ) +
- vecpChanFader[i]->GetReceivedName().toLower(),
- i );
- break;
- default: // ST_NO_SORT
- // per definition for no sort: faders are sorted in the order they appeared (note that we
- // pad to a total of 11 characters with zeros to make sure the sorting is done correctly)
- PairList << QPair ( QString ( "%1" ).arg ( vecpChanFader[i]->GetRunningNewClientCnt(), 11, 10, QLatin1Char ( '0' ) ),
- i );
- break;
- }
-
- // count the number of visible faders
- if ( vecpChanFader[i]->IsVisible() )
- {
- iNumVisibleFaders++;
- }
- }
-
- // sort the channels according to the first of the pair
- std::stable_sort ( PairList.begin(), PairList.end() );
-
- // move my fader to first position
- if ( pSettings->bOwnFaderFirst )
- {
- for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
- {
- if ( iMyFader == static_cast ( PairList[i].second ) )
- {
- PairList.move ( i, 0 );
- break;
- }
- }
- }
-
- // we want to distribute iNumVisibleFaders across the first row, then the next, etc
- // up to iNumMixerPanelRows. So row wants to start at 0 until we get to some number,
- // then increase, where "some number" means we get no more than iNumMixerPanelRows.
- const int iNumFadersFirstRow = ( iNumVisibleFaders + iNumMixerPanelRows - 1 ) / iNumMixerPanelRows;
-
- // add channels to the layout in the new order, note that it is not required to remove
- // the widget from the layout first but it is moved to the new position automatically
- int iVisibleFaderCnt = 0;
-
- for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
- {
- const size_t iCurFaderID = PairList[i].second;
-
- if ( vecpChanFader[iCurFaderID]->IsVisible() )
- {
- // channels are added row-first, up to iNumFadersFirstRow, then onto
- // the next row.
- pMainLayout->addWidget ( vecpChanFader[iCurFaderID]->GetMainWidget(),
- iVisibleFaderCnt / iNumFadersFirstRow,
- iVisibleFaderCnt % iNumFadersFirstRow );
-
- iVisibleFaderCnt++;
- }
- }
-}
-
-void CAudioMixerBoard::UpdateTitle()
-{
- QString strTitlePrefix = "";
-
- if ( eRecorderState == RS_RECORDING )
- {
- strTitlePrefix = QString ( "[%1] " ).arg ( tr ( "RECORDING ACTIVE" ) );
- }
-
- // replace & signs with && (See Qt documentation for QLabel)
- // if strServerName includes an "&" sign, this is interpreted as keyboard shortcut (#1886)
- // it might be possible to find a more elegant solution here?
-
- QString strEscServerName = strServerName;
- strEscServerName.replace ( "&", "&&" );
-
- setTitle ( strTitlePrefix + tr ( "Personal Mix at: %1" ).arg ( strEscServerName ) );
- setAccessibleName ( title() );
-}
-
-void CAudioMixerBoard::SetRecorderState ( const ERecorderState newRecorderState )
-{
- // store the new recorder state and update the title
- eRecorderState = newRecorderState;
- UpdateTitle();
+ // do Nothing for now
+ if (eChSortType == 3)
+ return;
}
void CAudioMixerBoard::ApplyNewConClientList ( CVector& vecChanInfo )
@@ -1218,119 +519,84 @@ void CAudioMixerBoard::ApplyNewConClientList ( CVector& vecChanInf
Mutex.lock();
{
- // we want to set the server name only if the very first faders appear
- // in the audio mixer board to show a "try to connect" before
- if ( bNoFaderVisible )
+ // Step 1: Create a mapping of current channel IDs to their indices in vecpChanFader
+ std::unordered_map currentChannelsMap;
+ for (CChannelFader* channelFader : vecpChanFader)
{
- UpdateTitle();
+ int chanID = channelFader->channelID();
+ currentChannelsMap[chanID] = channelFader;
+ if ( static_cast ( chanID ) == iMyChannelID )
+ {
+ // this is my own fader --> set fader property
+ channelFader->SetIsMyOwnFader();
+ }
}
- // search for channels which are already present and preserve their gain
- // setting, for all other channels reset gain
+ // Step 2: Prepare a new vector for updated channels
+ CVector newVecpChanFader;
- // get all channels which are in use/not in use.
- // We use the array index of vecChanInfo if the fader is in use,
- // else INVALID_INDEX to specify it is not in use
- // so must use "int" for the array type.
- int iFaderNumber[MAX_NUM_CHANNELS];
-
- for ( size_t iChanID = 0; iChanID < MAX_NUM_CHANNELS; iChanID++ )
+ // Step 3: Process connected clients
+ for (const auto& chanInfo : vecChanInfo)
{
- iFaderNumber[iChanID] = INVALID_INDEX;
- }
+ int chanID = chanInfo.iChanID;
- for ( size_t iFader = 0; iFader < iNumConnectedClients; iFader++ )
- {
- // ideally "iChanID" in CChannelInfo would be size_t if it can never be INVALID_INDEX
- // as assumed here
- iFaderNumber[vecChanInfo[iFader].iChanID] = static_cast ( iFader );
- }
-
- // Hide all unused faders and initialize used ones
- for ( size_t iChanID = 0; iChanID < MAX_NUM_CHANNELS; iChanID++ )
- {
- if ( iFaderNumber[iChanID] == INVALID_INDEX )
+ if (currentChannelsMap.count(chanID))
{
- // current fader is not used
- StoreFaderSettings ( vecpChanFader[iChanID] );
+ // Existing channel
+ CChannelFader* channelFader = currentChannelsMap[chanID];
+ currentChannelsMap.erase(chanID);
- vecpChanFader[iChanID]->Hide();
- continue;
- }
- size_t idxVecpChan = static_cast ( iFaderNumber[iChanID] );
+ // Update channel info
+ channelFader->SetChannelInfos(chanInfo);
- // current fader is used
- if ( !vecpChanFader[iChanID]->IsVisible() )
+ newVecpChanFader.pushback(channelFader);
+ }
+ else
{
- // the fader was not in use,
- // reset everything for new client
- vecpChanFader[iChanID]->Reset();
- vecAvgLevels[iChanID] = 0.0f;
-
- if ( static_cast ( iChanID ) == iMyChannelID )
- {
- // this is my own fader --> set fader property
- vecpChanFader[iChanID]->SetIsMyOwnFader();
- }
+ // New channel - use addChannel method
+ addChannel(chanInfo);
- // keep track of each new client
- // for "no sorting" channel sort order new clients are added
- // to the right-hand side of the mixer (#673)
- vecpChanFader[iChanID]->SetRunningNewClientCnt ( iRunningNewClientCnt++ );
-
- // show fader
- vecpChanFader[iChanID]->Show();
-
- // Set the default initial fader level. Check first that
- // this is not the initialization (i.e. previously there
- // were no faders visible) to avoid that our own level is
- // adjusted. If we have received our own channel ID, then
- // we can adjust the level even if no fader was visible.
- // The fader level of 100 % is the default in the
- // server, in that case we do not have to do anything here.
- if ( ( !bNoFaderVisible || ( ( iMyChannelID != INVALID_INDEX ) && ( iMyChannelID != static_cast ( iChanID ) ) ) ) &&
- ( pSettings->iNewClientFaderLevel != 100 ) )
- {
- // the value is in percent -> convert range
- vecpChanFader[iChanID]->SetFaderLevel ( pSettings->iNewClientFaderLevel / 100.0 * AUD_MIX_FADER_MAX );
- }
+ // Retrieve the recently added channel and add to new vector
+ CChannelFader* channelFader = vecpChanFader.back(); // The new channel is at the end
+ newVecpChanFader.pushback(channelFader);
}
+ }
- if ( vecpChanFader[iChanID]->GetReceivedName().compare ( vecChanInfo[idxVecpChan].strName ) )
- {
- // the text has actually changed, search in the list of
- // stored settings if we have a matching entry
- int iStoredFaderLevel;
- int iStoredPanValue;
- bool bStoredFaderIsSolo;
- bool bStoredFaderIsMute;
- int iGroupID;
-
- if ( GetStoredFaderSettings ( vecChanInfo[idxVecpChan].strName,
- iStoredFaderLevel,
- iStoredPanValue,
- bStoredFaderIsSolo,
- bStoredFaderIsMute,
- iGroupID ) )
- {
- vecpChanFader[iChanID]->SetFaderLevel ( iStoredFaderLevel, true ); // suppress group update
- vecpChanFader[iChanID]->SetPanValue ( iStoredPanValue );
- vecpChanFader[iChanID]->SetFaderIsSolo ( bStoredFaderIsSolo );
- vecpChanFader[iChanID]->SetFaderIsMute ( bStoredFaderIsMute );
- vecpChanFader[iChanID]->SetGroupID ( iGroupID ); // Must be the last to be set in the fader!
- }
- }
+ // Step 4: Remove disconnected channels
+ for (const auto& pair : currentChannelsMap)
+ {
+ CChannelFader* channelFader = pair.second;
+
+ // Store settings
+ StoreFaderSettings(channelFader);
- // set the channel infos
- vecpChanFader[iChanID]->SetChannelInfos ( vecChanInfo[idxVecpChan] );
+ // Delete channel fader
+ delete channelFader;
}
+ // Step 5: Swap the old vector with the new one
+ vecpChanFader = std::move(newVecpChanFader);
+
+ // Step 6: Notify QML that channels have changed
+ emit channelsChanged();
+
+ // Update any other UI elements or internal state as needed
+
+ // updateStatusBar();
+
+ // Check for stored settings
+ // QString name = channelFader->channelUserName();
+ // if (m_faderSettingsMap.contains(name))
+ // {
+ // FaderSettings settings = m_faderSettingsMap.value(name);
+ // channelFader->SetFaderLevel(settings.faderLevel);
+ // channelFader->setIsMuted(settings.isMuted);
+ // // Apply other settings
+ // }
+
// update the solo states since if any channel was on solo and a new client
// has just connected, the new channel must be muted
UpdateSoloStates();
-
- // update flag for "all faders are invisible"
- bNoFaderVisible = ( iNumConnectedClients == 0 );
}
Mutex.unlock(); // release mutex
@@ -1343,50 +609,37 @@ void CAudioMixerBoard::ApplyNewConClientList ( CVector& vecChanInf
void CAudioMixerBoard::SetFaderLevel ( const int iChannelIdx, const int iValue )
{
- // only apply new fader level if channel index is valid and the fader is visible
- if ( ( iChannelIdx >= 0 ) && ( iChannelIdx < MAX_NUM_CHANNELS ) )
+ // only apply new fader level if channel index is valid
+ if ( ( iChannelIdx >= 0 ) )
{
- if ( vecpChanFader[static_cast ( iChannelIdx )]->IsVisible() )
- {
- vecpChanFader[static_cast ( iChannelIdx )]->SetFaderLevel ( iValue );
- }
+ vecpChanFader[static_cast ( iChannelIdx )]->SetFaderLevel ( iValue );
}
}
void CAudioMixerBoard::SetPanValue ( const int iChannelIdx, const int iValue )
{
- // only apply new pan value if channel index is valid and the panner is visible
- if ( ( iChannelIdx >= 0 ) && ( iChannelIdx < MAX_NUM_CHANNELS ) && bDisplayPans )
+ // only apply new pan value if channel index is valid
+ if ( ( iChannelIdx >= 0 ) && bDisplayPans )
{
- if ( vecpChanFader[static_cast ( iChannelIdx )]->IsVisible() )
- {
- vecpChanFader[static_cast ( iChannelIdx )]->SetPanValue ( iValue );
- }
+ vecpChanFader[static_cast ( iChannelIdx )]->SetPanValue ( iValue );
}
}
void CAudioMixerBoard::SetFaderIsSolo ( const int iChannelIdx, const bool bIsSolo )
{
- // only apply solo if channel index is valid and the fader is visible
- if ( ( iChannelIdx >= 0 ) && ( iChannelIdx < MAX_NUM_CHANNELS ) )
-
+ // only apply solo if channel index is valid
+ if ( ( iChannelIdx >= 0 ) )
{
- if ( vecpChanFader[static_cast ( iChannelIdx )]->IsVisible() )
- {
- vecpChanFader[static_cast ( iChannelIdx )]->SetFaderIsSolo ( bIsSolo );
- }
+ vecpChanFader[static_cast ( iChannelIdx )]->SetFaderIsSolo ( bIsSolo );
}
}
void CAudioMixerBoard::SetFaderIsMute ( const int iChannelIdx, const bool bIsMute )
{
- // only apply mute if channel index is valid and the fader is visible
- if ( ( iChannelIdx >= 0 ) && ( iChannelIdx < MAX_NUM_CHANNELS ) )
+ // only apply mute if channel index is valid
+ if ( ( iChannelIdx >= 0 ) )
{
- if ( vecpChanFader[static_cast ( iChannelIdx )]->IsVisible() )
- {
- vecpChanFader[static_cast ( iChannelIdx )]->SetFaderIsMute ( bIsMute );
- }
+ vecpChanFader[static_cast ( iChannelIdx )]->SetFaderIsMute ( bIsMute );
}
}
@@ -1394,15 +647,14 @@ void CAudioMixerBoard::SetAllFaderLevelsToNewClientLevel()
{
QMutexLocker locker ( &Mutex );
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
+ for (CChannelFader* channelFader : vecpChanFader)
{
- // only apply to visible faders and not to my own channel fader
- if ( vecpChanFader[i]->IsVisible() && ( static_cast ( i ) != iMyChannelID ) )
+ if ( ( static_cast ( channelFader->channelID() ) != iMyChannelID ) )
{
// the value is in percent -> convert range, also use the group
// update flag to make sure the group values are all set to the
// same fader level now
- vecpChanFader[i]->SetFaderLevel ( pSettings->iNewClientFaderLevel / 100.0 * AUD_MIX_FADER_MAX, true );
+ channelFader->SetFaderLevel ( pSettings->iNewClientFaderLevel / 100.0 * AUD_MIX_FADER_MAX, true );
}
}
}
@@ -1423,19 +675,20 @@ void CAudioMixerBoard::AutoAdjustAllFaderLevels()
levels.resize ( MAX_NUM_FADER_GROUPS + 1 );
// compute min/max level per group and number of channels per group
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; ++i )
+ for (CChannelFader* channelFader : vecpChanFader)
{
- // only apply to visible faders (and not to my own channel fader)
- if ( vecpChanFader[i]->IsVisible() && ( static_cast ( i ) != iMyChannelID ) )
+ // don't apply to my own channel fader)
+ if ( channelFader->channelID() != iMyChannelID )
{
+ int i = channelFader->channelID();
// map averaged meter output level to decibels
// (invert CStereoSignalLevelMeter::CalcLogResultForMeter)
float leveldB = vecAvgLevels[i] * ( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER ) / NUM_STEPS_LED_BAR + LOW_BOUND_SIG_METER;
size_t group = MAX_NUM_FADER_GROUPS;
- if ( vecpChanFader[i]->GetGroupID() != INVALID_INDEX )
+ if ( channelFader->groupID() != INVALID_INDEX )
{
- group = static_cast ( vecpChanFader[i]->GetGroupID() );
+ group = static_cast ( channelFader->groupID() );
}
if ( leveldB >= AUTO_FADER_NOISE_THRESHOLD_DB )
@@ -1513,16 +766,17 @@ void CAudioMixerBoard::AutoAdjustAllFaderLevels()
}
// adjust all levels
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; ++i )
+ for (CChannelFader* channelFader : vecpChanFader)
{
- // only apply to visible faders (and not to my own channel fader)
- if ( vecpChanFader[i]->IsVisible() && ( static_cast ( i ) != iMyChannelID ) )
+ // don't apply to my own channel fader)
+ if ( channelFader->channelID() != iMyChannelID )
{
+ int i = channelFader->channelID();
// map averaged meter output level to decibels
// (invert CStereoSignalLevelMeter::CalcLogResultForMeter)
float leveldB = vecAvgLevels[i] * ( UPPER_BOUND_SIG_METER - LOW_BOUND_SIG_METER ) / NUM_STEPS_LED_BAR + LOW_BOUND_SIG_METER;
- int group = vecpChanFader[i]->GetGroupID();
+ int group = channelFader->groupID();
if ( group == INVALID_INDEX )
{
if ( cntActiveGroups > 0 )
@@ -1551,7 +805,7 @@ void CAudioMixerBoard::AutoAdjustAllFaderLevels()
newFaderLevel = fmin ( fmax ( newFaderLevel, 0.0f ), float ( AUD_MIX_FADER_MAX ) );
// set fader level
- vecpChanFader[i]->SetFaderLevel ( newFaderLevel, true );
+ channelFader->SetFaderLevel ( newFaderLevel, true );
}
}
}
@@ -1561,9 +815,9 @@ void CAudioMixerBoard::SetMIDICtrlUsed ( const bool bMIDICtrlUsed )
{
QMutexLocker locker ( &Mutex );
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
+ for (CChannelFader* channelFader : vecpChanFader)
{
- vecpChanFader[i]->SetMIDICtrlUsed ( bMIDICtrlUsed );
+ channelFader->SetMIDICtrlUsed ( bMIDICtrlUsed );
}
}
@@ -1571,9 +825,9 @@ void CAudioMixerBoard::StoreAllFaderSettings()
{
QMutexLocker locker ( &Mutex );
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
+ for (CChannelFader* channelFader : vecpChanFader)
{
- StoreFaderSettings ( vecpChanFader[i] );
+ StoreFaderSettings ( channelFader );
}
}
@@ -1587,33 +841,30 @@ void CAudioMixerBoard::LoadAllFaderSettings()
bool bStoredFaderIsMute;
int iGroupID;
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
+ for (CChannelFader* channelFader : vecpChanFader)
{
- if ( GetStoredFaderSettings ( vecpChanFader[i]->GetReceivedName(),
+ if ( GetStoredFaderSettings ( channelFader->GetReceivedName(),
iStoredFaderLevel,
iStoredPanValue,
bStoredFaderIsSolo,
bStoredFaderIsMute,
iGroupID ) )
{
- vecpChanFader[i]->SetFaderLevel ( iStoredFaderLevel, true ); // suppress group update
- vecpChanFader[i]->SetPanValue ( iStoredPanValue );
- vecpChanFader[i]->SetFaderIsSolo ( bStoredFaderIsSolo );
- vecpChanFader[i]->SetFaderIsMute ( bStoredFaderIsMute );
- vecpChanFader[i]->SetGroupID ( iGroupID ); // Must be the last to be set in the fader!
+ channelFader->SetFaderLevel ( iStoredFaderLevel, true ); // suppress group update
+ channelFader->SetPanValue ( iStoredPanValue );
+ channelFader->SetFaderIsSolo ( bStoredFaderIsSolo );
+ channelFader->SetFaderIsMute ( bStoredFaderIsMute );
+ channelFader->setGroupID ( iGroupID ); // Must be the last to be set in the fader!
}
}
}
void CAudioMixerBoard::SetRemoteFaderIsMute ( const int iChannelIdx, const bool bIsMute )
{
- // only apply remote mute state if channel index is valid and the fader is visible
- if ( ( iChannelIdx >= 0 ) && ( iChannelIdx < MAX_NUM_CHANNELS ) )
+ // only apply remote mute state if channel index is valid
+ if ( iChannelIdx >= 0 )
{
- if ( vecpChanFader[static_cast ( iChannelIdx )]->IsVisible() )
- {
- vecpChanFader[static_cast ( iChannelIdx )]->SetRemoteFaderIsMute ( bIsMute );
- }
+ vecpChanFader[static_cast ( iChannelIdx )]->SetRemoteFaderIsMute ( bIsMute );
}
}
@@ -1622,23 +873,20 @@ void CAudioMixerBoard::UpdateSoloStates()
// first check if any channel has a solo state active
bool bAnyChannelIsSolo = false;
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
+ for (CChannelFader* channelFader : vecpChanFader)
{
- // check if fader is in use and has solo state active
- if ( vecpChanFader[i]->IsVisible() && vecpChanFader[i]->IsSolo() )
+ // check if fader has solo state active
+ if ( channelFader->isSolo() )
{
bAnyChannelIsSolo = true;
continue;
}
}
- // now update the solo state of all active faders
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
+ // // now update the solo state of all active faders
+ for (CChannelFader* channelFader : vecpChanFader)
{
- if ( vecpChanFader[i]->IsVisible() )
- {
- vecpChanFader[i]->UpdateSoloState ( bAnyChannelIsSolo );
- }
+ channelFader->UpdateSoloState ( bAnyChannelIsSolo );
}
}
@@ -1659,28 +907,31 @@ void CAudioMixerBoard::UpdateGainValue ( const int iChannelIdx,
// if this fader is selected, all other in the group must be updated as
// well (note that we do not have to update if this is already a group update
// to avoid an infinite loop)
- if ( ( vecpChanFader[stChannelIdx]->GetGroupID() != INVALID_INDEX ) && !bIsGroupUpdate )
+ if ( ( vecpChanFader[stChannelIdx]->groupID() != INVALID_INDEX ) && !bIsGroupUpdate )
{
- for ( size_t i = 0; i < MAX_NUM_CHANNELS; i++ )
+ for (CChannelFader* channelFader : vecpChanFader)
{
// update rest of faders selected
- if ( vecpChanFader[i]->IsVisible() && ( vecpChanFader[i]->GetGroupID() == vecpChanFader[stChannelIdx]->GetGroupID() ) &&
- ( i != stChannelIdx ) && ( dLevelRatio >= 0 ) )
+ if (( channelFader->groupID() == vecpChanFader[stChannelIdx]->groupID() ) && ( channelFader->channelID() != stChannelIdx ) && ( dLevelRatio >= 0 ))
{
// synchronize faders with moving fader level (it is important
// to set the group flag to avoid infinite looping)
- vecpChanFader[i]->SetFaderLevel ( vecpChanFader[i]->GetPreviousFaderLevel() * dLevelRatio, true );
+ channelFader->SetFaderLevel ( channelFader->GetPreviousFaderLevel() * dLevelRatio, true );
}
}
+
}
}
-void CAudioMixerBoard::UpdatePanValue ( const int iChannelIdx, const float fValue ) { emit ChangeChanPan ( iChannelIdx, fValue ); }
+void CAudioMixerBoard::UpdatePanValue ( const int iChannelIdx, const float fValue )
+{
+ emit ChangeChanPan ( iChannelIdx, fValue );
+}
void CAudioMixerBoard::StoreFaderSettings ( CChannelFader* pChanFader )
{
- // if the fader was visible and the name is not empty, we store the old gain
- if ( pChanFader->IsVisible() && !pChanFader->GetReceivedName().isEmpty() )
+ // if the name is not empty, we store the old gain
+ if ( !pChanFader->GetReceivedName().isEmpty() )
{
CVector viOldStoredFaderLevels ( pSettings->vecStoredFaderLevels );
CVector viOldStoredPanValues ( pSettings->vecStoredPanValues );
@@ -1692,11 +943,11 @@ void CAudioMixerBoard::StoreFaderSettings ( CChannelFader* pChanFader )
const int iOldIdx = pSettings->vecStoredFaderTags.StringFiFoWithCompare ( pChanFader->GetReceivedName() );
// current fader level and solo state is at the top of the list
- pSettings->vecStoredFaderLevels[0] = pChanFader->GetFaderLevel();
+ pSettings->vecStoredFaderLevels[0] = pChanFader->faderLevel();
pSettings->vecStoredPanValues[0] = pChanFader->GetPanValue();
- pSettings->vecStoredFaderIsSolo[0] = pChanFader->IsSolo();
- pSettings->vecStoredFaderIsMute[0] = pChanFader->IsMute();
- pSettings->vecStoredFaderGroupID[0] = pChanFader->GetGroupID();
+ pSettings->vecStoredFaderIsSolo[0] = pChanFader->isSolo();
+ pSettings->vecStoredFaderIsMute[0] = pChanFader->isMuted();
+ pSettings->vecStoredFaderGroupID[0] = pChanFader->groupID();
size_t iTempListCnt = 1; // current fader is on top, other faders index start at 1
for ( size_t iIdx = 0; iIdx < MAX_NUM_STORED_FADER_SETTINGS; iIdx++ )
@@ -1722,6 +973,22 @@ void CAudioMixerBoard::StoreFaderSettings ( CChannelFader* pChanFader )
}
}
+// void CAudioMixerBoard::StoreFaderSettings(CChannelFader* pChanFader)
+// {
+// QString name = pChanFader->channelUserName();
+// if (name.isEmpty())
+// return;
+
+// // need to define FaderSettings as a struct and m_faderSettingsMap as a QMap.
+
+// FaderSettings fSettings;
+// fSettings.faderLevel = pChanFader->faderLevel();
+// fSettings.isMuted = pChanFader->isMuted();
+// // Store other settings as needed
+
+// m_faderSettingsMap[name] = fSettings;
+// }
+
bool CAudioMixerBoard::GetStoredFaderSettings ( const QString& strName,
int& iStoredFaderLevel,
int& iStoredPanValue,
@@ -1759,23 +1026,19 @@ void CAudioMixerBoard::SetChannelLevels ( const CVector& vecChannelLev
const size_t iNumChannelLevels = vecChannelLevel.size();
size_t i = 0;
- for ( size_t iChId = 0; iChId < MAX_NUM_CHANNELS; iChId++ )
+ for ( size_t iChId = 0; iChId < vecpChanFader.Size(); iChId++ )
{
- if ( vecpChanFader[iChId]->IsVisible() && ( i < iNumChannelLevels ) )
+ if ( i < iNumChannelLevels ) //FIXME - shouldn't need this
{
// compute exponential moving average
vecAvgLevels[iChId] = ( 1.0f - AUTO_FADER_ADJUST_ALPHA ) * vecAvgLevels[iChId] + AUTO_FADER_ADJUST_ALPHA * vecChannelLevel[i];
vecpChanFader[iChId]->SetChannelLevel ( vecChannelLevel[i++] );
-
- // show level only if we successfully received levels from the
- // server (if server does not support levels, do not show levels)
- if ( !vecpChanFader[iChId]->GetDisplayChannelLevel() )
- {
- vecpChanFader[iChId]->SetDisplayChannelLevel ( true );
- }
}
}
}
-void CAudioMixerBoard::MuteMyChannel() { SetFaderIsMute ( iMyChannelID, true ); }
+void CAudioMixerBoard::MuteMyChannel()
+{
+ SetFaderIsMute ( iMyChannelID, true );
+}
diff --git a/src/audiomixerboard.h b/src/audiomixerboard.h
index 6b42d35085..03680ebf34 100644
--- a/src/audiomixerboard.h
+++ b/src/audiomixerboard.h
@@ -24,21 +24,10 @@
#pragma once
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
#include
-#include
-#include
#include
#include
+#include
#include "global.h"
#include "util.h"
#include "levelmeter.h"
@@ -49,37 +38,57 @@ class CChannelFader : public QObject
{
Q_OBJECT
+ Q_PROPERTY(CLevelMeter* channelMeter READ channelMeter CONSTANT)
+ Q_PROPERTY(QString channelUserName READ channelUserName WRITE setchannelUserName NOTIFY channelUserNameChanged)
+ Q_PROPERTY(double faderLevel READ faderLevel WRITE setFaderLevel NOTIFY faderLevelChanged)
+ Q_PROPERTY(double panLevel READ panLevel WRITE setPanLevel NOTIFY panLevelChanged)
+ Q_PROPERTY(bool isMuted READ isMuted WRITE setIsMuted NOTIFY isMutedChanged)
+ Q_PROPERTY(bool isSolo READ isSolo WRITE setIsSolo NOTIFY isSoloChanged)
+ Q_PROPERTY(int groupID READ groupID WRITE setGroupID NOTIFY groupIDChanged FINAL)
+ Q_PROPERTY(bool isRemoteMuted READ isRemoteMuted WRITE setIsRemoteMuted NOTIFY isRemoteMutedChanged)
+
public:
- CChannelFader ( QWidget* pNW );
+ explicit CChannelFader(QObject* parent = nullptr);
+
+ // QML accessors
+ QString channelUserName() const;
+ void setchannelUserName(const QString& name);
+
+ double faderLevel() const;
+ Q_INVOKABLE void setFaderLevel(double dLevel);
+ // related helper function
+ void setFaderLevelNoSend(double dLevel);
+
+ double panLevel() const;
+ Q_INVOKABLE void setPanLevel(double level);
+
+ bool isMuted() const;
+ Q_INVOKABLE void setIsMuted(bool muted);
+
+ bool isSolo() const;
+ Q_INVOKABLE void setIsSolo(bool solo);
+
+ int groupID() const;
+ Q_INVOKABLE void setGroupID(int grpID);
+ bool isRemoteMuted() const;
+ void setIsRemoteMuted(bool remoteMuted);
+
+ CLevelMeter* channelMeter() const { return m_channelMeter; }
+ // --------
+
+ int channelID() const;
+ void setChannelID(int id);
QString GetReceivedName() { return cReceivedChanInfo.strName; }
- int GetReceivedInstrument() { return cReceivedChanInfo.iInstrument; }
- QString GetReceivedCity() { return cReceivedChanInfo.strCity; }
- int GetReceivedChID() { return cReceivedChanInfo.iChanID; }
void SetChannelInfos ( const CChannelInfo& cChanInfo );
- void Show() { pFrame->show(); }
- void Hide() { pFrame->hide(); }
- bool IsVisible() { return !pFrame->isHidden(); }
- bool IsSolo() { return pcbSolo->isChecked(); }
- bool IsMute() { return pcbMute->isChecked(); }
- int GetGroupID() { return iGroupID; }
- void SetGUIDesign ( const EGUIDesign eNewDesign );
- void SetMeterStyle ( const EMeterStyle eNewMeterStyle );
- void SetDisplayChannelLevel ( const bool eNDCL );
- bool GetDisplayChannelLevel();
- void SetDisplayPans ( const bool eNDP );
- QFrame* GetMainWidget() { return pFrame; }
-
void SetPanValue ( const int iPan );
void SetFaderIsSolo ( const bool bIsSolo );
void SetFaderIsMute ( const bool bIsMute );
- void SetGroupID ( const int iNGroupID );
void SetRemoteFaderIsMute ( const bool bIsMute );
void SetFaderLevel ( const double dLevel, const bool bIsGroupUpdate = false );
- int GetFaderLevel() { return pFader->value(); }
double GetPreviousFaderLevel() { return dPreviousFaderLevel; }
- int GetPanValue() { return pPan->value(); }
+ int GetPanValue() { return m_panLevel; }
void Reset();
void SetRunningNewClientCnt ( const int iNRunningNewClientCnt ) { iRunningNewClientCnt = iNRunningNewClientCnt; }
int GetRunningNewClientCnt() { return iRunningNewClientCnt; }
@@ -91,34 +100,20 @@ class CChannelFader : public QObject
void SetMIDICtrlUsed ( const bool isMIDICtrlUsed ) { bMIDICtrlUsed = isMIDICtrlUsed; }
protected:
+ // for QML
+ double m_faderLevel;
+ double m_panLevel;
+ bool m_isMuted;
+ bool m_isSolo;
+ bool m_isRemoteMuted;
+ CLevelMeter* m_channelMeter;
+ // --------
+
void UpdateGroupIDDependencies();
void SetMute ( const bool bState );
- void SetupFaderTag ( const ESkillLevel eSkillLevel );
void SendPanValueToServer ( const int iPan );
void SendFaderLevelToServer ( const double dLevel, const bool bIsGroupUpdate );
- QFrame* pFrame;
-
- QWidget* pLevelsBox;
- QWidget* pMuteSoloBox;
- CLevelMeter* plbrChannelLevel;
- QSlider* pFader;
- QDial* pPan;
- QLabel* pPanLabel;
- QLabel* pInfoLabel;
- QHBoxLayout* pLabelGrid;
- QVBoxLayout* pLabelPictGrid;
-
- QCheckBox* pcbMute;
- QCheckBox* pcbSolo;
- QCheckBox* pcbGroup;
- QMenu* pGroupPopupMenu;
-
- QGroupBox* pLabelInstBox;
- QLabel* plblLabel;
- QLabel* plblInstrument;
- QLabel* plblCountryFlag;
-
CChannelInfo cReceivedChanInfo;
bool bOtherChannelIsSolo;
@@ -128,87 +123,69 @@ class CChannelFader : public QObject
int iGroupID;
QString strGroupBaseText;
int iRunningNewClientCnt;
- int iInstrPicMaxWidth;
- EGUIDesign eDesign;
- EMeterStyle eMeterStyle;
- QPixmap BitmapMutedIcon;
bool bMIDICtrlUsed;
public slots:
- void OnLevelValueChanged ( int value )
+ void OnChGainValueChanged ( float fValue, bool bIsMyOwnFader, bool bIsGroupUpdate, bool bSuppressServerUpdate, double dLevelRatio )
{
- SendFaderLevelToServer ( value,
- QGuiApplication::keyboardModifiers() ==
- Qt::ShiftModifier ); /* isolate a channel from the group temporarily with shift-click-drag (#695) */
+ // add in the channel index/id for audiomixerboard to process
+ emit withIdxOnChGainValueChanged( cReceivedChanInfo.iChanID, fValue, bIsMyOwnFader, bIsGroupUpdate, bSuppressServerUpdate, dLevelRatio );
}
- void OnPanValueChanged ( int value );
- void OnMuteStateChanged ( int value );
- void OnGroupStateChanged ( int );
-
- void OnGroupMenuGrp ( int iGrp ) { SetGroupID ( iGrp ); }
-
-signals:
- void gainValueChanged ( float value, bool bIsMyOwnFader, bool bIsGroupUpdate, bool bSuppressServerUpdate, double dLevelRatio );
-
- void panValueChanged ( float value );
- void soloStateChanged ( int value );
-};
-
-template
-class CAudioMixerBoardSlots : public CAudioMixerBoardSlots
-{
-public:
- void OnChGainValueChanged ( float fValue, bool bIsMyOwnFader, bool bIsGroupUpdate, bool bSuppressServerUpdate, double dLevelRatio )
+ void OnChPanValueChanged ( float fValue )
{
- UpdateGainValue ( slotId - 1, fValue, bIsMyOwnFader, bIsGroupUpdate, bSuppressServerUpdate, dLevelRatio );
+ // add in the channel index/id for audiomixerboard to process
+ emit withIdxOnChPanValueChanged( cReceivedChanInfo.iChanID, fValue );
}
- void OnChPanValueChanged ( float fValue ) { UpdatePanValue ( slotId - 1, fValue ); }
-
-protected:
- virtual void UpdateGainValue ( const int iChannelIdx,
- const float fValue,
- const bool bIsMyOwnFader,
- const bool bIsGroupUpdate,
- const bool bSuppressServerUpdate,
- const double dLevelRatio ) = 0;
-
- virtual void UpdatePanValue ( const int iChannelIdx, const float fValue ) = 0;
+signals:
+ // update qml
+ void channelUserNameChanged();
+ void faderLevelChanged();
+ void panLevelChanged();
+ void isMutedChanged();
+ void isSoloChanged();
+ void groupIDChanged();
+ void isRemoteMutedChanged();
+
+ void gainValueChanged ( float value, bool bIsMyOwnFader, bool bIsGroupUpdate, bool bSuppressServerUpdate, double dLevelRatio ); // sends to server
+ void panValueChanged ( float value ); // sends to server
+ void soloStateChanged (); // the int didn't do anything ?? int value );
+
+ // for audiomixerboard slots
+ void withIdxOnChGainValueChanged ( int chanIdx, float value, bool bIsMyOwnFader, bool bIsGroupUpdate, bool bSuppressServerUpdate, double dLevelRatio );
+ void withIdxOnChPanValueChanged ( int chanIdx, float value );
};
-template<>
-class CAudioMixerBoardSlots<0>
-{};
-class CAudioMixerBoard : public QGroupBox, public CAudioMixerBoardSlots
+// --------------------------------------------------------------------------------------------------
+
+class CAudioMixerBoard : public QObject
{
Q_OBJECT
+ Q_PROPERTY(QQmlListProperty channels READ channels NOTIFY channelsChanged)
+
public:
- CAudioMixerBoard ( QWidget* parent = nullptr );
+ CAudioMixerBoard ( CClientSettings* pSet, QObject* parent = nullptr );
virtual ~CAudioMixerBoard();
- void SetSettingsPointer ( CClientSettings* pNSet ) { pSettings = pNSet; }
- void HideAll();
+ QQmlListProperty channels();
+
+ Q_INVOKABLE void addChannel(const CChannelInfo& chanInfo);
+ Q_INVOKABLE void removeChannel(const QString& name);
+
+ void clear();
+
void ApplyNewConClientList ( CVector& vecChanInfo );
- void SetServerName ( const QString& strNewServerName );
- QString GetServerName() { return strServerName; }
- void SetGUIDesign ( const EGUIDesign eNewDesign );
- void SetMeterStyle ( const EMeterStyle eNewMeterStyle );
- void SetDisplayPans ( const bool eNDP );
- void SetPanIsSupported();
void SetRemoteFaderIsMute ( const int iChannelIdx, const bool bIsMute );
void SetMyChannelID ( const int iChannelIdx ) { iMyChannelID = iChannelIdx; }
int GetMyChannelID() const { return iMyChannelID; }
void SetFaderLevel ( const int iChannelIdx, const int iValue );
-
void SetPanValue ( const int iChannelIdx, const int iValue );
-
void SetFaderIsSolo ( const int iChannelIdx, const bool bIsSolo );
-
void SetFaderIsMute ( const int iChannelIdx, const bool bIsMute );
void SetNumMixerPanelRows ( const int iNNumMixerPanelRows );
@@ -219,9 +196,6 @@ class CAudioMixerBoard : public QGroupBox, public CAudioMixerBoardSlots& vecChannelLevel );
- void SetRecorderState ( const ERecorderState newRecorderState );
- ERecorderState GetRecorderState() { return eRecorderState; };
-
void SetAllFaderLevelsToNewClientLevel();
void StoreAllFaderSettings();
void LoadAllFaderSettings();
@@ -232,64 +206,74 @@ class CAudioMixerBoard : public QGroupBox, public CAudioMixerBoardSlots* list, CChannelFader* channel);
+ static qsizetype channelCount(QQmlListProperty* list);
+ static CChannelFader* channelAt(QQmlListProperty* list, qsizetype index);
+ static void clearChannels(QQmlListProperty* list);
+
+ // for fader val storage - FIXME maybe not using
+ struct FaderSettings
{
- public:
- CMixerBoardScrollArea ( QWidget* parent = nullptr ) : QScrollArea ( parent ) {}
-
- protected:
- virtual void resizeEvent ( QResizeEvent* event )
- {
- // if after a resize of the main window a vertical scroll bar is required, make
- // sure that the fader label is visible (scroll down completely)
- ensureVisible ( 0, 2000 ); // use a large value here
- QScrollArea::resizeEvent ( event );
- }
+ double faderLevel = 100.0; // Default fader level (e.g., max volume)
+ int panValue = 0; // Default pan value (center)
+ bool isMuted = false;
+ bool isSolo = false;
+ int groupID = -1; // Default group ID (or invalid)
};
+ QMap m_faderSettingsMap;
+ // ----
void ChangeFaderOrder ( const EChSortType eChSortType );
-
bool GetStoredFaderSettings ( const QString& strName,
int& iStoredFaderLevel,
int& iStoredPanValue,
bool& bStoredFaderIsSolo,
bool& bStoredFaderIsMute,
int& iGroupID );
-
void StoreFaderSettings ( CChannelFader* pChanFader );
void UpdateSoloStates();
- void UpdateTitle();
+ // void UpdateTitle();
CClientSettings* pSettings;
CVector vecpChanFader;
- CMixerBoardScrollArea* pScrollArea;
- QGridLayout* pMainLayout;
bool bDisplayPans;
bool bIsPanSupported;
- bool bNoFaderVisible;
int iMyChannelID; // must use int (not size_t) so INVALID_INDEX can be stored
int iRunningNewClientCnt; // integer type is sufficient, will never overrun for its purpose
int iNumMixerPanelRows;
- QString strServerName;
+ // QString strServerName;
ERecorderState eRecorderState;
QMutex Mutex;
EChSortType eChSortType;
CVector vecAvgLevels;
- virtual void UpdateGainValue ( const int iChannelIdx,
+ void UpdateGainValue ( const int iChannelIdx,
const float fValue,
const bool bIsMyOwnFader,
const bool bIsGroupUpdate,
const bool bSuppressServerUpdate,
const double dLevelRatio );
- virtual void UpdatePanValue ( const int iChannelIdx, const float fValue );
+ void UpdatePanValue ( const int iChannelIdx, const float fValue );
- template
- inline void connectFaderSignalsToMixerBoardSlots();
+public slots:
+ void OnChGainValueChanged ( int iChannelIdx, float fValue, bool bIsMyOwnFader, bool bIsGroupUpdate, bool bSuppressServerUpdate, double dLevelRatio )
+ {
+ UpdateGainValue ( iChannelIdx, fValue, bIsMyOwnFader, bIsGroupUpdate, bSuppressServerUpdate, dLevelRatio );
+ }
+
+ void OnChPanValueChanged ( int iChannelIdx, float fValue )
+ {
+ UpdatePanValue ( iChannelIdx, fValue );
+ }
signals:
+ // for QML
+ void channelsChanged();
+
void ChangeChanGain ( int iId, float fGain, bool bIsMyOwnFader );
void ChangeChanPan ( int iId, float fPan );
void NumClientsChanged ( int iNewNumClients );
+
};
diff --git a/src/chatbox.cpp b/src/chatbox.cpp
new file mode 100644
index 0000000000..0324f963fd
--- /dev/null
+++ b/src/chatbox.cpp
@@ -0,0 +1,111 @@
+/******************************************************************************\
+ * Copyright (c) 2004-2024
+ *
+ * Author(s):
+ * Volker Fischer
+ *
+ ******************************************************************************
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+\******************************************************************************/
+
+#include "chatbox.h"
+
+/* Implementation *************************************************************/
+CChatBox::CChatBox(QObject* parent)
+ : QObject(parent)
+{
+}
+
+QString CChatBox::chatHistory() const
+{
+ return m_chatHistory;
+}
+
+void CChatBox::setChatHistory(const QString& newChat)
+{
+ if (m_chatHistory != newChat)
+ {
+ m_chatHistory = newChat;
+ emit chatHistoryChanged();
+ }
+}
+
+void CChatBox::sendMessage(const QString& msg)
+{
+ if (msg.isEmpty())
+ return;
+
+ emit NewLocalInputText ( msg );
+
+ qDebug() << "New message sent:" << msg;
+}
+
+
+
+void CChatBox::clearChatHistory()
+{
+ // clear chat window
+ setChatHistory("");
+}
+
+void CChatBox::AddChatText ( QString strChatText )
+{
+ // notify accessibility plugin that text has changed
+ // QAccessible::updateAccessibility ( new QAccessibleValueChangeEvent ( txvChatWindow, strChatText ) );
+
+ // analyze strChatText to check if hyperlink (limit ourselves to http(s)://) but do not
+ // replace the hyperlinks if any HTML code for a hyperlink was found (the user has done the HTML
+ // coding hisself and we should not mess with that)
+ if ( !strChatText.contains ( QRegularExpression ( "href\\s*=|src\\s*=" ) ) )
+ {
+ // searches for all occurrences of http(s) and cuts until a space (\S matches any non-white-space
+ // character and the + means that matches the previous element one or more times.)
+ // This regex now contains three parts:
+ // - https?://\\S+ matches as much non-whitespace as possible after the http:// or https://,
+ // subject to the next two parts, which exclude terminating punctuation
+ // - (??\\[\\]{}]) is a negative look-behind assertion that disallows the match
+ // from ending with one of the characters !"'()+,.:;<=>?[]{}
+ // - (??\\[\\]{}]) is a negative look-behind assertion that disallows the match
+ // from ending with a ? followed by one of the characters !"'()+,.:;<=>?[]{}
+ // These last two parts must be separate, as a look-behind assertion must be fixed length.
+#define PUNCT_NOEND_URL "[!\"'()+,.:;<=>?\\[\\]{}]"
+ strChatText.replace ( QRegularExpression ( "(https?://\\S+(?\\1" );
+ }
+
+ // add new text in chat window
+ if (strChatText.isEmpty())
+ return;
+ // Append new message to existing history
+ m_chatHistory.append(strChatText + "
");
+ emit chatHistoryChanged();
+}
+
+// void CChatBox::OnAnchorClicked ( const QUrl& Url )
+// {
+// // only allow http(s) URLs to be opened in an external browser
+// if ( Url.scheme() == QLatin1String ( "https" ) || Url.scheme() == QLatin1String ( "http" ) )
+// {
+// if ( QMessageBox::question ( this,
+// APP_NAME,
+// tr ( "Do you want to open the link '%1' in your browser?" ).arg ( "" + Url.toString() + "" ),
+// QMessageBox::Yes | QMessageBox::No ) == QMessageBox::Yes )
+// {
+// QDesktopServices::openUrl ( Url );
+// }
+// }
+// }
diff --git a/src/chatdlg.h b/src/chatbox.h
similarity index 66%
rename from src/chatdlg.h
rename to src/chatbox.h
index 39aa8c2a76..97d0f0396d 100644
--- a/src/chatdlg.h
+++ b/src/chatbox.h
@@ -24,40 +24,39 @@
#pragma once
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+// #include
+// #include
+// #include
#include "global.h"
#include "util.h"
-#include "ui_chatdlgbase.h"
/* Classes ********************************************************************/
-class CChatDlg : public CBaseDlg, private Ui_CChatDlgBase
+class CChatBox: public QObject
{
Q_OBJECT
+ Q_PROPERTY(QString chatHistory READ chatHistory WRITE setChatHistory NOTIFY chatHistoryChanged)
+
public:
- CChatDlg ( QWidget* parent = nullptr );
+ explicit CChatBox(QObject* parent = nullptr);
+
+ // Accessors for the Q_PROPERTY
+ QString chatHistory() const;
+ void setChatHistory(const QString& newChat);
+
+ // QML calls this to send a message
+ Q_INVOKABLE void sendMessage(const QString& msg);
+ Q_INVOKABLE void clearChatHistory();
void AddChatText ( QString strChatText );
public slots:
- void OnSendText();
- void OnLocalInputTextTextChanged ( const QString& strNewText );
- void OnClearChatHistory();
- void OnAnchorClicked ( const QUrl& Url );
-#if defined( Q_OS_IOS ) || defined( ANDROID ) || defined( Q_OS_ANDROID )
- void OnCloseClicked();
-#endif
signals:
void NewLocalInputText ( QString strNewText );
+ void chatHistoryChanged();
+
+private:
+ QString m_chatHistory;
+
};
diff --git a/src/chatdlg.cpp b/src/chatdlg.cpp
deleted file mode 100644
index 4d7adcfd5c..0000000000
--- a/src/chatdlg.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/******************************************************************************\
- * Copyright (c) 2004-2024
- *
- * Author(s):
- * Volker Fischer
- *
- ******************************************************************************
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- *
-\******************************************************************************/
-
-#include "chatdlg.h"
-
-/* Implementation *************************************************************/
-CChatDlg::CChatDlg ( QWidget* parent ) : CBaseDlg ( parent, Qt::Window ) // use Qt::Window to get min/max window buttons
-{
- setupUi ( this );
-
- // Add help text to controls -----------------------------------------------
- // chat window
- txvChatWindow->setWhatsThis ( "" + tr ( "Chat Window" ) + ": " + tr ( "The chat window shows a history of all chat messages." ) );
-
- txvChatWindow->setAccessibleName ( tr ( "Chat history" ) );
-
- // input message text
- edtLocalInputText->setWhatsThis ( "" + tr ( "Input Message Text" ) + ": " +
- tr ( "Enter the chat message text in the edit box and press enter to send the "
- "message to the server which distributes the message to all connected "
- "clients. Your message will then show up in the chat window." ) );
-
- edtLocalInputText->setAccessibleName ( tr ( "New chat text edit box" ) );
-
- // clear chat window and edit line
- txvChatWindow->clear();
- edtLocalInputText->clear();
-
- // we do not want to show a cursor in the chat history
- txvChatWindow->setCursorWidth ( 0 );
-
- // set a placeholder text to make sure where to type the message in (#384)
- edtLocalInputText->setPlaceholderText ( tr ( "Type a message here" ) );
-
- // Menu -------------------------------------------------------------------
- QMenuBar* pMenu = new QMenuBar ( this );
- QMenu* pEditMenu = new QMenu ( tr ( "&Edit" ), this );
-
- pEditMenu->addAction ( tr ( "Cl&ear Chat History" ), this, SLOT ( OnClearChatHistory() ), QKeySequence ( Qt::CTRL + Qt::Key_E ) );
-
- pMenu->addMenu ( pEditMenu );
-#if defined( Q_OS_IOS )
- QAction* closeAction = pMenu->addAction ( tr ( "&Close" ) );
-#endif
-
-#if defined( ANDROID ) || defined( Q_OS_ANDROID )
- pEditMenu->addAction ( tr ( "&Close" ), this, SLOT ( OnCloseClicked() ), QKeySequence ( Qt::CTRL + Qt::Key_W ) );
-#endif
-
- // Now tell the layout about the menu
- layout()->setMenuBar ( pMenu );
-
- // Connections -------------------------------------------------------------
- QObject::connect ( edtLocalInputText, &QLineEdit::textChanged, this, &CChatDlg::OnLocalInputTextTextChanged );
-
- QObject::connect ( butSend, &QPushButton::clicked, this, &CChatDlg::OnSendText );
-
- QObject::connect ( txvChatWindow, &QTextBrowser::anchorClicked, this, &CChatDlg::OnAnchorClicked );
-
-#if defined( Q_OS_IOS )
- QObject::connect ( closeAction, &QAction::triggered, this, &CChatDlg::OnCloseClicked );
-#endif
-}
-
-void CChatDlg::OnLocalInputTextTextChanged ( const QString& strNewText )
-{
- // check and correct length
- if ( strNewText.length() > MAX_LEN_CHAT_TEXT )
- {
- // text is too long, update control with shortened text
- edtLocalInputText->setText ( strNewText.left ( MAX_LEN_CHAT_TEXT ) );
- }
-}
-
-void CChatDlg::OnSendText()
-{
- // send new text and clear line afterwards, do not send an empty message
- if ( !edtLocalInputText->text().isEmpty() )
- {
- emit NewLocalInputText ( edtLocalInputText->text() );
- edtLocalInputText->clear();
- }
-}
-
-void CChatDlg::OnClearChatHistory()
-{
- // clear chat window
- txvChatWindow->clear();
-}
-
-void CChatDlg::AddChatText ( QString strChatText )
-{
- // notify accessibility plugin that text has changed
- QAccessible::updateAccessibility ( new QAccessibleValueChangeEvent ( txvChatWindow, strChatText ) );
-
- // analyze strChatText to check if hyperlink (limit ourselves to http(s)://) but do not
- // replace the hyperlinks if any HTML code for a hyperlink was found (the user has done the HTML
- // coding hisself and we should not mess with that)
- if ( !strChatText.contains ( QRegularExpression ( "href\\s*=|src\\s*=" ) ) )
- {
- // searches for all occurrences of http(s) and cuts until a space (\S matches any non-white-space
- // character and the + means that matches the previous element one or more times.)
- // This regex now contains three parts:
- // - https?://\\S+ matches as much non-whitespace as possible after the http:// or https://,
- // subject to the next two parts, which exclude terminating punctuation
- // - (??\\[\\]{}]) is a negative look-behind assertion that disallows the match
- // from ending with one of the characters !"'()+,.:;<=>?[]{}
- // - (??\\[\\]{}]) is a negative look-behind assertion that disallows the match
- // from ending with a ? followed by one of the characters !"'()+,.:;<=>?[]{}
- // These last two parts must be separate, as a look-behind assertion must be fixed length.
-#define PUNCT_NOEND_URL "[!\"'()+,.:;<=>?\\[\\]{}]"
- strChatText.replace ( QRegularExpression ( "(https?://\\S+(?\\1" );
- }
-
- // add new text in chat window
- txvChatWindow->append ( strChatText );
-}
-
-void CChatDlg::OnAnchorClicked ( const QUrl& Url )
-{
- // only allow http(s) URLs to be opened in an external browser
- if ( Url.scheme() == QLatin1String ( "https" ) || Url.scheme() == QLatin1String ( "http" ) )
- {
- if ( QMessageBox::question ( this,
- APP_NAME,
- tr ( "Do you want to open the link '%1' in your browser?" ).arg ( "" + Url.toString() + "" ),
- QMessageBox::Yes | QMessageBox::No ) == QMessageBox::Yes )
- {
- QDesktopServices::openUrl ( Url );
- }
- }
-}
-
-#if defined( Q_OS_IOS ) || defined( ANDROID ) || defined( Q_OS_ANDROID )
-void CChatDlg::OnCloseClicked()
-{
- // on mobile add a close button or menu entry
-# if defined( Q_OS_IOS )
- // On Qt6, iOS crashes if we call close() due to unknown reasons, therefore we just hide() the dialog. A Qt bug is suspected.
- // Checkout https://github.com/jamulussoftware/jamulus/pull/3413
- hide();
-# endif
-# if defined( ANDROID ) || defined( Q_OS_ANDROID )
- close();
-# endif
-}
-#endif
\ No newline at end of file
diff --git a/src/chatdlgbase.ui b/src/chatdlgbase.ui
deleted file mode 100644
index 7d59db9661..0000000000
--- a/src/chatdlgbase.ui
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
- CChatDlgBase
-
-
-
- 0
- 0
- 435
- 405
-
-
-
-
- 0
- 0
-
-
-
- Chat
-
-
-
- :/png/main/res/fronticon.png:/png/main/res/fronticon.png
-
-
- true
-
-
- -
-
-
- false
-
-
- Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
-
-
- false
-
-
- false
-
-
-
- -
-
-
-
-
-
- -
-
-
- &Send
-
-
- true
-
-
- true
-
-
-
-
-
-
-
-
- txvChatWindow
-
-
-
-
-
-
diff --git a/src/client.cpp b/src/client.cpp
index 8d61fd04eb..952c153750 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -32,17 +32,25 @@ CClient::CClient ( const quint16 iPortNumber,
const bool bNoAutoJackConnect,
const QString& strNClientName,
const bool bNEnableIPv6,
- const bool bNMuteMeInPersonalMix ) :
+ const bool bNMuteMeInPersonalMix,
+ const QString& strIniFileName,
+ const bool bMuteStream, // maybe
+ QList bCommandLineOptions
+ ) :
ChannelInfo(),
strClientName ( strNClientName ),
- Channel ( false ), /* we need a client channel -> "false" */
+ pSettings( this, strIniFileName ),
+ audioMixerBoard( &pSettings, this ), /* we need a client channel -> "false" */
+ chatBox(),
+ CommandLineOptions(bCommandLineOptions),
+ Channel ( false ),
CurOpusEncoder ( nullptr ),
CurOpusDecoder ( nullptr ),
eAudioCompressionType ( CT_OPUS ),
- iCeltNumCodedBytes ( OPUS_NUM_BYTES_MONO_LOW_QUALITY ),
- iOPUSFrameSizeSamples ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ),
- eAudioQuality ( AQ_NORMAL ),
- eAudioChannelConf ( CC_MONO ),
+ iCeltNumCodedBytes ( OPUS_NUM_BYTES_MONO_LOW_QUALITY ), // default should be high quality
+ iOPUSFrameSizeSamples ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ), // stereo as default
+ eAudioQuality ( AQ_HIGH ),
+ eAudioChannelConf ( CC_STEREO ),
iNumAudioChannels ( 1 ),
bIsInitializationPhase ( true ),
bMuteOutStream ( false ),
@@ -50,8 +58,6 @@ CClient::CClient ( const quint16 iPortNumber,
Socket ( &Channel, iPortNumber, iQosNumber, "", bNEnableIPv6 ),
Sound ( AudioCallback, this, strMIDISetup, bNoAutoJackConnect, strNClientName ),
iAudioInFader ( AUD_FADER_IN_MIDDLE ),
- bReverbOnLeftChan ( false ),
- iReverbLevel ( 0 ),
iInputBoost ( 1 ),
iSndCrdPrefFrameSizeFactor ( FRAME_SIZE_FACTOR_DEFAULT ),
iSndCrdFrameSizeFactor ( FRAME_SIZE_FACTOR_DEFAULT ),
@@ -60,15 +66,16 @@ CClient::CClient ( const quint16 iPortNumber,
bFraSiFactPrefSupported ( false ),
bFraSiFactDefSupported ( false ),
bFraSiFactSafeSupported ( false ),
- eGUIDesign ( GD_ORIGINAL ),
- eMeterStyle ( MT_LED_STRIPE ),
bEnableAudioAlerts ( false ),
bEnableOPUS64 ( false ),
bJitterBufferOK ( true ),
bEnableIPv6 ( bNEnableIPv6 ),
bMuteMeInPersonalMix ( bNMuteMeInPersonalMix ),
- iServerSockBufNumFrames ( DEF_NET_BUF_SIZE_NUM_BL ),
- pSignalHandler ( CSignalHandler::getSingletonP() )
+ iServerSockBufNumFrames ( DEF_NET_BUF_SIZE_NUM_BL ), // Construct inputMeterL
+ pSignalHandler ( CSignalHandler::getSingletonP() ), // Construct inputMeterR
+ strServerName ( "" ),
+ m_inputMeterL(), // Construct mixerBoard object
+ m_inputMeterR() // start with clean chatbox
{
int iOpusError;
@@ -120,12 +127,13 @@ CClient::CClient ( const quint16 iPortNumber,
// The first ConClientListMesReceived handler performs the necessary cleanup and has to run first:
QObject::connect ( &Channel, &CChannel::ConClientListMesReceived, this, &CClient::OnConClientListMesReceived );
+ QObject::connect ( &Channel, &CChannel::ConClientListMesReceived, this, &CClient::ConClientListMesReceived );
QObject::connect ( &Channel, &CChannel::Disconnected, this, &CClient::Disconnected );
QObject::connect ( &Channel, &CChannel::NewConnection, this, &CClient::OnNewConnection );
- QObject::connect ( &Channel, &CChannel::ChatTextReceived, this, &CClient::ChatTextReceived );
+ QObject::connect ( &Channel, &CChannel::ChatTextReceived, this, &CClient::OnChatTextReceived );
QObject::connect ( &Channel, &CChannel::ClientIDReceived, this, &CClient::OnClientIDReceived );
@@ -133,9 +141,9 @@ CClient::CClient ( const quint16 iPortNumber,
QObject::connect ( &Channel, &CChannel::LicenceRequired, this, &CClient::LicenceRequired );
- QObject::connect ( &Channel, &CChannel::VersionAndOSReceived, this, &CClient::VersionAndOSReceived );
+ QObject::connect ( &Channel, &CChannel::VersionAndOSReceived, this, &CClient::OnVersionAndOSReceived );
- QObject::connect ( &Channel, &CChannel::RecorderStateReceived, this, &CClient::RecorderStateReceived );
+ QObject::connect ( &Channel, &CChannel::RecorderStateReceived, this, &CClient::OnRecorderStateReceived );
QObject::connect ( &ConnLessProtocol, &CProtocol::CLMessReadyForSending, this, &CClient::OnSendCLProtMessage );
@@ -151,7 +159,7 @@ CClient::CClient ( const quint16 iPortNumber,
QObject::connect ( &ConnLessProtocol, &CProtocol::CLDisconnection, this, &CClient::OnCLDisconnection );
- QObject::connect ( &ConnLessProtocol, &CProtocol::CLVersionAndOSReceived, this, &CClient::CLVersionAndOSReceived );
+ QObject::connect ( &ConnLessProtocol, &CProtocol::CLVersionAndOSReceived, this, &CClient::OnCLVersionAndOSReceived );
QObject::connect ( &ConnLessProtocol, &CProtocol::CLChannelLevelListReceived, this, &CClient::OnCLChannelLevelListReceived );
@@ -176,9 +184,9 @@ CClient::CClient ( const quint16 iPortNumber,
PreciseTime.start();
// set gain delay timer to single-shot and connect handler function
- TimerGainOrPan.setSingleShot ( true );
+ TimerGain.setSingleShot ( true );
- QObject::connect ( &TimerGainOrPan, &QTimer::timeout, this, &CClient::OnTimerRemoteChanGainOrPan );
+ QObject::connect ( &TimerGain, &QTimer::timeout, this, &CClient::OnTimerRemoteChanGain );
// start the socket (it is important to start the socket after all
// initializations and connections)
@@ -190,6 +198,61 @@ CClient::CClient ( const quint16 iPortNumber,
SetServerAddr ( strConnOnStartupAddress );
Start();
}
+
+ // -----------------------------------------------------------
+ // NOW we do what WAS done (or equivalent) in clientdlg constructor...
+
+ // CREATE inputMeterL and inputMeterR objects
+ m_inputMeterL = new CLevelMeter(this);
+ m_inputMeterR = new CLevelMeter(this);
+
+ //IF load settings, do it here
+ pSettings.Load ( CommandLineOptions );
+ emit pSettings.updateSettings();
+
+ // MainMixerBoard.SetNumMixerPanelRows ( pSettings->iNumMixerPanelRows );
+ audioMixerBoard.SetMIDICtrlUsed ( !strMIDISetup.isEmpty() );
+
+ // setup timers
+ TimerCheckAudioDeviceOk.setSingleShot ( true ); // only check once after connection
+ TimerDetectFeedback.setSingleShot ( true );
+
+ // Connect on startup ------------------------------------------------------
+ if ( !strConnOnStartupAddress.isEmpty() )
+ {
+ // initiate connection (always show the address in the mixer board
+ // (no alias))
+ Connect ( strConnOnStartupAddress );
+ }
+
+ // All Connections
+ // timers
+ QObject::connect ( &TimerSigMet, &QTimer::timeout, this, &CClient::OnTimerSigMet );
+ QObject::connect ( &TimerBuffersLED, &QTimer::timeout, this, &CClient::OnTimerBuffersLED );
+ QObject::connect ( &TimerPing, &QTimer::timeout, this, &CClient::OnTimerPing );
+ QObject::connect ( &TimerCheckAudioDeviceOk, &QTimer::timeout, this, &CClient::OnTimerCheckAudioDeviceOk );
+ QObject::connect ( &TimerDetectFeedback, &QTimer::timeout, this, &CClient::OnTimerDetectFeedback );
+ QObject::connect ( &TimerStatus, &QTimer::timeout, this, &CClient::OnTimerStatus );
+ // client-client connections //TODO: tidy
+ QObject::connect ( this, &CClient::Disconnected, this, &CClient::OnDisconnected );
+ QObject::connect ( this, &CClient::PingTimeReceived, this, &CClient::OnPingTimeResult );
+ QObject::connect ( this, &CClient::SoundDeviceChanged, this, &CClient::OnSoundDeviceChanged );
+ // Mixerboard updates
+ QObject::connect ( &audioMixerBoard, &CAudioMixerBoard::ChangeChanGain, this, &CClient::OnChangeChanGain );
+ QObject::connect ( &audioMixerBoard, &CAudioMixerBoard::ChangeChanPan, this, &CClient::OnChangeChanPan );
+ QObject::connect ( &audioMixerBoard, &CAudioMixerBoard::NumClientsChanged, this, &CClient::OnNumClientsChanged );
+ // chatbox
+ QObject::connect ( &chatBox, &CChatBox::NewLocalInputText, this, &CClient::OnNewLocalInputText );
+
+ // Post Connections init
+ // start timer for status bar
+ TimerStatus.start ( LED_BAR_UPDATE_TIME_MS );
+
+ if ( bMuteStream )
+ {
+ this->setMuteOut(true);
+ }
+
}
CClient::~CClient()
@@ -215,6 +278,27 @@ CClient::~CClient()
opus_custom_mode_destroy ( Opus64Mode );
}
+bool CClient::jitterWarn()
+{
+ return m_jitterWarn;
+}
+
+void CClient::setJitterWarn( bool warn )
+{
+ if (m_jitterWarn != warn) {
+ m_jitterWarn = warn;
+ emit jitterWarnChanged();
+ }
+}
+
+void CClient::setSessionStatus(QString strName)
+{
+ if ( m_sessionStatus != strName ) {
+ m_sessionStatus = strName;
+ emit sessionStatusChanged();
+ }
+}
+
void CClient::OnSendProtMessage ( CVector vecMessage )
{
// the protocol queries me to call the function to send the message
@@ -258,10 +342,22 @@ void CClient::OnJittBufSizeChanged ( int iNewJitBufSize )
// to the server which is incorrect.
iServerSockBufNumFrames = iNewJitBufSize;
}
+
+ // update QML
+ pSettings.UpdateJitterBufferFrame();
}
void CClient::OnNewConnection()
{
+ // The oldGain and newGain arrays are used to avoid sending duplicate gain change messages.
+ // As these values depend on the channel IDs of a specific server, we have
+ // to reset those upon connect.
+ // We reset to 1 because this is what the server part sets by default.
+ for ( int iId = 0; iId < MAX_NUM_CHANNELS; iId++ )
+ {
+ oldGain[iId] = newGain[iId] = 1;
+ }
+
// a new connection was successfully initiated, send infos and request
// connected clients list
Channel.SetRemoteInfo ( ChannelInfo );
@@ -281,91 +377,36 @@ void CClient::OnNewConnection()
//### TODO: END ###//
}
-void CClient::OnMuteStateHasChangedReceived ( int iServerChanID, bool bIsMuted )
-{
- // map iChanID from server channel ID to client channel ID
- int iChanID = FindClientChannel ( iServerChanID, false );
-
- if ( iChanID != INVALID_INDEX )
- {
- emit MuteStateHasChangedReceived ( iChanID, bIsMuted );
- }
-}
-
-void CClient::OnCLChannelLevelListReceived ( CHostAddress InetAddr, CVector vecLevelList )
+void CClient::OnConClientListMesReceived ( CVector vecChanInfo )
{
- // reorder levels from server channel order to client channel order
+ // Upon receiving a new client list, we have to reset oldGain and newGain
+ // entries for unused channels. This ensures that a disconnected channel
+ // does not leave behind wrong cached gain values which would leak into
+ // any new channel which reused this channel id.
+ int iNumConnectedClients = vecChanInfo.Size();
- if ( ReorderLevelList ( vecLevelList ) )
+ // Save what channel IDs are in use:
+ bool bChanIdInUse[MAX_NUM_CHANNELS] = {};
+ for ( int i = 0; i < iNumConnectedClients; i++ )
{
- emit CLChannelLevelListReceived ( InetAddr, vecLevelList );
+ bChanIdInUse[vecChanInfo[i].iChanID] = true;
}
-}
-
-void CClient::OnConClientListMesReceived ( CVector vecChanInfo )
-{
- // translate from server channel IDs to client channel IDs
- // ALSO here is where we allocate and free client channels as required
-
- const int iNumConnectedClients = vecChanInfo.Size();
- int i, iSrvIdx;
-
- // on a new connection, a server sends an empty channel list before sending
- // the real channel list (see #1010). To avoid this discarding "our" channel
- // that we have just created, we skip this processing and just pass the empty
- // list to the emitted signal.
- if ( iNumConnectedClients != 0 )
+ // Reset all gains for unused channel IDs:
+ for ( int iId = 0; iId < MAX_NUM_CHANNELS; iId++ )
{
- // this relies on the received client list being in order of server channel ID
-
- for ( i = 0, iSrvIdx = 0; i < iNumConnectedClients && iSrvIdx < MAX_NUM_CHANNELS; )
- {
- // server channel ID of this entry
- const int iServerChannelID = vecChanInfo[i].iChanID;
-
- // find matching client channel ID, creating new if necessary,
- // update channel number to be client-side
- vecChanInfo[i].iChanID = FindClientChannel ( iServerChannelID, true );
-
- // discard any lower server channels that are no longer in our local list
- while ( iSrvIdx < iServerChannelID )
- {
- const int iId = FindClientChannel ( iSrvIdx, false );
-
- if ( iId != INVALID_INDEX )
- {
- // iSrvIdx contains a server channel number that has now gone
- FreeClientChannel ( iSrvIdx );
- }
- iSrvIdx++;
- }
-
- i++; // next list entry
- iSrvIdx++; // next local server channel
- }
-
- // have now run out of active channels, discard any remaining from our local list
- // note that iActiveChannels will reduce as remaining channels are freed
-
- while ( iActiveChannels > iNumConnectedClients && iSrvIdx < MAX_NUM_CHANNELS )
+ if ( !bChanIdInUse[iId] )
{
- const int iId = FindClientChannel ( iSrvIdx, false );
-
- if ( iId != INVALID_INDEX )
- {
- // iSrvIdx contains a server channel number that has now gone
- FreeClientChannel ( iSrvIdx );
- }
- iSrvIdx++;
+ // reset oldGain and newGain as this channel id is currently unused and will
+ // start with a server-side gain at 1 (100%) again.
+ oldGain[iId] = newGain[iId] = 1;
}
-
- Q_ASSERT ( iActiveChannels == iNumConnectedClients );
}
- // pass the received list onwards, now containing client channel IDs
-
- emit ConClientListMesReceived ( vecChanInfo );
+ // update mixer board with the additional client infos
+ audioMixerBoard.ApplyNewConClientList( vecChanInfo );
+ // set session status
+ setSessionStatus("CONNECTED");
}
void CClient::CreateServerJitterBufferMessage()
@@ -431,30 +472,27 @@ void CClient::SetDoAutoSockBufSize ( const bool bValue )
CreateServerJitterBufferMessage();
}
-// In order not to flood the server with gain or pan change messages, particularly when using
+// In order not to flood the server with gain change messages, particularly when using
// a MIDI controller, a timer is used to limit the rate at which such messages are generated.
// This avoids a potential long backlog of messages, since each must be ACKed before the next
// can be sent, and this ACK is subject to the latency of the server connection.
//
-// When the first gain or pan change message is requested after an idle period (i.e. the timer is not
-// running), it will be sent immediately, and a timer started. The timer period is dependent on
-// the current ping time to the remote server.
+// When the first gain change message is requested after an idle period (i.e. the timer is not
+// running), it will be sent immediately, and a 300ms timer started.
//
-// If a gain or pan change message is requested while the timer is still running, the new value is not sent,
-// but just stored in newGain or newPan within clientChannels[iId], and the minGainOrPanId and maxGainOrPanId
-// updated to note the range of IDs that must be checked when the time expires (this will usually be a single
-// channel unless channel grouping is being used). This avoids having to check all possible channels.
+// If a gain change message is requested while the timer is still running, the new gain is not sent,
+// but just stored in newGain[iId], and the minGainId and maxGainId updated to note the range of
+// IDs that must be checked when the time expires (this will usually be a single channel
+// unless channel grouping is being used). This avoids having to check all possible channels.
//
-// When the timer fires, the channels minGainOrPanId <= iId < maxGainOrPanId are checked by comparing the
-// last sent values in oldGain or oldPan with any pending values in newGain or newPan, and if they differ,
-// the new value is sent, updating oldGain or oldPan with the sent value. If any new values are sent,
-// the timer is restarted so that further immediate updates will be pended.
+// When the timer fires, the channels minGainId <= iId < maxGainId are checked by comparing
+// the last sent value in oldGain[iId] with any pending value in newGain[iId], and if they differ,
+// the new value is sent, updating oldGain[iId] with the sent value. If any new values are
+// sent, the timer is restarted so that further immediate updates will be pended.
void CClient::SetRemoteChanGain ( const int iId, const float fGain, const bool bIsMyOwnFader )
{
- QMutexLocker locker ( &MutexGainOrPan );
-
- CClientChannel* clientChan = &clientChannels[iId];
+ QMutexLocker locker ( &MutexGain );
// if this gain is for my own channel, apply the value for the Mute Myself function
if ( bIsMyOwnFader )
@@ -462,108 +500,69 @@ void CClient::SetRemoteChanGain ( const int iId, const float fGain, const bool b
fMuteOutStreamGain = fGain;
}
- if ( TimerGainOrPan.isActive() )
+ if ( TimerGain.isActive() )
{
// just update the new value for sending later;
- // will compare with oldGain when the timer fires
- clientChan->newGain = fGain;
+ // will compare with oldGain[iId] when the timer fires
+ newGain[iId] = fGain;
// update range of channel IDs to check in the timer
- if ( iId < minGainOrPanId )
- minGainOrPanId = iId; // first value to check
- if ( iId >= maxGainOrPanId )
- maxGainOrPanId = iId + 1; // first value NOT to check
+ if ( iId < minGainId )
+ minGainId = iId; // first value to check
+ if ( iId >= maxGainId )
+ maxGainId = iId + 1; // first value NOT to check
return;
}
// here the timer was not active:
// send the actual gain and reset the range of channel IDs to empty
- clientChan->oldGain = clientChan->newGain = fGain;
- Channel.SetRemoteChanGain ( clientChan->iServerChannelID, fGain ); // translate client channel to server channel ID
+ oldGain[iId] = newGain[iId] = fGain;
+ Channel.SetRemoteChanGain ( iId, fGain );
- StartTimerGainOrPan();
+ StartDelayTimer();
}
-void CClient::OnTimerRemoteChanGainOrPan()
+void CClient::OnTimerRemoteChanGain()
{
- QMutexLocker locker ( &MutexGainOrPan );
+ QMutexLocker locker ( &MutexGain );
bool bSent = false;
- for ( int iId = minGainOrPanId; iId < maxGainOrPanId; iId++ )
+ for ( int iId = minGainId; iId < maxGainId; iId++ )
{
- CClientChannel* clientChan = &clientChannels[iId];
-
- if ( clientChan->newGain != clientChan->oldGain )
+ if ( newGain[iId] != oldGain[iId] )
{
// send new gain and record as old gain
- float fGain = clientChan->oldGain = clientChan->newGain;
- Channel.SetRemoteChanGain ( clientChan->iServerChannelID, fGain ); // translate client channel to server channel ID
- bSent = true;
- }
-
- if ( clientChan->newPan != clientChan->oldPan )
- {
- // send new pan and record as old pan
- float fPan = clientChan->oldPan = clientChan->newPan;
- Channel.SetRemoteChanPan ( clientChan->iServerChannelID, fPan ); // translate client channel to server channel ID
+ float fGain = oldGain[iId] = newGain[iId];
+ Channel.SetRemoteChanGain ( iId, fGain );
bSent = true;
}
}
- // if a new gain or pan has been sent, reset the range of channel IDs to empty and start timer
+ // if a new gain has been sent, reset the range of channel IDs to empty and start timer
if ( bSent )
{
- StartTimerGainOrPan();
+ StartDelayTimer();
}
}
// reset the range of channel IDs to check and start the delay timer
-void CClient::StartTimerGainOrPan()
+void CClient::StartDelayTimer()
{
- maxGainOrPanId = 0;
- minGainOrPanId = MAX_NUM_CHANNELS;
+ maxGainId = 0;
+ minGainId = MAX_NUM_CHANNELS;
// start timer to delay sending further updates
// use longer delay when connected to server with higher ping time,
// double the ping time in order to allow a bit of overhead for other messages
if ( iCurPingTime < DEFAULT_GAIN_DELAY_PERIOD_MS / 2 )
{
- TimerGainOrPan.start ( DEFAULT_GAIN_DELAY_PERIOD_MS );
+ TimerGain.start ( DEFAULT_GAIN_DELAY_PERIOD_MS );
}
else
{
- TimerGainOrPan.start ( iCurPingTime * 2 );
- }
-}
-
-void CClient::SetRemoteChanPan ( const int iId, const float fPan )
-{
- QMutexLocker locker ( &MutexGainOrPan );
-
- CClientChannel* clientChan = &clientChannels[iId];
-
- if ( TimerGainOrPan.isActive() )
- {
- // just update the new value for sending later;
- // will compare with oldPan when the timer fires
- clientChan->newPan = fPan;
-
- // update range of channel IDs to check in the timer
- if ( iId < minGainOrPanId )
- minGainOrPanId = iId; // first value to check
- if ( iId >= maxGainOrPanId )
- maxGainOrPanId = iId + 1; // first value NOT to check
-
- return;
+ TimerGain.start ( iCurPingTime * 2 );
}
-
- // here the timer was not active:
- // send the actual gain and reset the range of channel IDs to empty
- clientChan->oldPan = clientChan->newPan = fPan;
- Channel.SetRemoteChanPan ( clientChan->iServerChannelID, fPan ); // translate client channel to server channel ID
-
- StartTimerGainOrPan();
}
bool CClient::SetServerAddr ( QString strNAddr )
@@ -607,6 +606,7 @@ bool CClient::GetAndResetbJitterBufferOKFlag()
// since per definition the jitter buffer status is OK if both the
// put and get status are OK
return bSocketJitBufOKFlag;
+
}
void CClient::SetSndCrdPrefFrameSizeFactor ( const int iNewFactor )
@@ -722,6 +722,8 @@ QString CClient::SetSndCrdDev ( const QString strNewDev )
if ( !strError.isEmpty() )
{
emit SoundDeviceChanged ( strError );
+
+ emit pSettings.slSndCrdDevChanged();
}
return strError;
@@ -893,7 +895,7 @@ void CClient::OnControllerInFaderLevel ( int iChannelIdx, int iValue )
}
#endif
- emit ControllerInFaderLevel ( iChannelIdx, iValue );
+ audioMixerBoard.SetFaderLevel ( iChannelIdx, iValue );
}
void CClient::OnControllerInPanValue ( int iChannelIdx, int iValue )
@@ -905,7 +907,7 @@ void CClient::OnControllerInPanValue ( int iChannelIdx, int iValue )
SetRemoteChanPan ( iChannelIdx, static_cast ( iValue ) / AUD_MIX_PAN_MAX );
#endif
- emit ControllerInPanValue ( iChannelIdx, iValue );
+ audioMixerBoard.SetPanValue ( iChannelIdx, iValue );
}
void CClient::OnControllerInFaderIsSolo ( int iChannelIdx, bool bIsSolo )
@@ -916,7 +918,7 @@ void CClient::OnControllerInFaderIsSolo ( int iChannelIdx, bool bIsSolo )
// FIXME: no idea what to do here.
#endif
- emit ControllerInFaderIsSolo ( iChannelIdx, bIsSolo );
+ audioMixerBoard.SetFaderIsSolo ( iChannelIdx, bIsSolo );
}
void CClient::OnControllerInFaderIsMute ( int iChannelIdx, bool bIsMute )
@@ -927,7 +929,7 @@ void CClient::OnControllerInFaderIsMute ( int iChannelIdx, bool bIsMute )
// FIXME: no idea what to do here.
#endif
- emit ControllerInFaderIsMute ( iChannelIdx, bIsMute );
+ audioMixerBoard.SetFaderIsMute ( iChannelIdx, bIsMute );
}
void CClient::OnControllerInMuteMyself ( bool bMute )
@@ -938,23 +940,11 @@ void CClient::OnControllerInMuteMyself ( bool bMute )
// FIXME: no idea what to do here.
#endif
- emit ControllerInMuteMyself ( bMute );
+ this->setMuteOut( bMute );
}
-void CClient::OnClientIDReceived ( int iServerChanID )
+void CClient::OnClientIDReceived ( int iChanID )
{
- // if we have just connected to a running server, iActiveChannels will be 0
- // if iActiveChannels is not 0, the server must have been restarted on the fly
- // in that case, channels might have changed, so clear our list to get it afresh.
- if ( iActiveChannels != 0 )
- {
- qInfo() << "> Server restarted?";
- ClearClientChannels();
- }
-
- // allocate and map client-side channel 0
- int iChanID = FindClientChannel ( iServerChanID, true ); // should always return channel 0
-
// for headless mode we support to mute our own signal in the personal mix
// (note that the check for headless is done in the main.cpp and must not
// be checked here)
@@ -963,7 +953,7 @@ void CClient::OnClientIDReceived ( int iServerChanID )
SetRemoteChanGain ( iChanID, 0, false );
}
- emit ClientIDReceived ( iChanID );
+ audioMixerBoard.SetMyChannelID ( iChanID );
}
void CClient::Start()
@@ -971,9 +961,6 @@ void CClient::Start()
// init object
Init();
- // initialise client channels
- ClearClientChannels();
-
// enable channel
Channel.SetEnable ( true );
@@ -1205,9 +1192,6 @@ void CClient::Init()
// set the channel network properties
Channel.SetAudioStreamProperties ( eAudioCompressionType, iCeltNumCodedBytes, iSndCrdFrameSizeFactor, iNumAudioChannels );
- // init reverberation
- AudioReverb.Init ( eAudioChannelConf, iStereoBlockSizeSam, SYSTEM_SAMPLE_RATE_HZ );
-
// init the sound card conversion buffers
if ( bSndCrdConversionBufferRequired )
{
@@ -1300,12 +1284,6 @@ void CClient::ProcessAudioDataIntern ( CVector& vecsStereoSndCrd )
SignalLevelMeter.Update ( vecsStereoSndCrd, iMonoBlockSizeSam, true );
#endif
- // add reverberation effect if activated
- if ( iReverbLevel != 0 )
- {
- AudioReverb.Process ( vecsStereoSndCrd, bReverbOnLeftChan, static_cast ( iReverbLevel ) / AUD_REVERB_MAX / 4 );
- }
-
// apply pan (audio fader) and mix mono signals
if ( !( ( iAudioInFader == AUD_FADER_IN_MIDDLE ) && ( eAudioChannelConf == CC_STEREO ) ) )
{
@@ -1494,183 +1472,391 @@ int CClient::EstimatedOverallDelay ( const int iPingTimeMs )
return MathUtils::round ( fTotalBufferDelayMs + iPingTimeMs );
}
-// Management of Client Channels and mapping to/from Server Channels
+void CClient::onConnectButtonClicked()
+{
+ // set off the connect process
+ strSelectedAddress = NetworkUtil::FixAddress ( strSelectedAddress );
+
+ if ( !strSelectedAddress.isEmpty() )
+ {
+ // store new address at the top of the list, if the list was already
+ // full, the last element is thrown out
+ pSettings.vstrIPAddress.StringFiFoWithCompare ( strSelectedAddress );
+ }
+
+ // first check if we are already connected, if this is the case we have to
+ // disconnect the old server first
+ if ( IsRunning() )
+ {
+ Disconnect();
+ }
+
+ // initiate connection
+ Connect ( strSelectedAddress );
+
+}
+
+
+void CClient::onDisconnectButtonClicked()
+{
+ qDebug() << "Disconnecting...";
+
+ if ( IsRunning() )
+ {
+ Disconnect();
+ }
+}
-void CClient::ClearClientChannels()
+void CClient::OnTimerSigMet()
{
- QMutexLocker locker ( &MutexChannels );
+ // show current level
+ m_inputMeterL->setDoubleVal( GetLevelForMeterdBLeft() );
+ m_inputMeterR->setDoubleVal( GetLevelForMeterdBRight() );
- iActiveChannels = 0;
- iJoinSequence = 0;
+ if ( bDetectFeedback &&
+ ( GetLevelForMeterdBLeft() > NUM_STEPS_LED_BAR - 0.5 || GetLevelForMeterdBRight() > NUM_STEPS_LED_BAR - 0.5 ) )
+ {
+ // mute locally and mute channel
+ this->setMuteOut( true );
+ audioMixerBoard.MuteMyChannel();
- for ( int i = 0; i < MAX_NUM_CHANNELS; i++ )
+ qDebug() << "Feedback detected ... ";
+ // show message about feedback issue
+ setUserMsg( tr ( "Audio feedback or loud signal detected.\n\n"
+ "We muted your channel and activated 'Mute Myself'. Please solve "
+ "the feedback issue first and unmute yourself afterwards." ) );
+ }
+}
+
+void CClient::OnTimerBuffersLED()
+{
+ if ( GetAndResetbJitterBufferOKFlag() )
{
- clientChannels[i].iServerChannelID = INVALID_INDEX;
- // all other fields will be initialised on channel allocation
+ setJitterWarn( false ); // status OK, no warning
+ }
+ else
+ {
+ setJitterWarn( true ); // status BAD, give warning
+ }
+}
- clientChannelIDs[i] = INVALID_INDEX;
+void CClient::OnTimerCheckAudioDeviceOk()
+{
+ // check if the audio device entered the audio callback after a pre-defined
+ // timeout to check if a valid device is selected and if we do not have
+ // fundamental settings errors (in which case the GUI would only show that
+ // it is trying to connect the server which does not help to solve the problem (#129))
+ if ( !this->IsCallbackEntered() )
+ {
+ setUserMsg(tr ( "Your sound card is not working correctly. "
+ "Please open the settings dialog and check the device selection and the driver settings." ) );
}
+}
- // qInfo() << "> Client channel list cleared";
+void CClient::OnTimerDetectFeedback()
+{
+ bDetectFeedback = false;
}
-void CClient::FreeClientChannel ( const int iServerChannelID )
+
+void CClient::Connect( const QString& strAddress )
{
- QMutexLocker locker ( &MutexChannels );
+ // set address and check if address is valid
+ if ( SetServerAddr ( strAddress ) )
+ {
+ // try to start client, if error occurred, do not go in
+ // running state but show error message
+ try
+ {
+ if ( !IsRunning() )
+ {
+ Start();
+ }
+ }
- if ( iServerChannelID == INVALID_INDEX || iServerChannelID >= MAX_NUM_CHANNELS )
+ catch ( const CGenErr& generr )
+ {
+ // show error message and return the function
+ setUserMsg( generr.GetErrorText() );
+ return;
+ }
+
+ // set session status bar
+ emit sessionNameChanged();
+ emit sessionStatusChanged();
+ emit bConnectedChanged();
+
+ SetServerStatus ( "SESSION ACTIVE" );
+
+ // start timer for level meter bar and ping time measurement
+ TimerSigMet.start ( LEVELMETER_UPDATE_TIME_MS );
+ TimerBuffersLED.start ( BUFFER_LED_UPDATE_TIME_MS );
+ TimerPing.start ( PING_UPDATE_TIME_MS );
+ TimerCheckAudioDeviceOk.start ( CHECK_AUDIO_DEV_OK_TIME_MS ); // is single shot timer
+
+ // audio feedback detection
+ if ( pSettings.bEnableFeedbackDetection )
+ {
+ TimerDetectFeedback.start ( DETECT_FEEDBACK_TIME_MS ); // single shot timer
+ bDetectFeedback = true;
+ }
+
+ }
+}
+
+void CClient::Disconnect()
+{
+ // only stop client if currently running, in case we received
+ // the stopped message, the client is already stopped but the
+ // connect/disconnect button and other GUI controls must be
+ // updated
+ if ( IsRunning() )
{
- return;
+ Stop();
}
- const int iClientChannelID = clientChannelIDs[iServerChannelID];
+ SetServerStatus ( "" );
- Q_ASSERT ( clientChannels[iClientChannelID].iServerChannelID == iServerChannelID );
+ // stop timer for level meter bars and reset them
+ TimerSigMet.stop();
+ m_inputMeterL->setDoubleVal( 0 );
+ m_inputMeterR->setDoubleVal( 0 );
+ setJitterWarn(false);
- clientChannelIDs[iServerChannelID] = INVALID_INDEX;
- clientChannels[iClientChannelID].iServerChannelID = INVALID_INDEX;
+ // stop other timers
+ TimerBuffersLED.stop();
+ TimerPing.stop();
+ TimerCheckAudioDeviceOk.stop();
+ TimerDetectFeedback.stop();
+ bDetectFeedback = false;
- iActiveChannels -= 1;
+ // immediately update status bar
+ OnTimerStatus();
- /*
- qInfo() << qUtf8Printable ( QString ( "> Freed client ch %1 for server ch %2; chan count = %3" )
- .arg ( iClientChannelID )
- .arg ( iServerChannelID )
- .arg ( iActiveChannels ) );
- */
+ SetPingTime (0,0);
+
+ strSelectedAddress = "127.0.0.1"; //FIXME - temp default
+ emit sessionlinkTextChanged();
+ emit sessionNameChanged();
+ emit sessionStatusChanged();
+ emit recordingStatusChanged();
+ emit bConnectedChanged();
+
+ // clear mixer board (remove all faders)
+ audioMixerBoard.clear();
+}
+
+void CClient::SetPingTime(const int iPingTime, const int iOverallDelayMs)
+{
+ // apply values
+ m_pingVal = iPingTime;
+ m_delayVal = iOverallDelayMs;
+
+ emit pingValChanged();
+ emit delayValChanged();
}
-// find, and optionally create, a client channel for the supplied server channel ID
-// returns a client channel ID or INVALID_INDEX
-int CClient::FindClientChannel ( const int iServerChannelID, const bool bCreateIfNew )
+void CClient::SetServerStatus ( const QString& strNewServerName )
{
- QMutexLocker locker ( &MutexChannels );
+ // store the current server name
+ strServerName = strNewServerName;
- if ( iServerChannelID == INVALID_INDEX || iServerChannelID >= MAX_NUM_CHANNELS )
+ if ( strServerName.isEmpty() )
{
- return INVALID_INDEX;
+ // no connection or connection was reset: show default title
+ setSessionStatus("NO SESSION");
}
+ else
+ {
+ // Do not set the server name directly but first show a label which indicates
+ // that we are trying to connect the server
+ setSessionStatus("CONNECTING ...");
+ }
+}
- int iClientChannelID = clientChannelIDs[iServerChannelID];
+QString CClient::sessionlinkText()
+{
+ return Channel.GetAddress().toString();
+}
- if ( iClientChannelID != INVALID_INDEX )
- {
- Q_ASSERT ( clientChannels[iClientChannelID].iServerChannelID == iServerChannelID );
- return iClientChannelID;
+void CClient::setSessionlinkText( const QString& sessionUrlText )
+{
+ if ( strSelectedAddress == sessionUrlText )
+ return;
+
+ strSelectedAddress = sessionUrlText;
+ qDebug() << "set strSelectedAddress to: " << sessionUrlText;
+}
+
+QString CClient::userMsg() const
+{
+ return m_userMsg;
+}
+
+void CClient::setUserMsg(const QString &msg)
+{
+ if (m_userMsg != msg) {
+ m_userMsg = msg;
+ emit userMsgChanged();
}
+}
- // no matching client channel - create new one if requested
- if ( bCreateIfNew )
+void CClient::closeEvent ( QCloseEvent* Event )
+{
+ // if connected, terminate connection
+ if ( IsRunning() )
{
- // search clientChannels[] for a free client channel
- for ( iClientChannelID = 0; iClientChannelID < MAX_NUM_CHANNELS; iClientChannelID++ )
- {
- CClientChannel* clientChan = &clientChannels[iClientChannelID];
+ Stop();
+ }
- if ( clientChan->iServerChannelID == INVALID_INDEX )
- {
- clientChan->iServerChannelID = iServerChannelID;
- clientChan->iJoinSequence = ++iJoinSequence;
+ // make sure all current fader settings are applied to the settings struct
+ audioMixerBoard.StoreAllFaderSettings();
- clientChan->oldGain = clientChan->newGain = 1.0f;
- clientChan->oldPan = clientChan->newPan = 0.5f;
+ // pSettings->bConnectDlgShowAllMusicians = ConnectDlg.GetShowAllMusicians();
+ // pSettings->eChannelSortType = MainMixerBoard.GetFaderSorting();
+ // pSettings->iNumMixerPanelRows = MainMixerBoard.GetNumMixerPanelRows();
- clientChan->level = 0;
+ // default implementation of this event handler routine
+ Event->accept();
+}
- clientChannelIDs[iServerChannelID] = iClientChannelID;
- iActiveChannels += 1;
+void CClient::OnTimerPing()
+{
+ // send ping message to the server
+ CreateCLPingMes();
+}
- /*
- qInfo() << qUtf8Printable ( QString ( "> Alloc client ch %1 for server ch %2; chan count = %3" )
- .arg ( iClientChannelID )
- .arg ( iServerChannelID )
- .arg ( iActiveChannels ) );
- */
+void CClient::OnPingTimeResult ( int iPingTime )
+{
+ // // calculate overall delay
+ const int iOverallDelayMs = EstimatedOverallDelay ( iPingTime );
+
+ SetPingTime ( iPingTime, iOverallDelayMs );
+}
- return iClientChannelID; // new client channel ID
- }
- }
- }
- return INVALID_INDEX;
+void CClient::OnVersionAndOSReceived ( COSUtil::EOpSystemType, QString strVersion )
+{
+ ; // nothing for now
}
-// When the client receives a channel level list from the server, the list contains one value
-// for each currently-active channel, ordered by the channel ID assigned by the server.
-// The values will correspond to the active channels in the last client list that was sent.
-// This list is passed up to the mixer board, which will interpret the values in the order
-// of channels that it knows about.
-//
-// Since CClient is translating server channel IDs to local client channel IDs before
-// passing the client list up to the mixer board, it is also necessary to re-order the values
-// in the level list so that they are in order of mapped client channel ID.
-// This function performs that re-ordering by scanning the server channels in order, once,
-// for active channels, and storing the level value in the corresponding client channel.
-// Then the function scans the client channels in order, fetching the level values and putting
-// them back into vecLevelList in order of client channel. The mixer board will then display
-// the levels against the correct channels.
-//
-// The list size is checked against the current number of active channels to guard against
-// any unexpected temporary mismatch in size due to potential out-of-order message delivery.
-//
-// This function returns true if the list has been processed and should be passed on,
-// or false if it was the wrong size and should be discarded.
-bool CClient::ReorderLevelList ( CVector& vecLevelList )
+void CClient::OnCLVersionAndOSReceived ( CHostAddress, COSUtil::EOpSystemType, QString strVersion )
{
- QMutexLocker locker ( &MutexChannels );
+ // update check
+ int mySuffixIndex;
+ QVersionNumber myVersion = QVersionNumber::fromString ( VERSION, &mySuffixIndex );
+
+ int serverSuffixIndex;
+ QVersionNumber serverVersion = QVersionNumber::fromString ( strVersion, &serverSuffixIndex );
- // vecLevelList is sent from server ordered by server channel ID
- // re-order it by client channel ID before passing up to the GUI
- // the list is passed in by reference and modified in situ
+ // only compare if the server version has no suffix (such as dev or beta)
+ if ( strVersion.size() == serverSuffixIndex && QVersionNumber::compare ( serverVersion, myVersion ) > 0 )
+ {
+ // do nothing
+ ;
+ // show the label and hide it after one minute again
+ // lblUpdateCheck->show();
+ // QTimer::singleShot ( 60000, [this]() { lblUpdateCheck->hide(); } );
+ }
+}
- // check it is the right length
- if ( vecLevelList.Size() != iActiveChannels )
+void CClient::OnChatTextReceived ( QString strChatText )
+{
+ if ( pSettings.bEnableAudioAlerts )
{
- return false; // tell caller to ignore it
+ // QSoundEffect* sf = new QSoundEffect();
+ // sf->setSource ( QUrl::fromLocalFile ( ":sounds/res/sounds/new_message.wav" ) );
+ // sf->play();
+ ;
}
+ chatBox.AddChatText ( strChatText );
+}
- int iClientCh;
- int iServerCh = 0;
+void CClient::OnClearAllStoredSoloMuteSettings()
+{
+ // if we are in an active connection, we first have to store all fader settings in
+ // the settings struct, clear the solo and mute states and then apply the settings again
+ audioMixerBoard.StoreAllFaderSettings();
+ pSettings.vecStoredFaderIsSolo.Reset ( false );
+ pSettings.vecStoredFaderIsMute.Reset ( false );
+ audioMixerBoard.LoadAllFaderSettings();
+}
- // fetch levels by server channel ID
+void CClient::OnLoadChannelSetup()
+{
+ QString strFileName = "somefile.ini" ; //FIXME - QFileDialog::getOpenFileName ( this, tr ( "Select Channel Setup File" ), "", QString ( "*." ) + MIX_SETTINGS_FILE_SUFFIX );
- for ( int i = 0; i < iActiveChannels; i++ )
+ if ( !strFileName.isEmpty() )
{
- // find next active server channel
- while ( iServerCh < MAX_NUM_CHANNELS )
- {
- iClientCh = clientChannelIDs[iServerCh++];
-
- if ( iClientCh != INVALID_INDEX )
- {
- clientChannels[iClientCh].level = vecLevelList[i];
- break;
- }
- }
+ // first update the settings struct and then update the mixer panel
+ pSettings.LoadFaderSettings ( strFileName );
+ audioMixerBoard.LoadAllFaderSettings();
}
+}
- // store levels by client channel ID
- iClientCh = 0;
+void CClient::OnSaveChannelSetup()
+{
+ QString strFileName = "somefile.ini" ; //FIXME - QFileDialog::getSaveFileName ( this, tr ( "Select Channel Setup File" ), "", QString ( "*." ) + MIX_SETTINGS_FILE_SUFFIX );
- for ( int i = 0; i < iActiveChannels; i++ )
+ if ( !strFileName.isEmpty() )
{
- while ( iClientCh < MAX_NUM_CHANNELS )
- {
- uint16_t level = clientChannels[iClientCh].level;
+ // first store all current fader settings (in case we are in an active connection
+ // right now) and then save the information in the settings struct in the file
+ audioMixerBoard.StoreAllFaderSettings();
+ pSettings.SaveFaderSettings ( strFileName );
+ }
+}
- iServerCh = clientChannels[iClientCh++].iServerChannelID;
- if ( iServerCh != INVALID_INDEX )
- {
- vecLevelList[i] = level;
- break;
- }
+void CClient::OnSoundDeviceChanged ( QString strError )
+{
+ if ( !strError.isEmpty() )
+ {
+ // the sound device setup has a problem, disconnect any active connection
+ if ( IsRunning() )
+ {
+ Disconnect();
}
+
+ // show the error message of the device setup
+ setUserMsg( strError );
+ }
+
+ // if the check audio device timer is running, it must be restarted on a device change
+ if ( TimerCheckAudioDeviceOk.isActive() )
+ {
+ TimerCheckAudioDeviceOk.start ( CHECK_AUDIO_DEV_OK_TIME_MS );
+ }
+
+ if ( pSettings.bEnableFeedbackDetection && TimerDetectFeedback.isActive() )
+ {
+ TimerDetectFeedback.start ( DETECT_FEEDBACK_TIME_MS );
+ bDetectFeedback = true;
+ }
+}
+
+void CClient::OnRecorderStateReceived ( const ERecorderState newRecorderState )
+{
+ // update immediately here and inform QML
+ eRecorderState = newRecorderState;
+ emit recordingStatusChanged();
+}
+
+void CClient::OnNumClientsChanged ( int iNewNumClients )
+{
+ if ( pSettings.bEnableAudioAlerts && iNewNumClients > iClients )
+ {
+ // QSoundEffect* sf = new QSoundEffect();
+ // sf->setSource ( QUrl::fromLocalFile ( ":sounds/res/sounds/new_user.wav" ) );
+ // sf->play();
+ ; // do nothing for now
}
- return true; // tell caller to emit signal with new list
+ // iNewNumClients will be zero on the first trigger of this signal handler when connecting to a new server.
+ // Subsequent triggers will thus sound the alert (if enabled).
+ iClients = iNewNumClients;
}
diff --git a/src/client.h b/src/client.h
index dea4b4ebbc..05743a1357 100644
--- a/src/client.h
+++ b/src/client.h
@@ -38,31 +38,25 @@
#include "socket.h"
#include "channel.h"
#include "util.h"
-#include "plugins/audioreverb.h"
#include "buffer.h"
#include "signalhandler.h"
+#include "audiomixerboard.h"
+#include "levelmeter.h"
+#include "chatbox.h"
-#if defined( _WIN32 ) && !defined( JACK_ON_WINDOWS )
+#if defined( _WIN32 )
# include "sound/asio/sound.h"
-#else
-# if ( defined( Q_OS_MACOS ) ) && !defined( JACK_REPLACES_COREAUDIO )
-# include "sound/coreaudio-mac/sound.h"
-# else
-# if defined( Q_OS_IOS )
-# include "sound/coreaudio-ios/sound.h"
-# else
-# ifdef ANDROID
-# include "sound/oboe/sound.h"
-# else
-# include "sound/jack/sound.h"
-# ifndef JACK_ON_WINDOWS // these headers are not available in Windows OS
-# include
-# include
-# endif
-# include
-# endif
-# endif
-# endif
+#elif defined( Q_OS_MACOS )
+# include "sound/coreaudio-mac/sound.h"
+#elif defined( Q_OS_IOS )
+# include "sound/coreaudio-ios/sound.h"
+#elif defined (Q_OS_ANDROID)
+# include "sound/oboe/sound.h"
+#elif defined (Q_OS_LINUX)
+# include "sound/jack/sound.h"
+# include
+# include
+# include
#endif
/* Definitions ****************************************************************/
@@ -71,9 +65,6 @@
#define AUD_FADER_IN_MAX 100
#define AUD_FADER_IN_MIDDLE ( AUD_FADER_IN_MAX / 2 )
-// audio reverberation range
-#define AUD_REVERB_MAX 100
-
// default delay period between successive gain updates (ms)
// this will be increased to double the ping time if connected to a distant server
#define DEFAULT_GAIN_DELAY_PERIOD_MS 50
@@ -103,26 +94,45 @@
#define OPUS_NUM_BYTES_STEREO_NORMAL_QUALITY_DBLE_FRAMESIZE 71
#define OPUS_NUM_BYTES_STEREO_HIGH_QUALITY_DBLE_FRAMESIZE 165
-/* Classes ********************************************************************/
+// from clientdlg
+/* Definitions ****************************************************************/
+// update time for GUI controls
+#define LEVELMETER_UPDATE_TIME_MS 100 // ms
+#define BUFFER_LED_UPDATE_TIME_MS 300 // ms
+#define LED_BAR_UPDATE_TIME_MS 1000 // ms
+#define CHECK_AUDIO_DEV_OK_TIME_MS 5000 // ms
+#define DETECT_FEEDBACK_TIME_MS 3000 // ms
-class CClientChannel
-{
-public:
- int iServerChannelID; // unused channels will contain INVALID_INDEX
- int iJoinSequence; // order of joining of session participants
+// number of ping times > upper bound until error message is shown
+#define NUM_HIGH_PINGS_UNTIL_ERROR 5
- float oldGain, newGain; // for rate-limiting sending of gain messages
- float oldPan, newPan; // for rate-limiting sending of pan messages
+#define DISPLAY_UPDATE_TIME 1000 // ms
- uint16_t level; // last value of level meter received for channel
+#define SERV_LIST_REQ_UPDATE_TIME_MS 2000 // ms
- // can store here other information about an active channel
-};
+// ------------
+/* Classes ********************************************************************/
class CClient : public QObject
{
Q_OBJECT
+ Q_PROPERTY(QString sessionlinkText READ sessionlinkText WRITE setSessionlinkText NOTIFY sessionlinkTextChanged)
+ Q_PROPERTY(bool muteOut READ muteOut WRITE setMuteOut NOTIFY muteOutChanged)
+ Q_PROPERTY(int audioInPan READ audioInPan WRITE setAudioInPan NOTIFY audioInPanChanged FINAL)
+ Q_PROPERTY(int pingVal READ pingVal NOTIFY pingValChanged FINAL)
+ Q_PROPERTY(int delayVal READ delayVal NOTIFY delayValChanged FINAL)
+ Q_PROPERTY(bool jitterWarn READ jitterWarn WRITE setJitterWarn NOTIFY jitterWarnChanged FINAL)
+ Q_PROPERTY(QString sessionStatus READ sessionStatus NOTIFY sessionStatusChanged FINAL)
+ Q_PROPERTY(QString sessionName READ sessionName NOTIFY sessionNameChanged FINAL)
+ Q_PROPERTY(QString recordingStatus READ recordingStatus NOTIFY recordingStatusChanged FINAL)
+ Q_PROPERTY(bool bConnected READ bConnected NOTIFY bConnectedChanged FINAL)
+ // for Input LevelMeter L-R
+ Q_PROPERTY(CLevelMeter* inputMeterL READ inputMeterL CONSTANT)
+ Q_PROPERTY(CLevelMeter* inputMeterR READ inputMeterR CONSTANT)
+ // show user messages
+ Q_PROPERTY(QString userMsg READ userMsg WRITE setUserMsg NOTIFY userMsgChanged FINAL)
+
public:
CClient ( const quint16 iPortNumber,
const quint16 iQosNumber,
@@ -131,15 +141,76 @@ class CClient : public QObject
const bool bNoAutoJackConnect,
const QString& strNClientName,
const bool bNEnableIPv6,
- const bool bNMuteMeInPersonalMix );
+ const bool bNMuteMeInPersonalMix,
+ // additional from clientdlg:
+ const QString& strIniFileName,
+ const bool bMuteStream, // maybe
+ // for settings
+ const QList bCommandLineOptions
+ );
virtual ~CClient();
+ // QML accessors -----------
+ int audioInPan() const { return iAudioInFader; }
+ void setAudioInPan ( const int iNV ) { iAudioInFader = iNV; emit audioInPanChanged(); }
+
+ int pingVal() { return m_pingVal; }
+
+ int delayVal() { return m_delayVal; }
+
+ bool jitterWarn();
+ void setJitterWarn( bool warn );
+
+ QString sessionStatus() { return m_sessionStatus; }
+ void setSessionStatus( QString strName );
+ // { if (IsRunning())
+ // return "CONNECTED";
+ // return "NO SESSION";
+ // }
+
+ QString sessionName() { return strSelectedAddress; }
+
+ QString recordingStatus()
+ {
+ if (eRecorderState == 3)
+ return "ON";
+ return "OFF";
+ }
+
+ QString sessionlinkText();
+ void setSessionlinkText( const QString& strSelectedAddress );
+
+ bool muteOut() { return bMuteOutStream; }
+ void setMuteOut ( bool value )
+ {
+ bMuteOutStream = value;
+ }
+
+ CLevelMeter* inputMeterL() const { return m_inputMeterL; }
+ CLevelMeter* inputMeterR() const { return m_inputMeterR; }
+
+ QString userMsg() const;
+ void setUserMsg( const QString &userMessage );
+
+ // -- QML ----
+
+ // things
+ CChannelCoreInfo ChannelInfo;
+ QString strClientName;
+ QString strIniFileName;
+ CClientSettings pSettings;
+ CAudioMixerBoard audioMixerBoard;
+ CChatBox chatBox;
+ QList CommandLineOptions; // for settings
+ // ----
+
void Start();
void Stop();
bool IsRunning() { return Sound.IsRunning(); }
bool IsCallbackEntered() const { return Sound.IsCallbackEntered(); }
bool SetServerAddr ( QString strNAddr );
+ void SetServerStatus ( const QString& strNewServerName );
double GetLevelForMeterdBLeft() { return SignalLevelMeter.GetLevelForMeterdBLeftOrMono(); }
double GetLevelForMeterdBRight() { return SignalLevelMeter.GetLevelForMeterdBRight(); }
@@ -148,30 +219,13 @@ class CClient : public QObject
bool IsConnected() { return Channel.IsConnected(); }
- EGUIDesign GetGUIDesign() const { return eGUIDesign; }
- void SetGUIDesign ( const EGUIDesign eNGD ) { eGUIDesign = eNGD; }
-
- EMeterStyle GetMeterStyle() const { return eMeterStyle; }
- void SetMeterStyle ( const EMeterStyle eNMT ) { eMeterStyle = eNMT; }
-
EAudioQuality GetAudioQuality() const { return eAudioQuality; }
void SetAudioQuality ( const EAudioQuality eNAudioQuality );
EAudChanConf GetAudioChannels() const { return eAudioChannelConf; }
void SetAudioChannels ( const EAudChanConf eNAudChanConf );
- int GetAudioInFader() const { return iAudioInFader; }
- void SetAudioInFader ( const int iNV ) { iAudioInFader = iNV; }
-
- int GetReverbLevel() const { return iReverbLevel; }
- void SetReverbLevel ( const int iNL ) { iReverbLevel = iNL; }
-
- bool IsReverbOnLeftChan() const { return bReverbOnLeftChan; }
- void SetReverbOnLeftChan ( const bool bIL )
- {
- bReverbOnLeftChan = bIL;
- AudioReverb.Clear();
- }
+ bool bConnected() { return IsRunning(); }
void SetDoAutoSockBufSize ( const bool bValue );
bool GetDoAutoSockBufSize() const { return Channel.GetDoAutoSockBufSize(); }
@@ -256,9 +310,10 @@ class CClient : public QObject
void SetMuteOutStream ( const bool bDoMute ) { bMuteOutStream = bDoMute; }
void SetRemoteChanGain ( const int iId, const float fGain, const bool bIsMyOwnFader );
- void SetRemoteChanPan ( const int iId, const float fPan );
- void OnTimerRemoteChanGainOrPan();
- void StartTimerGainOrPan();
+ void OnTimerRemoteChanGain();
+ void StartDelayTimer();
+
+ void SetRemoteChanPan ( const int iId, const float fPan ) { Channel.SetRemoteChanPan ( iId, fPan ); }
void SetInputBoost ( const int iNewBoost ) { iInputBoost = iNewBoost; }
@@ -286,9 +341,6 @@ class CClient : public QObject
Channel.GetBufErrorRates ( vecErrRates, dLimit, dMaxUpLimit );
}
- // settings
- CChannelCoreInfo ChannelInfo;
- QString strClientName;
protected:
// callback function must be static, otherwise it does not work
@@ -302,27 +354,10 @@ class CClient : public QObject
int EvaluatePingMessage ( const int iMs );
void CreateServerJitterBufferMessage();
- void ClearClientChannels();
- void FreeClientChannel ( const int iServerChannelID );
- int FindClientChannel ( const int iServerChannelID, const bool bCreateIfNew ); // returns a client channel ID or INVALID_INDEX
- bool ReorderLevelList ( CVector& vecLevelList ); // modifies vecLevelList, passed by reference
-
// only one channel is needed for client application
CChannel Channel;
CProtocol ConnLessProtocol;
- // client channels, indexed by client channel ID,
- // containing server channel ID (INVALID_INDEX if free)
- CClientChannel clientChannels[MAX_NUM_CHANNELS];
-
- // client channel IDs, indexed by server channel ID
- // unused channels will contain INVALID_INDEX
- int clientChannelIDs[MAX_NUM_CHANNELS];
-
- int iActiveChannels; // number of active channels
- int iJoinSequence; // order of joining of session participants
- QMutex MutexChannels;
-
// audio encoder/decoder
OpusCustomMode* Opus64Mode;
OpusCustomEncoder* Opus64EncoderMono;
@@ -354,9 +389,6 @@ class CClient : public QObject
CVector vecbyNetwData;
int iAudioInFader;
- bool bReverbOnLeftChan;
- int iReverbLevel;
- CAudioReverb AudioReverb;
int iInputBoost;
int iSndCrdPrefFrameSizeFactor;
@@ -377,8 +409,6 @@ class CClient : public QObject
int iMonoBlockSizeSam;
int iStereoBlockSizeSam;
- EGUIDesign eGUIDesign;
- EMeterStyle eMeterStyle;
bool bEnableAudioAlerts;
bool bEnableOPUS64;
@@ -393,15 +423,58 @@ class CClient : public QObject
// for ping measurement
QElapsedTimer PreciseTime;
- // for gain or pan rate limiting
- QMutex MutexGainOrPan;
- QTimer TimerGainOrPan;
- int minGainOrPanId;
- int maxGainOrPanId;
+ // for gain rate limiting
+ QMutex MutexGain;
+ QTimer TimerGain;
+ int minGainId;
+ int maxGainId;
+ float oldGain[MAX_NUM_CHANNELS];
+ float newGain[MAX_NUM_CHANNELS];
int iCurPingTime;
CSignalHandler* pSignalHandler;
+ // for join / connect
+ QString strSelectedAddress;
+ void Connect( const QString& strAddress );
+ void Disconnect();
+ QString strServerName;
+
+ // timers
+ QTimer TimerSigMet;
+ QTimer TimerBuffersLED;
+ QTimer TimerStatus;
+ QTimer TimerPing;
+ QTimer TimerCheckAudioDeviceOk;
+ QTimer TimerDetectFeedback;
+
+ void SetPingTime ( const int iPingTime, const int iOverallDelayMs );
+
+ int iClients;
+ // bool bConnected;
+ bool bConnectDlgWasShown;
+ bool bMIDICtrlUsed;
+ bool bDetectFeedback;
+ ERecorderState eLastRecorderState;
+ ERecorderState eRecorderState;
+
+ virtual void closeEvent ( QCloseEvent* Event );
+
+ // QML props .................
+ // object refs for input meter levels
+ CLevelMeter* m_inputMeterL;
+ CLevelMeter* m_inputMeterR;
+ // for ping/delay stat display
+ int m_pingVal;
+ int m_delayVal;
+ // for user messages
+ QString m_userMsg;
+ // handle jitterWarn state
+ bool m_jitterWarn = false;
+ // session status
+ QString m_sessionStatus = "NO SESSION";
+
+
protected slots:
void OnHandledSignal ( int sigNum );
void OnSendProtMessage ( CVector vecMessage );
@@ -432,11 +505,63 @@ protected slots:
void OnControllerInFaderIsSolo ( int iChannelIdx, bool bIsSolo );
void OnControllerInFaderIsMute ( int iChannelIdx, bool bIsMute );
void OnControllerInMuteMyself ( bool bMute );
- void OnClientIDReceived ( int iServerChanID );
- void OnMuteStateHasChangedReceived ( int iServerChanID, bool bIsMuted );
- void OnCLChannelLevelListReceived ( CHostAddress InetAddr, CVector vecLevelList );
+ void OnClientIDReceived ( int iChanID );
void OnConClientListMesReceived ( CVector vecChanInfo );
+
+public slots:
+ // new client stuff
+ void onConnectButtonClicked();
+ void onDisconnectButtonClicked();
+ void OnTimerSigMet();
+ void OnTimerBuffersLED();
+ void OnTimerCheckAudioDeviceOk();
+ void OnTimerDetectFeedback();
+ void OnTimerStatus() { ; } // redundant ?
+ void OnTimerPing();
+ void OnPingTimeResult ( int iPingTime );
+ void OnVersionAndOSReceived ( COSUtil::EOpSystemType, QString strVersion );
+ void OnCLVersionAndOSReceived ( CHostAddress, COSUtil::EOpSystemType, QString strVersion );
+ void OnChatTextReceived ( QString strChatText );
+ void OnLoadChannelSetup();
+ void OnSaveChannelSetup();
+
+ void OnOwnFaderFirst()
+ {
+ pSettings.bOwnFaderFirst = !pSettings.bOwnFaderFirst;
+ audioMixerBoard.SetFaderSorting ( pSettings.eChannelSortType );
+ }
+ void OnNoSortChannels() { audioMixerBoard.SetFaderSorting ( ST_NO_SORT ); }
+ void OnSortChannelsByName() { audioMixerBoard.SetFaderSorting ( ST_BY_NAME ); }
+ void OnSortChannelsByGroupID() { audioMixerBoard.SetFaderSorting ( ST_BY_GROUPID ); }
+ void OnClearAllStoredSoloMuteSettings();
+ void OnSetAllFadersToNewClientLevel() { audioMixerBoard.SetAllFaderLevelsToNewClientLevel(); }
+ void OnAutoAdjustAllFaderLevels() { audioMixerBoard.AutoAdjustAllFaderLevels(); }
+ void OnNumMixerPanelRowsChanged ( int value ) { audioMixerBoard.SetNumMixerPanelRows ( value ); }
+ void OnNewLocalInputText ( QString strChatText ) { CreateChatTextMes ( strChatText ); }
+
+ void OnSoundDeviceChanged ( QString strError );
+
+ void OnChangeChanGain ( int iId, float fGain, bool bIsMyOwnFader ) { SetRemoteChanGain ( iId, fGain, bIsMyOwnFader ); }
+
+ void OnChangeChanPan ( int iId, float fPan ) { SetRemoteChanPan ( iId, fPan ); }
+
+ void OnMuteStateHasChangedReceived ( int iChanID, bool bIsMuted )
+ {
+ audioMixerBoard.SetRemoteFaderIsMute ( iChanID, bIsMuted );
+ }
+
+ void OnCLChannelLevelListReceived ( CHostAddress /* unused */, CVector vecLevelList )
+ {
+ audioMixerBoard.SetChannelLevels ( vecLevelList );
+ }
+
+ void OnDisconnected() { Disconnect(); }
+ void OnRecorderStateReceived ( ERecorderState eRecorderState );
+ void OnNumClientsChanged ( int iNewNumClients );
+ // void accept() { close(); } // introduced by pljones
+
+
signals:
void ConClientListMesReceived ( CVector vecChanInfo );
void ChatTextReceived ( QString strChatText );
@@ -448,15 +573,10 @@ protected slots:
void RecorderStateReceived ( ERecorderState eRecorderState );
void CLServerListReceived ( CHostAddress InetAddr, CVector vecServerInfo );
-
void CLRedServerListReceived ( CHostAddress InetAddr, CVector vecServerInfo );
-
void CLConnClientsListMesReceived ( CHostAddress InetAddr, CVector vecChanInfo );
-
void CLPingTimeWithNumClientsReceived ( CHostAddress InetAddr, int iPingTime, int iNumClients );
-
void CLVersionAndOSReceived ( CHostAddress InetAddr, COSUtil::EOpSystemType eOSType, QString strVersion );
-
void CLChannelLevelListReceived ( CHostAddress InetAddr, CVector vecLevelList );
void Disconnected();
@@ -466,4 +586,19 @@ protected slots:
void ControllerInFaderIsSolo ( int iChannelIdx, bool bIsSolo );
void ControllerInFaderIsMute ( int iChannelIdx, bool bIsMute );
void ControllerInMuteMyself ( bool bMute );
+
+ // QML signals
+ void sessionlinkTextChanged();
+ void muteOutChanged();
+ void audioInPanChanged();
+ void pingValChanged();
+ void delayValChanged();
+ void jitterWarnChanged();
+ void inputLevelLChanged();
+ void inputLevelRChanged();
+ void sessionStatusChanged();
+ void sessionNameChanged();
+ void recordingStatusChanged();
+ void bConnectedChanged();
+ void userMsgChanged();
};
diff --git a/src/clientdlg.cpp b/src/clientdlg.cpp
deleted file mode 100644
index cbfa04518d..0000000000
--- a/src/clientdlg.cpp
+++ /dev/null
@@ -1,1518 +0,0 @@
-/******************************************************************************\
- * Copyright (c) 2004-2024
- *
- * Author(s):
- * Volker Fischer
- *
- ******************************************************************************
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- *
-\******************************************************************************/
-
-#include "clientdlg.h"
-
-/* Implementation *************************************************************/
-CClientDlg::CClientDlg ( CClient* pNCliP,
- CClientSettings* pNSetP,
- const QString& strConnOnStartupAddress,
- const QString& strMIDISetup,
- const bool bNewShowComplRegConnList,
- const bool bShowAnalyzerConsole,
- const bool bMuteStream,
- const bool bNEnableIPv6,
- QWidget* parent ) :
- CBaseDlg ( parent, Qt::Window ), // use Qt::Window to get min/max window buttons
- pClient ( pNCliP ),
- pSettings ( pNSetP ),
- bConnectDlgWasShown ( false ),
- bDetectFeedback ( false ),
- bEnableIPv6 ( bNEnableIPv6 ),
- eLastRecorderState ( RS_UNDEFINED ), // for SetMixerBoardDeco
- eLastDesign ( GD_ORIGINAL ), // "
- ClientSettingsDlg ( pNCliP, pNSetP, parent ),
- ChatDlg ( parent ),
- ConnectDlg ( pNSetP, bNewShowComplRegConnList, parent ),
- AnalyzerConsole ( pNCliP, parent )
-{
- setupUi ( this );
-
- // Add help text to controls -----------------------------------------------
- // input level meter
- QString strInpLevH = "" + tr ( "Input Level Meter" ) + ": " +
- tr ( "This shows "
- "the level of the two stereo channels "
- "for your audio input." ) +
- "
" +
- tr ( "Make sure not to clip the input signal to avoid distortions of the "
- "audio signal." );
-
- QString strInpLevHTT = tr ( "If the application "
- "is connected to a server and "
- "you play your instrument/sing into the microphone, the VU "
- "meter should flicker. If this is not the case, you have "
- "probably selected the wrong input channel (e.g. 'line in' instead "
- "of the microphone input) or set the input gain too low in the "
- "(Windows) audio mixer." ) +
- "
" +
- tr ( "For proper usage of the "
- "application, you should not hear your singing/instrument through "
- "the loudspeaker or your headphone when the software is not connected. "
- "This can be achieved by muting your input audio channel in the "
- "Playback mixer (not the Recording mixer!)." ) +
- TOOLTIP_COM_END_TEXT;
-
- QString strInpLevHAccText = tr ( "Input level meter" );
- QString strInpLevHAccDescr = tr ( "Simulates an analog LED level meter." );
-
- lblInputLEDMeter->setWhatsThis ( strInpLevH );
- lblLevelMeterLeft->setWhatsThis ( strInpLevH );
- lblLevelMeterRight->setWhatsThis ( strInpLevH );
- lbrInputLevelL->setWhatsThis ( strInpLevH );
- lbrInputLevelL->setAccessibleName ( strInpLevHAccText );
- lbrInputLevelL->setAccessibleDescription ( strInpLevHAccDescr );
- lbrInputLevelL->setToolTip ( strInpLevHTT );
- lbrInputLevelL->setEnabled ( false );
- lbrInputLevelR->setWhatsThis ( strInpLevH );
- lbrInputLevelR->setAccessibleName ( strInpLevHAccText );
- lbrInputLevelR->setAccessibleDescription ( strInpLevHAccDescr );
- lbrInputLevelR->setToolTip ( strInpLevHTT );
- lbrInputLevelR->setEnabled ( false );
-
- // connect/disconnect button
- butConnect->setWhatsThis ( "" + tr ( "Connect/Disconnect Button" ) + ": " +
- tr ( "Opens a dialog where you can select a server to connect to. "
- "If you are connected, pressing this button will end the session." ) );
-
- butConnect->setAccessibleName ( tr ( "Connect and disconnect toggle button" ) );
-
- // reverberation level
- QString strAudReverb = "" + tr ( "Reverb effect" ) + ": " +
- tr ( "Reverb can be applied to one local mono audio channel or to both "
- "channels in stereo mode. The mono channel selection and the "
- "reverb level can be modified. For example, if "
- "a microphone signal is fed in to the right audio channel of the "
- "sound card and a reverb effect needs to be applied, set the "
- "channel selector to right and move the fader upwards until the "
- "desired reverb level is reached." );
-
- lblAudioReverb->setWhatsThis ( strAudReverb );
- sldAudioReverb->setWhatsThis ( strAudReverb );
-
- sldAudioReverb->setAccessibleName ( tr ( "Reverb effect level setting" ) );
-
- // reverberation channel selection
- QString strRevChanSel = "" + tr ( "Reverb Channel Selection" ) + ": " +
- tr ( "With these radio buttons the audio input channel on which the "
- "reverb effect is applied can be chosen. Either the left "
- "or right input channel can be selected." );
-
- rbtReverbSelL->setWhatsThis ( strRevChanSel );
- rbtReverbSelL->setAccessibleName ( tr ( "Left channel selection for reverb" ) );
- rbtReverbSelR->setWhatsThis ( strRevChanSel );
- rbtReverbSelR->setAccessibleName ( tr ( "Right channel selection for reverb" ) );
-
- // delay LED
- QString strLEDDelay = "" + tr ( "Delay Status LED" ) + ": " + tr ( "Shows the current audio delay status:" ) +
- ""
- "- "
- "" +
- tr ( "Green" ) + ": " +
- tr ( "The delay is perfect for a jam "
- "session." ) +
- "
"
- "- "
- "" +
- tr ( "Yellow" ) + ": " +
- tr ( "A session is still possible "
- "but it may be harder to play." ) +
- "
"
- "- "
- "" +
- tr ( "Red" ) + ": " +
- tr ( "The delay is too large for "
- "jamming." ) +
- "
"
- "
";
-
- lblDelay->setWhatsThis ( strLEDDelay );
- ledDelay->setWhatsThis ( strLEDDelay );
- ledDelay->setToolTip ( tr ( "If this LED indicator turns red, "
- "you will not have much fun using %1." )
- .arg ( APP_NAME ) +
- TOOLTIP_COM_END_TEXT );
-
- ledDelay->setAccessibleName ( tr ( "Delay status LED indicator" ) );
-
- // buffers LED
- QString strLEDBuffers = "" + tr ( "Local Jitter Buffer Status LED" ) + ": " +
- tr ( "The local jitter buffer status LED shows the current audio/streaming "
- "status. If the light is red, the audio stream is interrupted. "
- "This is caused by one of the following problems:" ) +
- ""
- "- " +
- tr ( "The network jitter buffer is not large enough for the current "
- "network/audio interface jitter." ) +
- "
"
- "- " +
- tr ( "The sound card's buffer delay (buffer size) is too small "
- "(see Settings window)." ) +
- "
"
- "- " +
- tr ( "The upload or download stream rate is too high for your "
- "internet bandwidth." ) +
- "
"
- "- " +
- tr ( "The CPU of the client or server is at 100%." ) +
- "
"
- "
";
-
- lblBuffers->setWhatsThis ( strLEDBuffers );
- ledBuffers->setWhatsThis ( strLEDBuffers );
- ledBuffers->setToolTip ( tr ( "If this LED indicator turns red, "
- "the audio stream is interrupted." ) +
- TOOLTIP_COM_END_TEXT );
-
- ledBuffers->setAccessibleName ( tr ( "Local Jitter Buffer status LED indicator" ) );
-
- // current connection status details
- QString strConnStats = "" + tr ( "Current Connection Status" ) + ": " +
- tr ( "The Ping Time is the time required for the audio "
- "stream to travel from the client to the server and back again. This "
- "delay is introduced by the network and should be about "
- "20-30 ms. If this delay is higher than about 50 ms, your distance to "
- "the server is too large or your internet connection is not "
- "sufficient." ) +
- "
" +
- tr ( "Overall Delay is calculated from the current Ping Time and the "
- "delay introduced by the current buffer settings." );
-
- lblPing->setWhatsThis ( strConnStats );
- lblPingVal->setWhatsThis ( strConnStats );
- lblDelay->setWhatsThis ( strConnStats );
- lblDelayVal->setWhatsThis ( strConnStats );
- lblPingVal->setText ( "---" );
- lblPingUnit->setText ( "" );
- lblDelayVal->setText ( "---" );
- lblDelayUnit->setText ( "" );
-
- // init GUI design
- SetGUIDesign ( pClient->GetGUIDesign() );
-
- // MeterStyle init
- SetMeterStyle ( pClient->GetMeterStyle() );
-
- // set the settings pointer to the mixer board (must be done early)
- MainMixerBoard->SetSettingsPointer ( pSettings );
- MainMixerBoard->SetNumMixerPanelRows ( pSettings->iNumMixerPanelRows );
-
- // Pass through flag for MIDICtrlUsed
- MainMixerBoard->SetMIDICtrlUsed ( !strMIDISetup.isEmpty() );
-
- // reset mixer board
- MainMixerBoard->HideAll();
-
- // init status label
- OnTimerStatus();
-
- // init connection button text
- butConnect->setText ( tr ( "C&onnect" ) );
-
- // init input level meter bars
- lbrInputLevelL->SetValue ( 0 );
- lbrInputLevelR->SetValue ( 0 );
-
- // init status LEDs
- ledBuffers->Reset();
- ledDelay->Reset();
-
- // init audio reverberation
- sldAudioReverb->setRange ( 0, AUD_REVERB_MAX );
- const int iCurAudReverb = pClient->GetReverbLevel();
- sldAudioReverb->setValue ( iCurAudReverb );
- sldAudioReverb->setTickInterval ( AUD_REVERB_MAX / 5 );
-
- // init input boost
- pClient->SetInputBoost ( pSettings->iInputBoost );
-
- // init reverb channel
- UpdateRevSelection();
-
- // init connect dialog
- ConnectDlg.SetShowAllMusicians ( pSettings->bConnectDlgShowAllMusicians );
-
- // set window title (with no clients connected -> "0")
- SetMyWindowTitle ( 0 );
-
- // track number of clients to detect joins/leaves for audio alerts
- iClients = 0;
-
- // prepare Mute Myself info label (invisible by default)
- lblGlobalInfoLabel->setStyleSheet ( ".QLabel { background: red; }" );
- lblGlobalInfoLabel->hide();
-
- // prepare update check info label (invisible by default)
- lblUpdateCheck->setOpenExternalLinks ( true ); // enables opening a web browser if one clicks on a html link
- lblUpdateCheck->setText ( "" + APP_UPGRADE_AVAILABLE_MSG_TEXT.arg ( APP_NAME ).arg ( VERSION ) + "" );
- lblUpdateCheck->hide();
-
- // setup timers
- TimerCheckAudioDeviceOk.setSingleShot ( true ); // only check once after connection
- TimerDetectFeedback.setSingleShot ( true );
-
- // Connect on startup ------------------------------------------------------
- if ( !strConnOnStartupAddress.isEmpty() )
- {
- // initiate connection (always show the address in the mixer board
- // (no alias))
- Connect ( strConnOnStartupAddress, strConnOnStartupAddress );
- }
-
- // File menu --------------------------------------------------------------
- QMenu* pFileMenu = new QMenu ( tr ( "&File" ), this );
-
- pFileMenu->addAction ( tr ( "&Connection Setup..." ), this, SLOT ( OnOpenConnectionSetupDialog() ), QKeySequence ( Qt::CTRL + Qt::Key_C ) );
-
- pFileMenu->addSeparator();
-
- pFileMenu->addAction ( tr ( "&Load Mixer Channels Setup..." ), this, SLOT ( OnLoadChannelSetup() ) );
-
- pFileMenu->addAction ( tr ( "&Save Mixer Channels Setup..." ), this, SLOT ( OnSaveChannelSetup() ) );
-
- pFileMenu->addSeparator();
-
- pFileMenu->addAction ( tr ( "E&xit" ), this, SLOT ( close() ), QKeySequence ( Qt::CTRL + Qt::Key_Q ) );
-
- // Edit menu --------------------------------------------------------------
- QMenu* pEditMenu = new QMenu ( tr ( "&Edit" ), this );
-
- pEditMenu->addAction ( tr ( "Clear &All Stored Solo and Mute Settings" ), this, SLOT ( OnClearAllStoredSoloMuteSettings() ) );
-
- pEditMenu->addAction ( tr ( "Set All Faders to New Client &Level" ),
- this,
- SLOT ( OnSetAllFadersToNewClientLevel() ),
- QKeySequence ( Qt::CTRL + Qt::Key_L ) );
-
- pEditMenu->addAction ( tr ( "Auto-Adjust all &Faders" ), this, SLOT ( OnAutoAdjustAllFaderLevels() ), QKeySequence ( Qt::CTRL + Qt::Key_F ) );
-
- // View menu --------------------------------------------------------------
- QMenu* pViewMenu = new QMenu ( tr ( "&View" ), this );
-
- // own fader first option: works from server version 3.5.5 which supports sending client ID back to client
- QAction* OwnFaderFirstAction =
- pViewMenu->addAction ( tr ( "O&wn Fader First" ), this, SLOT ( OnOwnFaderFirst() ), QKeySequence ( Qt::CTRL + Qt::Key_W ) );
-
- pViewMenu->addSeparator();
-
- QAction* NoSortAction =
- pViewMenu->addAction ( tr ( "N&o User Sorting" ), this, SLOT ( OnNoSortChannels() ), QKeySequence ( Qt::CTRL + Qt::Key_O ) );
-
- QAction* ByNameAction =
- pViewMenu->addAction ( tr ( "Sort Users by &Name" ), this, SLOT ( OnSortChannelsByName() ), QKeySequence ( Qt::CTRL + Qt::Key_N ) );
-
- QAction* ByInstrAction = pViewMenu->addAction ( tr ( "Sort Users by &Instrument" ),
- this,
- SLOT ( OnSortChannelsByInstrument() ),
- QKeySequence ( Qt::CTRL + Qt::Key_I ) );
-
- QAction* ByGroupAction =
- pViewMenu->addAction ( tr ( "Sort Users by &Group" ), this, SLOT ( OnSortChannelsByGroupID() ), QKeySequence ( Qt::CTRL + Qt::Key_G ) );
-
- QAction* ByCityAction =
- pViewMenu->addAction ( tr ( "Sort Users by &City" ), this, SLOT ( OnSortChannelsByCity() ), QKeySequence ( Qt::CTRL + Qt::Key_T ) );
-
- QAction* ByChannelAction =
- pViewMenu->addAction ( tr ( "Sort Users by Chann&el" ), this, SLOT ( OnSortChannelsByChannel() ), QKeySequence ( Qt::CTRL + Qt::Key_E ) );
-
- OwnFaderFirstAction->setCheckable ( true );
- OwnFaderFirstAction->setChecked ( pSettings->bOwnFaderFirst );
-
- // the sorting menu entries shall be checkable and exclusive
- QActionGroup* SortActionGroup = new QActionGroup ( this );
- SortActionGroup->setExclusive ( true );
- NoSortAction->setCheckable ( true );
- SortActionGroup->addAction ( NoSortAction );
- ByNameAction->setCheckable ( true );
- SortActionGroup->addAction ( ByNameAction );
- ByInstrAction->setCheckable ( true );
- SortActionGroup->addAction ( ByInstrAction );
- ByGroupAction->setCheckable ( true );
- SortActionGroup->addAction ( ByGroupAction );
- ByCityAction->setCheckable ( true );
- SortActionGroup->addAction ( ByCityAction );
- ByChannelAction->setCheckable ( true );
- SortActionGroup->addAction ( ByChannelAction );
-
- // initialize sort type setting (i.e., recover stored setting)
- switch ( pSettings->eChannelSortType )
- {
- case ST_BY_NAME:
- ByNameAction->setChecked ( true );
- break;
- case ST_BY_INSTRUMENT:
- ByInstrAction->setChecked ( true );
- break;
- case ST_BY_GROUPID:
- ByGroupAction->setChecked ( true );
- break;
- case ST_BY_CITY:
- ByCityAction->setChecked ( true );
- break;
- case ST_BY_SERVER_CHANNEL:
- ByChannelAction->setChecked ( true );
- break;
- default: // ST_NO_SORT
- NoSortAction->setChecked ( true );
- break;
- }
- MainMixerBoard->SetFaderSorting ( pSettings->eChannelSortType );
-
- pViewMenu->addSeparator();
-
- pViewMenu->addAction ( tr ( "C&hat..." ), this, SLOT ( OnOpenChatDialog() ), QKeySequence ( Qt::CTRL + Qt::Key_H ) );
-
- // optionally show analyzer console entry
- if ( bShowAnalyzerConsole )
- {
- pViewMenu->addAction ( tr ( "&Analyzer Console..." ), this, SLOT ( OnOpenAnalyzerConsole() ) );
- }
-
- pViewMenu->addSeparator();
-
- // Settings menu --------------------------------------------------------------
- QMenu* pSettingsMenu = new QMenu ( tr ( "Sett&ings" ), this );
-
- pSettingsMenu->addAction ( tr ( "My &Profile..." ), this, SLOT ( OnOpenUserProfileSettings() ), QKeySequence ( Qt::CTRL + Qt::Key_P ) );
-
- pSettingsMenu->addAction ( tr ( "Audio/Network &Settings..." ), this, SLOT ( OnOpenAudioNetSettings() ), QKeySequence ( Qt::CTRL + Qt::Key_S ) );
-
- pSettingsMenu->addAction ( tr ( "A&dvanced Settings..." ), this, SLOT ( OnOpenAdvancedSettings() ), QKeySequence ( Qt::CTRL + Qt::Key_D ) );
-
- // Main menu bar -----------------------------------------------------------
- QMenuBar* pMenu = new QMenuBar ( this );
-
- pMenu->addMenu ( pFileMenu );
- pMenu->addMenu ( pEditMenu );
- pMenu->addMenu ( pViewMenu );
- pMenu->addMenu ( pSettingsMenu );
- pMenu->addMenu ( new CHelpMenu ( true, this ) );
-
- // Now tell the layout about the menu
- layout()->setMenuBar ( pMenu );
-
- // Window positions --------------------------------------------------------
- // main window
- if ( !pSettings->vecWindowPosMain.isEmpty() && !pSettings->vecWindowPosMain.isNull() )
- {
- restoreGeometry ( pSettings->vecWindowPosMain );
- }
-
- // settings window
- if ( !pSettings->vecWindowPosSettings.isEmpty() && !pSettings->vecWindowPosSettings.isNull() )
- {
- ClientSettingsDlg.restoreGeometry ( pSettings->vecWindowPosSettings );
- }
-
- if ( pSettings->bWindowWasShownSettings )
- {
- ShowGeneralSettings ( pSettings->iSettingsTab );
- }
-
- // chat window
- if ( !pSettings->vecWindowPosChat.isEmpty() && !pSettings->vecWindowPosChat.isNull() )
- {
- ChatDlg.restoreGeometry ( pSettings->vecWindowPosChat );
- }
-
- if ( pSettings->bWindowWasShownChat )
- {
- ShowChatWindow();
- }
-
- // connection setup window
- if ( !pSettings->vecWindowPosConnect.isEmpty() && !pSettings->vecWindowPosConnect.isNull() )
- {
- ConnectDlg.restoreGeometry ( pSettings->vecWindowPosConnect );
- }
-
- // Connections -------------------------------------------------------------
- // push buttons
- QObject::connect ( butConnect, &QPushButton::clicked, this, &CClientDlg::OnConnectDisconBut );
-
- // check boxes
- QObject::connect ( chbSettings, &QCheckBox::stateChanged, this, &CClientDlg::OnSettingsStateChanged );
-
- QObject::connect ( chbChat, &QCheckBox::stateChanged, this, &CClientDlg::OnChatStateChanged );
-
- QObject::connect ( chbLocalMute, &QCheckBox::stateChanged, this, &CClientDlg::OnLocalMuteStateChanged );
-
- // timers
- QObject::connect ( &TimerSigMet, &QTimer::timeout, this, &CClientDlg::OnTimerSigMet );
-
- QObject::connect ( &TimerBuffersLED, &QTimer::timeout, this, &CClientDlg::OnTimerBuffersLED );
-
- QObject::connect ( &TimerStatus, &QTimer::timeout, this, &CClientDlg::OnTimerStatus );
-
- QObject::connect ( &TimerPing, &QTimer::timeout, this, &CClientDlg::OnTimerPing );
-
- QObject::connect ( &TimerCheckAudioDeviceOk, &QTimer::timeout, this, &CClientDlg::OnTimerCheckAudioDeviceOk );
-
- QObject::connect ( &TimerDetectFeedback, &QTimer::timeout, this, &CClientDlg::OnTimerDetectFeedback );
-
- QObject::connect ( sldAudioReverb, &QSlider::valueChanged, this, &CClientDlg::OnAudioReverbValueChanged );
-
- // radio buttons
- QObject::connect ( rbtReverbSelL, &QRadioButton::clicked, this, &CClientDlg::OnReverbSelLClicked );
-
- QObject::connect ( rbtReverbSelR, &QRadioButton::clicked, this, &CClientDlg::OnReverbSelRClicked );
-
- // other
- QObject::connect ( pClient, &CClient::ConClientListMesReceived, this, &CClientDlg::OnConClientListMesReceived );
-
- QObject::connect ( pClient, &CClient::Disconnected, this, &CClientDlg::OnDisconnected );
-
- QObject::connect ( pClient, &CClient::ChatTextReceived, this, &CClientDlg::OnChatTextReceived );
-
- QObject::connect ( pClient, &CClient::ClientIDReceived, this, &CClientDlg::OnClientIDReceived );
-
- QObject::connect ( pClient, &CClient::MuteStateHasChangedReceived, this, &CClientDlg::OnMuteStateHasChangedReceived );
-
- QObject::connect ( pClient, &CClient::RecorderStateReceived, this, &CClientDlg::OnRecorderStateReceived );
-
- // This connection is a special case. On receiving a licence required message via the
- // protocol, a modal licence dialog is opened. Since this blocks the thread, we need
- // a queued connection to make sure the core protocol mechanism is not blocked, too.
- qRegisterMetaType ( "ELicenceType" );
- QObject::connect ( pClient, &CClient::LicenceRequired, this, &CClientDlg::OnLicenceRequired, Qt::QueuedConnection );
-
- QObject::connect ( pClient, &CClient::PingTimeReceived, this, &CClientDlg::OnPingTimeResult );
-
- QObject::connect ( pClient, &CClient::CLServerListReceived, this, &CClientDlg::OnCLServerListReceived );
-
- QObject::connect ( pClient, &CClient::CLRedServerListReceived, this, &CClientDlg::OnCLRedServerListReceived );
-
- QObject::connect ( pClient, &CClient::CLConnClientsListMesReceived, this, &CClientDlg::OnCLConnClientsListMesReceived );
-
- QObject::connect ( pClient, &CClient::CLPingTimeWithNumClientsReceived, this, &CClientDlg::OnCLPingTimeWithNumClientsReceived );
-
- QObject::connect ( pClient, &CClient::ControllerInFaderLevel, this, &CClientDlg::OnControllerInFaderLevel );
-
- QObject::connect ( pClient, &CClient::ControllerInPanValue, this, &CClientDlg::OnControllerInPanValue );
-
- QObject::connect ( pClient, &CClient::ControllerInFaderIsSolo, this, &CClientDlg::OnControllerInFaderIsSolo );
-
- QObject::connect ( pClient, &CClient::ControllerInFaderIsMute, this, &CClientDlg::OnControllerInFaderIsMute );
-
- QObject::connect ( pClient, &CClient::ControllerInMuteMyself, this, &CClientDlg::OnControllerInMuteMyself );
-
- QObject::connect ( pClient, &CClient::CLChannelLevelListReceived, this, &CClientDlg::OnCLChannelLevelListReceived );
-
- QObject::connect ( pClient, &CClient::VersionAndOSReceived, this, &CClientDlg::OnVersionAndOSReceived );
-
- QObject::connect ( pClient, &CClient::CLVersionAndOSReceived, this, &CClientDlg::OnCLVersionAndOSReceived );
-
- QObject::connect ( pClient, &CClient::SoundDeviceChanged, this, &CClientDlg::OnSoundDeviceChanged );
-
- QObject::connect ( &ClientSettingsDlg, &CClientSettingsDlg::GUIDesignChanged, this, &CClientDlg::OnGUIDesignChanged );
-
- QObject::connect ( &ClientSettingsDlg, &CClientSettingsDlg::MeterStyleChanged, this, &CClientDlg::OnMeterStyleChanged );
-
- QObject::connect ( &ClientSettingsDlg, &CClientSettingsDlg::AudioChannelsChanged, this, &CClientDlg::OnAudioChannelsChanged );
-
- QObject::connect ( &ClientSettingsDlg, &CClientSettingsDlg::CustomDirectoriesChanged, &ConnectDlg, &CConnectDlg::OnCustomDirectoriesChanged );
-
- QObject::connect ( &ClientSettingsDlg, &CClientSettingsDlg::NumMixerPanelRowsChanged, this, &CClientDlg::OnNumMixerPanelRowsChanged );
-
- QObject::connect ( this, &CClientDlg::SendTabChange, &ClientSettingsDlg, &CClientSettingsDlg::OnMakeTabChange );
-
- QObject::connect ( MainMixerBoard, &CAudioMixerBoard::ChangeChanGain, this, &CClientDlg::OnChangeChanGain );
-
- QObject::connect ( MainMixerBoard, &CAudioMixerBoard::ChangeChanPan, this, &CClientDlg::OnChangeChanPan );
-
- QObject::connect ( MainMixerBoard, &CAudioMixerBoard::NumClientsChanged, this, &CClientDlg::OnNumClientsChanged );
-
- QObject::connect ( &ChatDlg, &CChatDlg::NewLocalInputText, this, &CClientDlg::OnNewLocalInputText );
-
- QObject::connect ( &ConnectDlg, &CConnectDlg::ReqServerListQuery, this, &CClientDlg::OnReqServerListQuery );
-
- // note that this connection must be a queued connection, otherwise the server list ping
- // times are not accurate and the client list may not be retrieved for all servers listed
- // (it seems the sendto() function needs to be called from different threads to fire the
- // packet immediately and do not collect packets before transmitting)
- QObject::connect ( &ConnectDlg, &CConnectDlg::CreateCLServerListPingMes, this, &CClientDlg::OnCreateCLServerListPingMes, Qt::QueuedConnection );
-
- QObject::connect ( &ConnectDlg, &CConnectDlg::CreateCLServerListReqVerAndOSMes, this, &CClientDlg::OnCreateCLServerListReqVerAndOSMes );
-
- QObject::connect ( &ConnectDlg,
- &CConnectDlg::CreateCLServerListReqConnClientsListMes,
- this,
- &CClientDlg::OnCreateCLServerListReqConnClientsListMes );
-
- QObject::connect ( &ConnectDlg, &CConnectDlg::accepted, this, &CClientDlg::OnConnectDlgAccepted );
-
- // Initializations which have to be done after the signals are connected ---
- // start timer for status bar
- TimerStatus.start ( LED_BAR_UPDATE_TIME_MS );
-
- // restore connect dialog
- if ( pSettings->bWindowWasShownConnect )
- {
- ShowConnectionSetupDialog();
- }
-
- // mute stream on startup (must be done after the signal connections)
- if ( bMuteStream )
- {
- chbLocalMute->setCheckState ( Qt::Checked );
- }
-
- // query the update server version number needed for update check (note
- // that the connection less message respond may not make it back but that
- // is not critical since the next time Jamulus is started we have another
- // chance and the update check is not time-critical at all)
- CHostAddress UpdateServerHostAddress;
-
- // Send the request to two servers for redundancy if either or both of them
- // has a higher release version number, the reply will trigger the notification.
-
- if ( NetworkUtil().ParseNetworkAddress ( UPDATECHECK1_ADDRESS, UpdateServerHostAddress, bEnableIPv6 ) )
- {
- pClient->CreateCLServerListReqVerAndOSMes ( UpdateServerHostAddress );
- }
-
- if ( NetworkUtil().ParseNetworkAddress ( UPDATECHECK2_ADDRESS, UpdateServerHostAddress, bEnableIPv6 ) )
- {
- pClient->CreateCLServerListReqVerAndOSMes ( UpdateServerHostAddress );
- }
-}
-
-void CClientDlg::closeEvent ( QCloseEvent* Event )
-{
- // store window positions
- pSettings->vecWindowPosMain = saveGeometry();
- pSettings->vecWindowPosSettings = ClientSettingsDlg.saveGeometry();
- pSettings->vecWindowPosChat = ChatDlg.saveGeometry();
- pSettings->vecWindowPosConnect = ConnectDlg.saveGeometry();
-
- pSettings->bWindowWasShownSettings = ClientSettingsDlg.isVisible();
- pSettings->bWindowWasShownChat = ChatDlg.isVisible();
- pSettings->bWindowWasShownConnect = ConnectDlg.isVisible();
-
- // if settings/connect dialog or chat dialog is open, close it
- ClientSettingsDlg.close();
- ChatDlg.close();
- ConnectDlg.close();
- AnalyzerConsole.close();
-
- // if connected, terminate connection
- if ( pClient->IsRunning() )
- {
- pClient->Stop();
- }
-
- // make sure all current fader settings are applied to the settings struct
- MainMixerBoard->StoreAllFaderSettings();
-
- pSettings->bConnectDlgShowAllMusicians = ConnectDlg.GetShowAllMusicians();
- pSettings->eChannelSortType = MainMixerBoard->GetFaderSorting();
- pSettings->iNumMixerPanelRows = MainMixerBoard->GetNumMixerPanelRows();
-
- // default implementation of this event handler routine
- Event->accept();
-}
-
-void CClientDlg::ManageDragNDrop ( QDropEvent* Event, const bool bCheckAccept )
-{
- // we only want to use drag'n'drop with file URLs
- QListIterator UrlIterator ( Event->mimeData()->urls() );
-
- while ( UrlIterator.hasNext() )
- {
- const QString strFileNameWithPath = UrlIterator.next().toLocalFile();
-
- // check all given URLs and if any has the correct suffix
- if ( !strFileNameWithPath.isEmpty() && ( QFileInfo ( strFileNameWithPath ).suffix() == MIX_SETTINGS_FILE_SUFFIX ) )
- {
- if ( bCheckAccept )
- {
- // only accept drops of supports file types
- Event->acceptProposedAction();
- }
- else
- {
- // load the first valid settings file and leave the loop
- pSettings->LoadFaderSettings ( strFileNameWithPath );
- MainMixerBoard->LoadAllFaderSettings();
- break;
- }
- }
- }
-}
-
-void CClientDlg::UpdateRevSelection()
-{
- if ( pClient->GetAudioChannels() == CC_STEREO )
- {
- // for stereo make channel selection invisible since
- // reverberation effect is always applied to both channels
- rbtReverbSelL->setVisible ( false );
- rbtReverbSelR->setVisible ( false );
- }
- else
- {
- // make radio buttons visible
- rbtReverbSelL->setVisible ( true );
- rbtReverbSelR->setVisible ( true );
-
- // update value
- if ( pClient->IsReverbOnLeftChan() )
- {
- rbtReverbSelL->setChecked ( true );
- }
- else
- {
- rbtReverbSelR->setChecked ( true );
- }
- }
-
- // update visibility of the pan controls in the audio mixer board (pan is not supported for mono)
- MainMixerBoard->SetDisplayPans ( pClient->GetAudioChannels() != CC_MONO );
-}
-
-void CClientDlg::OnConnectDlgAccepted()
-{
- // We had an issue that the accepted signal was emit twice if a list item was double
- // clicked in the connect dialog. To avoid this we introduced a flag which makes sure
- // we process the accepted signal only once after the dialog was initially shown.
- if ( bConnectDlgWasShown )
- {
- // get the address from the connect dialog
- QString strSelectedAddress = ConnectDlg.GetSelectedAddress();
-
- // only store new host address in our data base if the address is
- // not empty and it was not a server list item (only the addresses
- // typed in manually are stored by definition)
- if ( !strSelectedAddress.isEmpty() && !ConnectDlg.GetServerListItemWasChosen() )
- {
- // store new address at the top of the list, if the list was already
- // full, the last element is thrown out
- pSettings->vstrIPAddress.StringFiFoWithCompare ( strSelectedAddress );
- }
-
- // get name to be set in audio mixer group box title
- QString strMixerBoardLabel;
-
- if ( ConnectDlg.GetServerListItemWasChosen() )
- {
- // in case a server in the server list was chosen,
- // display the server name of the server list
- strMixerBoardLabel = ConnectDlg.GetSelectedServerName();
- }
- else
- {
- // an item of the server address combo box was chosen,
- // just show the address string as it was entered by the
- // user
- strMixerBoardLabel = strSelectedAddress;
-
- // special case: if the address is empty, we substitute the default
- // directory address so that a user who just pressed the connect
- // button without selecting an item in the table or manually entered an
- // address gets a successful connection
- if ( strSelectedAddress.isEmpty() )
- {
- strSelectedAddress = DEFAULT_SERVER_ADDRESS;
- strMixerBoardLabel = tr ( "%1 Directory" ).arg ( DirectoryTypeToString ( AT_DEFAULT ) );
- }
- }
-
- // first check if we are already connected, if this is the case we have to
- // disconnect the old server first
- if ( pClient->IsRunning() )
- {
- Disconnect();
- }
-
- // initiate connection
- Connect ( strSelectedAddress, strMixerBoardLabel );
-
- // reset flag
- bConnectDlgWasShown = false;
- }
-}
-
-void CClientDlg::OnConnectDisconBut()
-{
- // the connect/disconnect button implements a toggle functionality
- if ( pClient->IsRunning() )
- {
- Disconnect();
- SetMixerBoardDeco ( RS_UNDEFINED, pClient->GetGUIDesign() );
- }
- else
- {
- ShowConnectionSetupDialog();
- }
-}
-
-void CClientDlg::OnClearAllStoredSoloMuteSettings()
-{
- // if we are in an active connection, we first have to store all fader settings in
- // the settings struct, clear the solo and mute states and then apply the settings again
- MainMixerBoard->StoreAllFaderSettings();
- pSettings->vecStoredFaderIsSolo.Reset ( false );
- pSettings->vecStoredFaderIsMute.Reset ( false );
- MainMixerBoard->LoadAllFaderSettings();
-}
-
-void CClientDlg::OnLoadChannelSetup()
-{
- QString strFileName = QFileDialog::getOpenFileName ( this, tr ( "Select Channel Setup File" ), "", QString ( "*." ) + MIX_SETTINGS_FILE_SUFFIX );
-
- if ( !strFileName.isEmpty() )
- {
- // first update the settings struct and then update the mixer panel
- pSettings->LoadFaderSettings ( strFileName );
- MainMixerBoard->LoadAllFaderSettings();
- }
-}
-
-void CClientDlg::OnSaveChannelSetup()
-{
- QString strFileName = QFileDialog::getSaveFileName ( this, tr ( "Select Channel Setup File" ), "", QString ( "*." ) + MIX_SETTINGS_FILE_SUFFIX );
-
- if ( !strFileName.isEmpty() )
- {
- // first store all current fader settings (in case we are in an active connection
- // right now) and then save the information in the settings struct in the file
- MainMixerBoard->StoreAllFaderSettings();
- pSettings->SaveFaderSettings ( strFileName );
- }
-}
-
-void CClientDlg::OnVersionAndOSReceived ( COSUtil::EOpSystemType, QString strVersion )
-{
- // check if Pan is supported by the server (minimum version is 3.5.4)
-#if QT_VERSION >= QT_VERSION_CHECK( 5, 6, 0 )
- if ( QVersionNumber::compare ( QVersionNumber::fromString ( strVersion ), QVersionNumber ( 3, 5, 4 ) ) >= 0 )
- {
- MainMixerBoard->SetPanIsSupported();
- }
-#endif
-}
-
-void CClientDlg::OnCLVersionAndOSReceived ( CHostAddress InetAddr, COSUtil::EOpSystemType, QString strVersion )
-{
- // display version in connect dialog
- ConnectDlg.SetServerVersionResult ( InetAddr, strVersion );
-
- // update check
-#if ( QT_VERSION >= QT_VERSION_CHECK( 5, 6, 0 ) ) && !defined( DISABLE_VERSION_CHECK )
- int mySuffixIndex;
- QVersionNumber myVersion = QVersionNumber::fromString ( VERSION, &mySuffixIndex );
-
- int serverSuffixIndex;
- QVersionNumber serverVersion = QVersionNumber::fromString ( strVersion, &serverSuffixIndex );
-
- // only compare if the server version has no suffix (such as dev or beta)
- if ( strVersion.size() == serverSuffixIndex && QVersionNumber::compare ( serverVersion, myVersion ) > 0 )
- {
- // show the label and hide it after one minute again
- lblUpdateCheck->show();
- QTimer::singleShot ( 60000, [this]() { lblUpdateCheck->hide(); } );
- }
-#endif
-}
-
-void CClientDlg::OnChatTextReceived ( QString strChatText )
-{
- if ( pSettings->bEnableAudioAlerts )
- {
- QSoundEffect* sf = new QSoundEffect();
- sf->setSource ( QUrl::fromLocalFile ( ":sounds/res/sounds/new_message.wav" ) );
- sf->play();
- }
- ChatDlg.AddChatText ( strChatText );
-
- // Open chat dialog. If a server welcome message is received, we force
- // the dialog to be upfront in case a licence text is shown. For all
- // other new chat texts we do not want to force the dialog to be upfront
- // always when a new message arrives since this is annoying.
- ShowChatWindow ( ( strChatText.indexOf ( WELCOME_MESSAGE_PREFIX ) == 0 ) );
-
- UpdateDisplay();
-}
-
-void CClientDlg::OnLicenceRequired ( ELicenceType eLicenceType )
-{
- // right now only the creative common licence is supported
- if ( eLicenceType == LT_CREATIVECOMMONS )
- {
- CLicenceDlg LicenceDlg;
-
- // mute the client output stream
- pClient->SetMuteOutStream ( true );
-
- // Open the licence dialog and check if the licence was accepted. In
- // case the dialog is just closed or the decline button was pressed,
- // disconnect from that server.
- if ( !LicenceDlg.exec() )
- {
- Disconnect();
- }
-
- // unmute the client output stream if local mute button is not pressed
- if ( chbLocalMute->checkState() == Qt::Unchecked )
- {
- pClient->SetMuteOutStream ( false );
- }
- }
-}
-
-void CClientDlg::OnConClientListMesReceived ( CVector vecChanInfo )
-{
- // update mixer board with the additional client infos
- MainMixerBoard->ApplyNewConClientList ( vecChanInfo );
-}
-
-void CClientDlg::OnNumClientsChanged ( int iNewNumClients )
-{
- if ( pSettings->bEnableAudioAlerts && iNewNumClients > iClients )
- {
- QSoundEffect* sf = new QSoundEffect();
- sf->setSource ( QUrl::fromLocalFile ( ":sounds/res/sounds/new_user.wav" ) );
- sf->play();
- }
-
- // iNewNumClients will be zero on the first trigger of this signal handler when connecting to a new server.
- // Subsequent triggers will thus sound the alert (if enabled).
- iClients = iNewNumClients;
-
- // update window title
- SetMyWindowTitle ( iNewNumClients );
-}
-
-void CClientDlg::OnOpenAudioNetSettings() { ShowGeneralSettings ( SETTING_TAB_AUDIONET ); }
-
-void CClientDlg::OnOpenAdvancedSettings() { ShowGeneralSettings ( SETTING_TAB_ADVANCED ); }
-
-void CClientDlg::OnOpenUserProfileSettings() { ShowGeneralSettings ( SETTING_TAB_USER ); }
-
-void CClientDlg::SetMyWindowTitle ( const int iNumClients )
-{
- // set the window title (and therefore also the task bar icon text of the OS)
- // according to the following specification (#559):
- // - users - Jamulus
- QString strWinTitle;
- const bool bClientNameIsUsed = !pClient->strClientName.isEmpty();
-
- if ( bClientNameIsUsed )
- {
- // if --clientname is used, the APP_NAME must be the very first word in
- // the title, otherwise some user scripts do not work anymore, see #789
- strWinTitle += QString ( APP_NAME ) + " - " + pClient->strClientName + " ";
- }
-
- if ( iNumClients == 0 )
- {
- // only application name
- if ( !bClientNameIsUsed ) // if --clientname is used, the APP_NAME is the first word in title
- {
- strWinTitle += QString ( APP_NAME );
- }
- }
- else
- {
- strWinTitle += MainMixerBoard->GetServerName();
-
- if ( iNumClients == 1 )
- {
- strWinTitle += " - 1 " + tr ( "user" );
- }
- else if ( iNumClients > 1 )
- {
- strWinTitle += " - " + QString::number ( iNumClients ) + " " + tr ( "users" );
- }
-
- if ( !bClientNameIsUsed ) // if --clientname is used, the APP_NAME is the first word in title
- {
- strWinTitle += " - " + QString ( APP_NAME );
- }
- }
-
- setWindowTitle ( strWinTitle );
-
-#if defined( Q_OS_MACOS )
- // for MacOS only we show the number of connected clients as a
- // badge label text if more than one user is connected
- if ( iNumClients > 1 )
- {
- // show the number of connected clients
- SetMacBadgeLabelText ( QString ( "%1" ).arg ( iNumClients ) );
- }
- else
- {
- // clear the text (apply an empty string)
- SetMacBadgeLabelText ( "" );
- }
-#endif
-}
-
-void CClientDlg::ShowConnectionSetupDialog()
-{
- // show connect dialog
- bConnectDlgWasShown = true;
- ConnectDlg.show();
- ConnectDlg.setWindowTitle ( MakeClientNameTitle ( tr ( "Connect" ), pClient->strClientName ) );
-
- // make sure dialog is upfront and has focus
- ConnectDlg.raise();
- ConnectDlg.activateWindow();
-}
-
-void CClientDlg::ShowGeneralSettings ( int iTab )
-{
- // open general settings dialog
- emit SendTabChange ( iTab );
- ClientSettingsDlg.show();
- ClientSettingsDlg.setWindowTitle ( MakeClientNameTitle ( tr ( "Settings" ), pClient->strClientName ) );
-
- // make sure dialog is upfront and has focus
- ClientSettingsDlg.raise();
- ClientSettingsDlg.activateWindow();
-}
-
-void CClientDlg::ShowChatWindow ( const bool bForceRaise )
-{
- ChatDlg.show();
- ChatDlg.setWindowTitle ( MakeClientNameTitle ( tr ( "Chat" ), pClient->strClientName ) );
-
- if ( bForceRaise )
- {
- // make sure dialog is upfront and has focus
- ChatDlg.showNormal();
- ChatDlg.raise();
- ChatDlg.activateWindow();
- }
-
- UpdateDisplay();
-}
-
-void CClientDlg::ShowAnalyzerConsole()
-{
- // open analyzer console dialog
- AnalyzerConsole.show();
-
- // make sure dialog is upfront and has focus
- AnalyzerConsole.raise();
- AnalyzerConsole.activateWindow();
-}
-
-void CClientDlg::OnSettingsStateChanged ( int value )
-{
- if ( value == Qt::Checked )
- {
- ShowGeneralSettings ( SETTING_TAB_AUDIONET );
- }
- else
- {
- ClientSettingsDlg.hide();
- }
-}
-
-void CClientDlg::OnChatStateChanged ( int value )
-{
- if ( value == Qt::Checked )
- {
- ShowChatWindow();
- }
- else
- {
- ChatDlg.hide();
- }
-}
-
-void CClientDlg::OnLocalMuteStateChanged ( int value )
-{
- pClient->SetMuteOutStream ( value == Qt::Checked );
-
- // show/hide info label
- if ( value == Qt::Checked )
- {
- lblGlobalInfoLabel->show();
- }
- else
- {
- lblGlobalInfoLabel->hide();
- }
-}
-
-void CClientDlg::OnTimerSigMet()
-{
- // show current level
- lbrInputLevelL->SetValue ( pClient->GetLevelForMeterdBLeft() );
- lbrInputLevelR->SetValue ( pClient->GetLevelForMeterdBRight() );
-
- if ( bDetectFeedback &&
- ( pClient->GetLevelForMeterdBLeft() > NUM_STEPS_LED_BAR - 0.5 || pClient->GetLevelForMeterdBRight() > NUM_STEPS_LED_BAR - 0.5 ) )
- {
- // mute locally and mute channel
- chbLocalMute->setCheckState ( Qt::Checked );
- MainMixerBoard->MuteMyChannel();
-
- // show message box about feedback issue
- QCheckBox* chb = new QCheckBox ( tr ( "Enable feedback detection" ) );
- chb->setCheckState ( pSettings->bEnableFeedbackDetection ? Qt::Checked : Qt::Unchecked );
- QMessageBox msgbox;
- msgbox.setText ( tr ( "Audio feedback or loud signal detected.\n\n"
- "We muted your channel and activated 'Mute Myself'. Please solve "
- "the feedback issue first and unmute yourself afterwards." ) );
- msgbox.setIcon ( QMessageBox::Icon::Warning );
- msgbox.addButton ( QMessageBox::Ok );
- msgbox.setDefaultButton ( QMessageBox::Ok );
- msgbox.setCheckBox ( chb );
-
- QObject::connect ( chb, &QCheckBox::stateChanged, this, &CClientDlg::OnFeedbackDetectionChanged );
-
- msgbox.exec();
- }
-}
-
-void CClientDlg::OnTimerBuffersLED()
-{
- CMultiColorLED::ELightColor eCurStatus;
-
- // get and reset current buffer state and set LED from that flag
- if ( pClient->GetAndResetbJitterBufferOKFlag() )
- {
- eCurStatus = CMultiColorLED::RL_GREEN;
- }
- else
- {
- eCurStatus = CMultiColorLED::RL_RED;
- }
-
- // update the buffer LED and the general settings dialog, too
- ledBuffers->SetLight ( eCurStatus );
-}
-
-void CClientDlg::OnTimerPing()
-{
- // send ping message to the server
- pClient->CreateCLPingMes();
-}
-
-void CClientDlg::OnPingTimeResult ( int iPingTime )
-{
- // calculate overall delay
- const int iOverallDelayMs = pClient->EstimatedOverallDelay ( iPingTime );
-
- // color definition: <= 43 ms green, <= 68 ms yellow, otherwise red
- CMultiColorLED::ELightColor eOverallDelayLEDColor;
-
- if ( iOverallDelayMs <= 43 )
- {
- eOverallDelayLEDColor = CMultiColorLED::RL_GREEN;
- }
- else
- {
- if ( iOverallDelayMs <= 68 )
- {
- eOverallDelayLEDColor = CMultiColorLED::RL_YELLOW;
- }
- else
- {
- eOverallDelayLEDColor = CMultiColorLED::RL_RED;
- }
- }
-
- // only update delay information on settings dialog if it is visible to
- // avoid CPU load on working thread if not necessary
- if ( ClientSettingsDlg.isVisible() )
- {
- // set ping time result to general settings dialog
- ClientSettingsDlg.UpdateUploadRate();
- }
- SetPingTime ( iPingTime, iOverallDelayMs, eOverallDelayLEDColor );
-
- // update delay LED on the main window
- ledDelay->SetLight ( eOverallDelayLEDColor );
-}
-
-void CClientDlg::OnTimerCheckAudioDeviceOk()
-{
- // check if the audio device entered the audio callback after a pre-defined
- // timeout to check if a valid device is selected and if we do not have
- // fundamental settings errors (in which case the GUI would only show that
- // it is trying to connect the server which does not help to solve the problem (#129))
- if ( !pClient->IsCallbackEntered() )
- {
- QMessageBox::warning ( this,
- APP_NAME,
- tr ( "Your sound card is not working correctly. "
- "Please open the settings dialog and check the device selection and the driver settings." ) );
- }
-}
-
-void CClientDlg::OnTimerDetectFeedback() { bDetectFeedback = false; }
-
-void CClientDlg::OnSoundDeviceChanged ( QString strError )
-{
- if ( !strError.isEmpty() )
- {
- // the sound device setup has a problem, disconnect any active connection
- if ( pClient->IsRunning() )
- {
- Disconnect();
- }
-
- // show the error message of the device setup
- QMessageBox::critical ( this, APP_NAME, strError, tr ( "Ok" ), nullptr );
- }
-
- // if the check audio device timer is running, it must be restarted on a device change
- if ( TimerCheckAudioDeviceOk.isActive() )
- {
- TimerCheckAudioDeviceOk.start ( CHECK_AUDIO_DEV_OK_TIME_MS );
- }
-
- if ( pSettings->bEnableFeedbackDetection && TimerDetectFeedback.isActive() )
- {
- TimerDetectFeedback.start ( DETECT_FEEDBACK_TIME_MS );
- bDetectFeedback = true;
- }
-
- // update the settings dialog
- ClientSettingsDlg.UpdateSoundDeviceChannelSelectionFrame();
-}
-
-void CClientDlg::OnCLPingTimeWithNumClientsReceived ( CHostAddress InetAddr, int iPingTime, int iNumClients )
-{
- // update connection dialog server list
- ConnectDlg.SetPingTimeAndNumClientsResult ( InetAddr, iPingTime, iNumClients );
-}
-
-void CClientDlg::Connect ( const QString& strSelectedAddress, const QString& strMixerBoardLabel )
-{
- // set address and check if address is valid
- if ( pClient->SetServerAddr ( strSelectedAddress ) )
- {
- // try to start client, if error occurred, do not go in
- // running state but show error message
- try
- {
- if ( !pClient->IsRunning() )
- {
- pClient->Start();
- }
- }
-
- catch ( const CGenErr& generr )
- {
- // show error message and return the function
- QMessageBox::critical ( this, APP_NAME, generr.GetErrorText(), "Close", nullptr );
- return;
- }
-
- // hide label connect to server
- lblConnectToServer->hide();
- lbrInputLevelL->setEnabled ( true );
- lbrInputLevelR->setEnabled ( true );
-
- // change connect button text to "disconnect"
- butConnect->setText ( tr ( "&Disconnect" ) );
-
- // set server name in audio mixer group box title
- MainMixerBoard->SetServerName ( strMixerBoardLabel );
-
- // start timer for level meter bar and ping time measurement
- TimerSigMet.start ( LEVELMETER_UPDATE_TIME_MS );
- TimerBuffersLED.start ( BUFFER_LED_UPDATE_TIME_MS );
- TimerPing.start ( PING_UPDATE_TIME_MS );
- TimerCheckAudioDeviceOk.start ( CHECK_AUDIO_DEV_OK_TIME_MS ); // is single shot timer
-
- // audio feedback detection
- if ( pSettings->bEnableFeedbackDetection )
- {
- TimerDetectFeedback.start ( DETECT_FEEDBACK_TIME_MS ); // single shot timer
- bDetectFeedback = true;
- }
- }
-}
-
-void CClientDlg::Disconnect()
-{
- // only stop client if currently running, in case we received
- // the stopped message, the client is already stopped but the
- // connect/disconnect button and other GUI controls must be
- // updated
- if ( pClient->IsRunning() )
- {
- pClient->Stop();
- }
-
- // change connect button text to "connect"
- butConnect->setText ( tr ( "C&onnect" ) );
-
- // reset server name in audio mixer group box title
- MainMixerBoard->SetServerName ( "" );
-
- // stop timer for level meter bars and reset them
- TimerSigMet.stop();
- lbrInputLevelL->setEnabled ( false );
- lbrInputLevelR->setEnabled ( false );
- lbrInputLevelL->SetValue ( 0 );
- lbrInputLevelR->SetValue ( 0 );
-
- // show connect to server message
- lblConnectToServer->show();
-
- // stop other timers
- TimerBuffersLED.stop();
- TimerPing.stop();
- TimerCheckAudioDeviceOk.stop();
- TimerDetectFeedback.stop();
- bDetectFeedback = false;
-
- //### TODO: BEGIN ###//
- // is this still required???
- // immediately update status bar
- OnTimerStatus();
- //### TODO: END ###//
-
- // reset LEDs
- ledBuffers->Reset();
- ledDelay->Reset();
-
- // clear text labels with client parameters
- lblPingVal->setText ( "---" );
- lblPingUnit->setText ( "" );
- lblDelayVal->setText ( "---" );
- lblDelayUnit->setText ( "" );
-
- // clear mixer board (remove all faders)
- MainMixerBoard->HideAll();
-}
-
-void CClientDlg::UpdateDisplay()
-{
- // update settings/chat buttons (do not fire signals since it is an update)
- if ( chbSettings->isChecked() && !ClientSettingsDlg.isVisible() )
- {
- chbSettings->blockSignals ( true );
- chbSettings->setChecked ( false );
- chbSettings->blockSignals ( false );
- }
- if ( !chbSettings->isChecked() && ClientSettingsDlg.isVisible() )
- {
- chbSettings->blockSignals ( true );
- chbSettings->setChecked ( true );
- chbSettings->blockSignals ( false );
- }
-
- if ( chbChat->isChecked() && !ChatDlg.isVisible() )
- {
- chbChat->blockSignals ( true );
- chbChat->setChecked ( false );
- chbChat->blockSignals ( false );
- }
- if ( !chbChat->isChecked() && ChatDlg.isVisible() )
- {
- chbChat->blockSignals ( true );
- chbChat->setChecked ( true );
- chbChat->blockSignals ( false );
- }
-}
-
-void CClientDlg::SetGUIDesign ( const EGUIDesign eNewDesign )
-{
- // remove any styling from the mixer board - reapply after changing skin
- MainMixerBoard->setStyleSheet ( "" );
-
- // apply GUI design to current window
- switch ( eNewDesign )
- {
- case GD_ORIGINAL:
- backgroundFrame->setStyleSheet (
- "QFrame#backgroundFrame { border-image: url(:/png/fader/res/mixerboardbackground.png) 34px 30px 40px 40px;"
- " border-top: 34px transparent;"
- " border-bottom: 40px transparent;"
- " border-left: 30px transparent;"
- " border-right: 40px transparent;"
- " padding: -5px;"
- " margin: -5px, -5px, 0px, 0px; }"
- "QLabel { color: rgb(220, 220, 220);"
- " font: bold; }"
- "QRadioButton { color: rgb(220, 220, 220);"
- " font: bold; }"
- "QScrollArea { background: transparent; }"
- ".QWidget { background: transparent; }" // note: matches instances of QWidget, but not of its subclasses
- "QGroupBox { background: transparent; }"
- "QGroupBox::title { color: rgb(220, 220, 220); }"
- "QCheckBox::indicator { width: 38px;"
- " height: 21px; }"
- "QCheckBox::indicator:unchecked {"
- " image: url(:/png/fader/res/ledbuttonnotpressed.png); }"
- "QCheckBox::indicator:checked {"
- " image: url(:/png/fader/res/ledbuttonpressed.png); }"
- "QCheckBox { color: rgb(220, 220, 220);"
- " font: bold; }" );
-#ifdef _WIN32
- // Workaround QT-Windows problem: This should not be necessary since in the
- // background frame the style sheet for QRadioButton was already set. But it
- // seems that it is only applied if the style was set to default and then back
- // to GD_ORIGINAL. This seems to be a QT related issue...
- rbtReverbSelL->setStyleSheet ( "color: rgb(220, 220, 220);"
- "font: bold;" );
- rbtReverbSelR->setStyleSheet ( "color: rgb(220, 220, 220);"
- "font: bold;" );
-#endif
-
- ledBuffers->SetType ( CMultiColorLED::MT_LED );
- ledDelay->SetType ( CMultiColorLED::MT_LED );
- break;
-
- default:
- // reset style sheet and set original parameters
- backgroundFrame->setStyleSheet ( "" );
-
-#ifdef _WIN32
- // Workaround QT-Windows problem: See above description
- rbtReverbSelL->setStyleSheet ( "" );
- rbtReverbSelR->setStyleSheet ( "" );
-#endif
-
- ledBuffers->SetType ( CMultiColorLED::MT_INDICATOR );
- ledDelay->SetType ( CMultiColorLED::MT_INDICATOR );
- break;
- }
-
- // also apply GUI design to child GUI controls
- MainMixerBoard->SetGUIDesign ( eNewDesign );
-}
-
-void CClientDlg::SetMeterStyle ( const EMeterStyle eNewMeterStyle )
-{
- // apply MeterStyle to current window
- switch ( eNewMeterStyle )
- {
- case MT_LED_STRIPE:
- lbrInputLevelL->SetLevelMeterType ( CLevelMeter::MT_LED_STRIPE );
- lbrInputLevelR->SetLevelMeterType ( CLevelMeter::MT_LED_STRIPE );
- break;
-
- case MT_LED_ROUND_BIG:
- lbrInputLevelL->SetLevelMeterType ( CLevelMeter::MT_LED_ROUND_BIG );
- lbrInputLevelR->SetLevelMeterType ( CLevelMeter::MT_LED_ROUND_BIG );
- break;
-
- case MT_BAR_WIDE:
- lbrInputLevelL->SetLevelMeterType ( CLevelMeter::MT_BAR_WIDE );
- lbrInputLevelR->SetLevelMeterType ( CLevelMeter::MT_BAR_WIDE );
- break;
-
- case MT_BAR_NARROW:
- lbrInputLevelL->SetLevelMeterType ( CLevelMeter::MT_BAR_WIDE );
- lbrInputLevelR->SetLevelMeterType ( CLevelMeter::MT_BAR_WIDE );
- break;
-
- case MT_LED_ROUND_SMALL:
- lbrInputLevelL->SetLevelMeterType ( CLevelMeter::MT_LED_ROUND_BIG );
- lbrInputLevelR->SetLevelMeterType ( CLevelMeter::MT_LED_ROUND_BIG );
- break;
- }
-
- // also apply MeterStyle to child GUI controls
- MainMixerBoard->SetMeterStyle ( eNewMeterStyle );
-}
-
-void CClientDlg::OnRecorderStateReceived ( const ERecorderState newRecorderState )
-{
- MainMixerBoard->SetRecorderState ( newRecorderState );
- SetMixerBoardDeco ( newRecorderState, pClient->GetGUIDesign() );
-}
-
-void CClientDlg::OnGUIDesignChanged()
-{
- SetGUIDesign ( pClient->GetGUIDesign() );
- SetMixerBoardDeco ( MainMixerBoard->GetRecorderState(), pClient->GetGUIDesign() );
-}
-
-void CClientDlg::OnMeterStyleChanged() { SetMeterStyle ( pClient->GetMeterStyle() ); }
-
-void CClientDlg::SetMixerBoardDeco ( const ERecorderState newRecorderState, const EGUIDesign eNewDesign )
-{
- // return if no change
- if ( ( newRecorderState == eLastRecorderState ) && ( eNewDesign == eLastDesign ) )
- return;
- eLastRecorderState = newRecorderState;
- eLastDesign = eNewDesign;
-
- // set base style
- QString sTitleStyle = "QGroupBox::title { subcontrol-origin: margin;"
- " subcontrol-position: left top;"
- " left: 7px;";
-
- if ( newRecorderState == RS_RECORDING )
- {
- sTitleStyle += "color: rgb(255,255,255);"
- "background-color: rgb(255,0,0); }";
- }
- else
- {
- if ( eNewDesign == GD_ORIGINAL )
- {
- // no need to set the background color for dark mode in fancy skin, as the background is already dark.
- sTitleStyle += "color: rgb(220,220,220); }";
- }
- else
- {
- if ( palette().color ( QPalette::Window ) == QColor::fromRgbF ( 0.196078, 0.196078, 0.196078, 1 ) )
- {
- // Dark mode on macOS/Linux needs a light color
-
- sTitleStyle += "color: rgb(220,220,220); }";
- }
- else
- {
- sTitleStyle += "color: rgb(0,0,0); }";
- }
- }
- }
-
- MainMixerBoard->setStyleSheet ( sTitleStyle );
-}
-
-void CClientDlg::SetPingTime ( const int iPingTime, const int iOverallDelayMs, const CMultiColorLED::ELightColor eOverallDelayLEDColor )
-{
- // apply values to GUI labels, take special care if ping time exceeds
- // a certain value
- if ( iPingTime > 500 )
- {
- const QString sErrorText = ">500";
- lblPingVal->setText ( sErrorText );
- lblDelayVal->setText ( sErrorText );
- }
- else
- {
- lblPingVal->setText ( QString().setNum ( iPingTime ) );
- lblDelayVal->setText ( QString().setNum ( iOverallDelayMs ) );
- }
- lblPingUnit->setText ( "ms" );
- lblDelayUnit->setText ( "ms" );
-
- // set current LED status
- ledDelay->SetLight ( eOverallDelayLEDColor );
-}
diff --git a/src/clientdlg.h b/src/clientdlg.h
deleted file mode 100644
index 2a9062a58d..0000000000
--- a/src/clientdlg.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/******************************************************************************\
- * Copyright (c) 2004-2024
- *
- * Author(s):
- * Volker Fischer
- *
- ******************************************************************************
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- *
-\******************************************************************************/
-
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#if QT_VERSION >= QT_VERSION_CHECK( 5, 6, 0 )
-# include
-#endif
-#include "global.h"
-#include "util.h"
-#include "client.h"
-#include "settings.h"
-#include "multicolorled.h"
-#include "audiomixerboard.h"
-#include "clientsettingsdlg.h"
-#include "chatdlg.h"
-#include "connectdlg.h"
-#include "analyzerconsole.h"
-#include "ui_clientdlgbase.h"
-#if defined( Q_OS_MACOS )
-# include "mac/badgelabel.h"
-#endif
-
-/* Definitions ****************************************************************/
-// update time for GUI controls
-#define LEVELMETER_UPDATE_TIME_MS 100 // ms
-#define BUFFER_LED_UPDATE_TIME_MS 300 // ms
-#define LED_BAR_UPDATE_TIME_MS 1000 // ms
-#define CHECK_AUDIO_DEV_OK_TIME_MS 5000 // ms
-#define DETECT_FEEDBACK_TIME_MS 3000 // ms
-
-// number of ping times > upper bound until error message is shown
-#define NUM_HIGH_PINGS_UNTIL_ERROR 5
-
-/* Classes ********************************************************************/
-class CClientDlg : public CBaseDlg, private Ui_CClientDlgBase
-{
- Q_OBJECT
-
-public:
- CClientDlg ( CClient* pNCliP,
- CClientSettings* pNSetP,
- const QString& strConnOnStartupAddress,
- const QString& strMIDISetup,
- const bool bNewShowComplRegConnList,
- const bool bShowAnalyzerConsole,
- const bool bMuteStream,
- const bool bNEnableIPv6,
- QWidget* parent = nullptr );
-
-protected:
- void SetGUIDesign ( const EGUIDesign eNewDesign );
- void SetMeterStyle ( const EMeterStyle eNewMeterStyle );
- void SetMyWindowTitle ( const int iNumClients );
- void ShowConnectionSetupDialog();
- void ShowGeneralSettings ( int iTab );
- void ShowChatWindow ( const bool bForceRaise = true );
- void ShowAnalyzerConsole();
- void UpdateAudioFaderSlider();
- void UpdateRevSelection();
- void Connect ( const QString& strSelectedAddress, const QString& strMixerBoardLabel );
- void Disconnect();
- void ManageDragNDrop ( QDropEvent* Event, const bool bCheckAccept );
- void SetPingTime ( const int iPingTime, const int iOverallDelayMs, const CMultiColorLED::ELightColor eOverallDelayLEDColor );
-
- CClient* pClient;
- CClientSettings* pSettings;
-
- int iClients;
- bool bConnected;
- bool bConnectDlgWasShown;
- bool bDetectFeedback;
- bool bEnableIPv6;
- ERecorderState eLastRecorderState;
- EGUIDesign eLastDesign;
- QTimer TimerSigMet;
- QTimer TimerBuffersLED;
- QTimer TimerStatus;
- QTimer TimerPing;
- QTimer TimerCheckAudioDeviceOk;
- QTimer TimerDetectFeedback;
-
- virtual void closeEvent ( QCloseEvent* Event );
- virtual void dragEnterEvent ( QDragEnterEvent* Event ) { ManageDragNDrop ( Event, true ); }
- virtual void dropEvent ( QDropEvent* Event ) { ManageDragNDrop ( Event, false ); }
- void UpdateDisplay();
-
- CClientSettingsDlg ClientSettingsDlg;
- CChatDlg ChatDlg;
- CConnectDlg ConnectDlg;
- CAnalyzerConsole AnalyzerConsole;
-
-public slots:
- void OnConnectDisconBut();
- void OnTimerSigMet();
- void OnTimerBuffersLED();
- void OnTimerCheckAudioDeviceOk();
- void OnTimerDetectFeedback();
-
- void OnTimerStatus() { UpdateDisplay(); }
-
- void OnTimerPing();
- void OnPingTimeResult ( int iPingTime );
- void OnCLPingTimeWithNumClientsReceived ( CHostAddress InetAddr, int iPingTime, int iNumClients );
-
- void OnControllerInFaderLevel ( const int iChannelIdx, const int iValue ) { MainMixerBoard->SetFaderLevel ( iChannelIdx, iValue ); }
-
- void OnControllerInPanValue ( const int iChannelIdx, const int iValue ) { MainMixerBoard->SetPanValue ( iChannelIdx, iValue ); }
-
- void OnControllerInFaderIsSolo ( const int iChannelIdx, const bool bIsSolo ) { MainMixerBoard->SetFaderIsSolo ( iChannelIdx, bIsSolo ); }
-
- void OnControllerInFaderIsMute ( const int iChannelIdx, const bool bIsMute ) { MainMixerBoard->SetFaderIsMute ( iChannelIdx, bIsMute ); }
-
- void OnControllerInMuteMyself ( const bool bMute ) { chbLocalMute->setChecked ( bMute ); }
-
- void OnVersionAndOSReceived ( COSUtil::EOpSystemType, QString strVersion );
-
- void OnCLVersionAndOSReceived ( CHostAddress, COSUtil::EOpSystemType, QString strVersion );
-
- void OnLoadChannelSetup();
- void OnSaveChannelSetup();
- void OnOpenConnectionSetupDialog() { ShowConnectionSetupDialog(); }
- void OnOpenUserProfileSettings();
- void OnOpenAudioNetSettings();
- void OnOpenAdvancedSettings();
- void OnOpenChatDialog() { ShowChatWindow(); }
- void OnOpenAnalyzerConsole() { ShowAnalyzerConsole(); }
- void OnOwnFaderFirst()
- {
- pSettings->bOwnFaderFirst = !pSettings->bOwnFaderFirst;
- MainMixerBoard->SetFaderSorting ( pSettings->eChannelSortType );
- }
- void OnNoSortChannels() { MainMixerBoard->SetFaderSorting ( ST_NO_SORT ); }
- void OnSortChannelsByName() { MainMixerBoard->SetFaderSorting ( ST_BY_NAME ); }
- void OnSortChannelsByInstrument() { MainMixerBoard->SetFaderSorting ( ST_BY_INSTRUMENT ); }
- void OnSortChannelsByGroupID() { MainMixerBoard->SetFaderSorting ( ST_BY_GROUPID ); }
- void OnSortChannelsByCity() { MainMixerBoard->SetFaderSorting ( ST_BY_CITY ); }
- void OnSortChannelsByChannel() { MainMixerBoard->SetFaderSorting ( ST_BY_SERVER_CHANNEL ); }
- void OnClearAllStoredSoloMuteSettings();
- void OnSetAllFadersToNewClientLevel() { MainMixerBoard->SetAllFaderLevelsToNewClientLevel(); }
- void OnAutoAdjustAllFaderLevels() { MainMixerBoard->AutoAdjustAllFaderLevels(); }
- void OnNumMixerPanelRowsChanged ( int value ) { MainMixerBoard->SetNumMixerPanelRows ( value ); }
-
- void OnSettingsStateChanged ( int value );
- void OnChatStateChanged ( int value );
- void OnLocalMuteStateChanged ( int value );
-
- void OnAudioReverbValueChanged ( int value ) { pClient->SetReverbLevel ( value ); }
-
- void OnReverbSelLClicked() { pClient->SetReverbOnLeftChan ( true ); }
-
- void OnReverbSelRClicked() { pClient->SetReverbOnLeftChan ( false ); }
-
- void OnFeedbackDetectionChanged ( int state ) { ClientSettingsDlg.SetEnableFeedbackDetection ( state == Qt::Checked ); }
-
- void OnConClientListMesReceived ( CVector vecChanInfo );
- void OnChatTextReceived ( QString strChatText );
- void OnLicenceRequired ( ELicenceType eLicenceType );
- void OnSoundDeviceChanged ( QString strError );
-
- void OnChangeChanGain ( int iId, float fGain, bool bIsMyOwnFader ) { pClient->SetRemoteChanGain ( iId, fGain, bIsMyOwnFader ); }
-
- void OnChangeChanPan ( int iId, float fPan ) { pClient->SetRemoteChanPan ( iId, fPan ); }
-
- void OnNewLocalInputText ( QString strChatText ) { pClient->CreateChatTextMes ( strChatText ); }
-
- void OnReqServerListQuery ( CHostAddress InetAddr ) { pClient->CreateCLReqServerListMes ( InetAddr ); }
-
- void OnCreateCLServerListPingMes ( CHostAddress InetAddr ) { pClient->CreateCLServerListPingMes ( InetAddr ); }
-
- void OnCreateCLServerListReqVerAndOSMes ( CHostAddress InetAddr ) { pClient->CreateCLServerListReqVerAndOSMes ( InetAddr ); }
-
- void OnCreateCLServerListReqConnClientsListMes ( CHostAddress InetAddr ) { pClient->CreateCLServerListReqConnClientsListMes ( InetAddr ); }
-
- void OnCLServerListReceived ( CHostAddress InetAddr, CVector vecServerInfo )
- {
- ConnectDlg.SetServerList ( InetAddr, vecServerInfo );
- }
-
- void OnCLRedServerListReceived ( CHostAddress InetAddr, CVector vecServerInfo )
- {
- ConnectDlg.SetServerList ( InetAddr, vecServerInfo, true );
- }
-
- void OnCLConnClientsListMesReceived ( CHostAddress InetAddr, CVector vecChanInfo )
- {
- ConnectDlg.SetConnClientsList ( InetAddr, vecChanInfo );
- }
-
- void OnClientIDReceived ( int iChanID ) { MainMixerBoard->SetMyChannelID ( iChanID ); }
-
- void OnMuteStateHasChangedReceived ( int iChanID, bool bIsMuted ) { MainMixerBoard->SetRemoteFaderIsMute ( iChanID, bIsMuted ); }
-
- void OnCLChannelLevelListReceived ( CHostAddress /* unused */, CVector vecLevelList )
- {
- MainMixerBoard->SetChannelLevels ( vecLevelList );
- }
-
- void OnConnectDlgAccepted();
- void OnDisconnected() { Disconnect(); }
- void OnGUIDesignChanged();
- void OnMeterStyleChanged();
- void OnRecorderStateReceived ( ERecorderState eRecorderState );
- void SetMixerBoardDeco ( const ERecorderState newRecorderState, const EGUIDesign eNewDesign );
- void OnAudioChannelsChanged() { UpdateRevSelection(); }
- void OnNumClientsChanged ( int iNewNumClients );
-
- void accept() { close(); } // introduced by pljones
-
-signals:
- void SendTabChange ( int iTabIdx );
-};
diff --git a/src/clientdlgbase.ui b/src/clientdlgbase.ui
deleted file mode 100644
index 0c652d7325..0000000000
--- a/src/clientdlgbase.ui
+++ /dev/null
@@ -1,653 +0,0 @@
-
-
- CClientDlgBase
-
-
-
- 0
- 0
- 511
- 490
-
-
-
- true
-
-
-
-
-
-
- :/png/main/res/fronticon.png:/png/main/res/fronticon.png
-
-
-
-
-
- true
-
-
-
- 0
-
-
- 0
-
-
- 3
-
-
- 3
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::NoFrame
-
-
- QFrame::Plain
-
-
-
-
-
-
-
-
-
- 6
-
-
-
-
-
- 3
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- :/png/main/res/fronticon.png
-
-
- Qt::AlignCenter
-
-
- false
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Expanding
-
-
-
- 13
- 10
-
-
-
-
- -
-
-
-
-
-
- 3
-
-
-
-
-
- Reverb
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Minimum
-
-
-
- 0
- 20
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 125
-
-
-
-
- 16777215
- 300
-
-
-
- 1
-
-
- Qt::Vertical
-
-
- QSlider::TicksBothSides
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Minimum
-
-
-
- 0
- 20
-
-
-
-
-
-
-
-
- -
-
-
- 3
-
-
-
-
-
- Left
-
-
-
- -
-
-
- Right
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Expanding
-
-
-
- 13
- 10
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- -
-
-
-
-
-
- Input
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 19
- 88
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 19
- 88
-
-
-
-
-
-
- -
-
-
-
-
-
- L
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- R
-
-
- Qt::AlignCenter
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
-
-
- Jitter
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- false
-
-
-
- -
-
-
- Delay
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- false
-
-
-
- -
-
-
- Ping
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- false
-
-
-
- -
-
-
-
- 34
- 0
-
-
-
- Qt::LeftToRight
-
-
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 22
- 0
-
-
-
-
- 22
- 16777215
-
-
-
- ms
-
-
-
- -
-
-
-
- 34
- 0
-
-
-
- Qt::LeftToRight
-
-
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- 22
- 0
-
-
-
-
- 22
- 16777215
-
-
-
- ms
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 14
- 14
-
-
-
-
- 14
- 14
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 14
- 14
-
-
-
-
- 14
- 14
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- &Mute Myself
-
-
-
- -
-
-
- &Settings
-
-
-
- -
-
-
- &Chat
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 120
- 45
-
-
-
- C&onnect
-
-
- false
-
-
- false
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
-
-
- -
-
-
-
-
-
- MUTED (Other people won't hear you)
-
-
- Qt::AlignCenter
-
-
- 6
-
-
-
- -
-
-
- QLayout::SetMinimumSize
-
-
- 0
-
-
- 9
-
-
-
-
-
-
- 0
- 0
-
-
-
- Set up your audio, connect to a server and start jamming!
-
-
- Qt::AlignCenter
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
- Update check
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CMultiColorLED
- QWidget
-
-
-
- CAudioMixerBoard
- QWidget
-
-
-
- CLevelMeter
- QWidget
-
- 1
-
-
-
- butConnect
- chbLocalMute
- chbSettings
- chbChat
- sldAudioReverb
- rbtReverbSelL
- rbtReverbSelR
-
-
-
-
-
-
diff --git a/src/clientsettingsdlg.cpp b/src/clientsettingsdlg.cpp
deleted file mode 100644
index c7458826fd..0000000000
--- a/src/clientsettingsdlg.cpp
+++ /dev/null
@@ -1,1218 +0,0 @@
-/******************************************************************************\
- * Copyright (c) 2004-2024
- *
- * Author(s):
- * Volker Fischer
- *
- ******************************************************************************
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- *
-\******************************************************************************/
-
-#include "clientsettingsdlg.h"
-
-/* Implementation *************************************************************/
-CClientSettingsDlg::CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSetP, QWidget* parent ) :
- CBaseDlg ( parent, Qt::Window ), // use Qt::Window to get min/max window buttons
- pClient ( pNCliP ),
- pSettings ( pNSetP )
-{
- setupUi ( this );
-
-#if defined( Q_OS_IOS )
- // iOS needs menu to close
- QMenuBar* pMenu = new QMenuBar ( this );
- QAction* action = pMenu->addAction ( tr ( "&Close" ) );
- connect ( action, SIGNAL ( triggered() ), this, SLOT ( close() ) );
-
- // Now tell the layout about the menu
- layout()->setMenuBar ( pMenu );
-#endif
-
-#if defined( Q_OS_ANDROID ) || defined( ANDROID )
- // Android too
- QMenuBar* pMenu = new QMenuBar ( this );
- QMenu* pCloseMenu = new QMenu ( tr ( "&Close" ), this );
- pCloseMenu->addAction ( tr ( "&Close" ), this, SLOT ( close() ) );
- pMenu->addMenu ( pCloseMenu );
-
- // Now tell the layout about the menu
- layout()->setMenuBar ( pMenu );
-#endif
-
- // Add help text to controls -----------------------------------------------
- // local audio input fader
- QString strAudFader = "" + tr ( "Local Audio Input Fader" ) + ": " +
- tr ( "Controls the relative levels of the left and right local audio "
- "channels. For a mono signal it acts as a pan between the two channels. "
- "For example, if a microphone is connected to "
- "the right input channel and an instrument is connected to the left "
- "input channel which is much louder than the microphone, move the "
- "audio fader in a direction where the label above the fader shows "
- "%1, where %2 is the current attenuation indicator." )
- .arg ( "" + tr ( "L" ) + " -x", "x" );
-
- lblAudioPan->setWhatsThis ( strAudFader );
- lblAudioPanValue->setWhatsThis ( strAudFader );
- sldAudioPan->setWhatsThis ( strAudFader );
-
- sldAudioPan->setAccessibleName ( tr ( "Local audio input fader (left/right)" ) );
-
- // jitter buffer
- QString strJitterBufferSize = "" + tr ( "Jitter Buffer Size" ) + ": " +
- tr ( "The jitter buffer compensates for network and sound card timing jitters. The "
- "size of the buffer therefore influences the quality of "
- "the audio stream (how many dropouts occur) and the overall delay "
- "(the longer the buffer, the higher the delay)." ) +
- "
" +
- tr ( "You can set the jitter buffer size manually for the local client "
- "and the remote server. For the local jitter buffer, dropouts in the "
- "audio stream are indicated by the light below the "
- "jitter buffer size faders. If the light turns to red, a buffer "
- "overrun/underrun has taken place and the audio stream is interrupted." ) +
- "
" +
- tr ( "The jitter buffer setting is therefore a trade-off between audio "
- "quality and overall delay." ) +
- "
" +
- tr ( "If the Auto setting is enabled, the jitter buffers of the local client and "
- "the remote server are set automatically "
- "based on measurements of the network and sound card timing jitter. If "
- "Auto is enabled, the jitter buffer size faders are "
- "disabled (they cannot be moved with the mouse)." );
-
- QString strJitterBufferSizeTT = tr ( "If the Auto setting "
- "is enabled, the network buffers of the local client and "
- "the remote server are set to a conservative "
- "value to minimize the audio dropout probability. To tweak the "
- "audio delay/latency it is recommended to disable the Auto setting "
- "and to lower the jitter buffer size manually by "
- "using the sliders until your personal acceptable amount "
- "of dropouts is reached. The LED indicator will display the audio "
- "dropouts of the local jitter buffer with a red light." ) +
- TOOLTIP_COM_END_TEXT;
-
- lblNetBuf->setWhatsThis ( strJitterBufferSize );
- lblNetBuf->setToolTip ( strJitterBufferSizeTT );
- grbJitterBuffer->setWhatsThis ( strJitterBufferSize );
- grbJitterBuffer->setToolTip ( strJitterBufferSizeTT );
- sldNetBuf->setWhatsThis ( strJitterBufferSize );
- sldNetBuf->setAccessibleName ( tr ( "Local jitter buffer slider control" ) );
- sldNetBuf->setToolTip ( strJitterBufferSizeTT );
- sldNetBufServer->setWhatsThis ( strJitterBufferSize );
- sldNetBufServer->setAccessibleName ( tr ( "Server jitter buffer slider control" ) );
- sldNetBufServer->setToolTip ( strJitterBufferSizeTT );
- chbAutoJitBuf->setAccessibleName ( tr ( "Auto jitter buffer check box" ) );
- chbAutoJitBuf->setToolTip ( strJitterBufferSizeTT );
-
-#if !defined( WITH_JACK )
- // sound card device
- lblSoundcardDevice->setWhatsThis ( "" + tr ( "Audio Device" ) + ": " +
- tr ( "Under the Windows operating system the ASIO driver (sound card) can be "
- "selected using %1. If the selected ASIO driver is not valid an error "
- "message is shown and the previous valid driver is selected. "
- "Under macOS the input and output hardware can be selected." )
- .arg ( APP_NAME ) +
- "
" +
- tr ( "If the driver is selected during an active connection, the connection "
- "is stopped, the driver is changed and the connection is started again "
- "automatically." ) );
-
- cbxSoundcard->setAccessibleName ( tr ( "Sound card device selector combo box" ) );
-
-# if defined( _WIN32 )
- // set Windows specific tool tip
- cbxSoundcard->setToolTip ( tr ( "If the ASIO4ALL driver is used, "
- "please note that this driver usually introduces approx. 10-30 ms of "
- "additional audio delay. Using a sound card with a native ASIO driver "
- "is therefore recommended." ) +
- "
" +
- tr ( "If you are using the kX ASIO "
- "driver, make sure to connect the ASIO inputs in the kX DSP settings "
- "panel." ) +
- TOOLTIP_COM_END_TEXT );
-# endif
-
- // sound card input/output channel mapping
- QString strSndCrdChanMapp = "" + tr ( "Sound Card Channel Mapping" ) + ": " +
- tr ( "If the selected sound card device offers more than one "
- "input or output channel, the Input Channel Mapping and Output "
- "Channel Mapping settings are visible." ) +
- "
" +
- tr ( "For each %1 input/output channel (left and "
- "right channel) a different actual sound card channel can be "
- "selected." )
- .arg ( APP_NAME );
-
- lblInChannelMapping->setWhatsThis ( strSndCrdChanMapp );
- lblOutChannelMapping->setWhatsThis ( strSndCrdChanMapp );
- cbxLInChan->setWhatsThis ( strSndCrdChanMapp );
- cbxLInChan->setAccessibleName ( tr ( "Left input channel selection combo box" ) );
- cbxRInChan->setWhatsThis ( strSndCrdChanMapp );
- cbxRInChan->setAccessibleName ( tr ( "Right input channel selection combo box" ) );
- cbxLOutChan->setWhatsThis ( strSndCrdChanMapp );
- cbxLOutChan->setAccessibleName ( tr ( "Left output channel selection combo box" ) );
- cbxROutChan->setWhatsThis ( strSndCrdChanMapp );
- cbxROutChan->setAccessibleName ( tr ( "Right output channel selection combo box" ) );
-#endif
-
- // enable OPUS64
- chbSmallNetworkBuffers->setWhatsThis (
- "" + tr ( "Small Network Buffers" ) + ": " +
- tr ( "Enables support for very small network audio packets. These "
- "network packets are only actually used if the sound card buffer delay is smaller than %1 samples. The "
- "smaller the network buffers, the lower the audio latency. But at the same time "
- "the network load and the probability of audio dropouts or sound artifacts increases." )
- .arg ( DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ) );
-
- chbSmallNetworkBuffers->setAccessibleName ( tr ( "Small network buffers check box" ) );
-
- // sound card buffer delay
- QString strSndCrdBufDelay =
- "" + tr ( "Sound Card Buffer Delay" ) + ": " +
- tr ( "The buffer delay setting is a fundamental setting of %1. "
- "This setting has an influence on many connection properties." )
- .arg ( APP_NAME ) +
- "
" + tr ( "Three buffer sizes can be selected" ) +
- ":"
- "- " +
- tr ( "64 samples: Provides the lowest latency but does not work with all sound cards." ) +
- "
"
- "- " +
- tr ( "128 samples: Should work for most available sound cards." ) +
- "
"
- "- " +
- tr ( "256 samples: Should only be used when 64 or 128 samples "
- "is causing issues." ) +
- "
"
- "
" +
- tr ( "Some sound card drivers do not allow the buffer delay to be changed from within %1. "
- "In this case the buffer delay setting is disabled and has to be changed using the sound card driver. "
- "Use the appropriate tool for the interface in use to adjust this buffer size. "
- "For example, if using ASIO, use the \"ASIO Device Settings\" button to open the driver settings panel or if using JACK, use a tool "
- "such as QjackCtl to adjust the buffer size. "
- "Other interfaces, such as Pipewire, would require their appropriate tool being used. Please refer to the interface manual." )
- .arg ( APP_NAME ) +
- "
" +
- tr ( "If no buffer size is selected and all settings are disabled, this means a "
- "buffer size in use by the driver which does not match the values. %1 "
- "will still work with this setting but may have restricted "
- "performance." )
- .arg ( APP_NAME ) +
- "
" +
- tr ( "The actual buffer delay has influence on the connection, the "
- "current upload rate and the overall delay. The lower the buffer size, "
- "the higher the probability of a red light in the status indicator (drop "
- "outs) and the higher the upload rate and the lower the overall "
- "delay." ) +
- "
" + tr ( "The buffer setting is therefore a trade-off between audio quality and overall delay." );
-
- QString strSndCrdBufDelayTT =
- tr ( "Some sound card drivers do not allow the buffer delay to be changed from within %1. "
- "In this case the buffer delay setting is disabled and has to be changed using the sound card driver. "
- "Use the appropriate tool for the interface in use to adjust this buffer size. "
- "For example, if using ASIO, use the \"ASIO Device Settings\" button to open the driver settings panel or if using JACK, use a tool "
- "such as QjackCtl to adjust the buffer size. "
- "Other interfaces, such as Pipewire, would require their appropriate tool being used. Please refer to the interface manual." )
- .arg ( APP_NAME ) +
- TOOLTIP_COM_END_TEXT;
-
-#if defined( _WIN32 ) && !defined( WITH_JACK )
- // Driver setup button
- QString strSndCardDriverSetup = "" + tr ( "Sound card driver settings" ) + ": " +
- tr ( "This opens the driver settings of your sound card. Some drivers "
- "allow you to change buffer settings, others like ASIO4ALL "
- "lets you choose input or outputs of your device(s). "
- "More information can be found on jamulus.io." );
-
- QString strSndCardDriverSetupTT = tr ( "Opens the driver settings. Note: %1 currently only supports devices "
- "with a sample rate of %2 Hz. "
- "You will not be able to select a driver/device which doesn't. "
- "For more help see jamulus.io." )
- .arg ( APP_NAME )
- .arg ( SYSTEM_SAMPLE_RATE_HZ ) +
- TOOLTIP_COM_END_TEXT;
-#endif
-
- rbtBufferDelayPreferred->setWhatsThis ( strSndCrdBufDelay );
- rbtBufferDelayPreferred->setAccessibleName ( tr ( "64 samples setting radio button" ) );
- rbtBufferDelayPreferred->setToolTip ( strSndCrdBufDelayTT );
- rbtBufferDelayDefault->setWhatsThis ( strSndCrdBufDelay );
- rbtBufferDelayDefault->setAccessibleName ( tr ( "128 samples setting radio button" ) );
- rbtBufferDelayDefault->setToolTip ( strSndCrdBufDelayTT );
- rbtBufferDelaySafe->setWhatsThis ( strSndCrdBufDelay );
- rbtBufferDelaySafe->setAccessibleName ( tr ( "256 samples setting radio button" ) );
- rbtBufferDelaySafe->setToolTip ( strSndCrdBufDelayTT );
-
-#if defined( _WIN32 ) && !defined( WITH_JACK )
- butDriverSetup->setWhatsThis ( strSndCardDriverSetup );
- butDriverSetup->setAccessibleName ( tr ( "ASIO Device Settings push button" ) );
- butDriverSetup->setToolTip ( strSndCardDriverSetupTT );
-#endif
-
- // fancy skin
- lblSkin->setWhatsThis ( "" + tr ( "Skin" ) + ": " + tr ( "Select the skin to be used for the main window." ) );
-
- cbxSkin->setAccessibleName ( tr ( "Skin combo box" ) );
-
- // MeterStyle
- lblMeterStyle->setWhatsThis ( "" + tr ( "Meter Style" ) + ": " +
- tr ( "Select the meter style to be used for the level meters. The "
- "Bar (narrow) and LEDs (round, small) options only apply to the mixerboard. When "
- "Bar (narrow) is selected, the input meters are set to Bar (wide). When "
- "LEDs (round, small) is selected, the input meters are set to LEDs (round, big). "
- "The remaining options apply to the mixerboard and input meters." ) );
-
- cbxMeterStyle->setAccessibleName ( tr ( "Meter Style combo box" ) );
-
- // Interface Language
- lblLanguage->setWhatsThis ( "" + tr ( "Language" ) + ": " + tr ( "Select the language to be used for the user interface." ) );
-
- cbxLanguage->setAccessibleName ( tr ( "Language combo box" ) );
-
- // audio channels
- QString strAudioChannels = "" + tr ( "Audio Channels" ) + ": " +
- tr ( "Selects the number of audio channels to be used for communication between "
- "client and server. There are three modes available:" ) +
- ""
- "- "
- "" +
- tr ( "Mono" ) + " " + tr ( "and" ) + " " + tr ( "Stereo" ) + ": " +
- tr ( "These modes use "
- "one and two audio channels respectively." ) +
- "
"
- "- "
- "" +
- tr ( "Mono in/Stereo-out" ) + ": " +
- tr ( "The audio signal sent to the server is mono but the "
- "return signal is stereo. This is useful if the "
- "sound card has the instrument on one input channel and the "
- "microphone on the other. In that case the two input signals "
- "can be mixed to one mono channel but the server mix is heard in "
- "stereo." ) +
- "
"
- "- " +
- tr ( "Enabling " ) + "" + tr ( "Stereo" ) + " " +
- tr ( " mode "
- "will increase your stream's data rate. Make sure your upload rate does not "
- "exceed the available upload speed of your internet connection." ) +
- "
"
- "
" +
- tr ( "In stereo streaming mode, no audio channel selection "
- "for the reverb effect will be available on the main window "
- "since the effect is applied to both channels in this case." );
-
- lblAudioChannels->setWhatsThis ( strAudioChannels );
- cbxAudioChannels->setWhatsThis ( strAudioChannels );
- cbxAudioChannels->setAccessibleName ( tr ( "Audio channels combo box" ) );
-
- // audio quality
- QString strAudioQuality = "" + tr ( "Audio Quality" ) + ": " +
- tr ( "The higher the audio quality, the higher your audio stream's "
- "data rate. Make sure your upload rate does not exceed the "
- "available bandwidth of your internet connection." );
-
- lblAudioQuality->setWhatsThis ( strAudioQuality );
- cbxAudioQuality->setWhatsThis ( strAudioQuality );
- cbxAudioQuality->setAccessibleName ( tr ( "Audio quality combo box" ) );
-
- // new client fader level
- QString strNewClientLevel = "" + tr ( "New Client Level" ) + ": " +
- tr ( "This setting defines the fader level of a newly "
- "connected client in percent. If a new client connects "
- "to the current server, they will get the specified initial "
- "fader level if no other fader level from a previous connection "
- "of that client was already stored." );
-
- lblNewClientLevel->setWhatsThis ( strNewClientLevel );
- edtNewClientLevel->setWhatsThis ( strNewClientLevel );
- edtNewClientLevel->setAccessibleName ( tr ( "New client level edit box" ) );
-
- // input boost
- QString strInputBoost = "" + tr ( "Input Boost" ) + ": " +
- tr ( "This setting allows you to increase your input signal level "
- "by factors up to 10 (+20dB). "
- "If your sound is too quiet, first try to increase the level by "
- "getting closer to the microphone, adjusting your sound equipment "
- "or increasing levels in your operating system's input settings. "
- "Only if this fails, set a factor here. "
- "If your sound is too loud, sounds distorted and is clipping, this "
- "option will not help. Do not use it. The distortion will still be "
- "there. Instead, decrease your input level by getting farther away "
- "from your microphone, adjusting your sound equipment "
- "or by decreasing your operating system's input settings." );
- lblInputBoost->setWhatsThis ( strInputBoost );
- cbxInputBoost->setWhatsThis ( strInputBoost );
- cbxInputBoost->setAccessibleName ( tr ( "Input Boost combo box" ) );
-
- // custom directories
- QString strCustomDirectories = "" + tr ( "Custom Directories" ) + ": " +
- tr ( "If you need to add additional directories to the Connect dialog Directory drop down, "
- "you can enter the addresses here.
" );
-
- lblCustomDirectories->setWhatsThis ( strCustomDirectories );
- cbxCustomDirectories->setWhatsThis ( strCustomDirectories );
- cbxCustomDirectories->setAccessibleName ( tr ( "Custom Directories combo box" ) );
-
- tbtDeleteCustomDirectory->setAccessibleName ( tr ( "Delete custom directory button" ) );
- tbtDeleteCustomDirectory->setWhatsThis ( "" + tr ( "Delete Custom Directory" ) + ": " +
- tr ( "Click the button to delete the currently selected custom directory." ) );
- tbtDeleteCustomDirectory->setText ( u8"\u232B" );
-
- // current connection status parameter
- QString strConnStats = "" + tr ( "Audio Upstream Rate" ) + ": " +
- tr ( "Depends on the current audio packet size and "
- "compression setting. Make sure that the upstream rate is not "
- "higher than your available internet upload speed (check this with a "
- "service such as speedtest.net)." );
-
- lblUpstreamValue->setWhatsThis ( strConnStats );
- grbUpstreamValue->setWhatsThis ( strConnStats );
-
- QString strNumMixerPanelRows =
- "" + tr ( "Number of Mixer Panel Rows" ) + ": " + tr ( "Adjust the number of rows used to arrange the mixer panel." );
- lblMixerRows->setWhatsThis ( strNumMixerPanelRows );
- spnMixerRows->setWhatsThis ( strNumMixerPanelRows );
- spnMixerRows->setAccessibleName ( tr ( "Number of Mixer Panel Rows spin box" ) );
-
- chbDetectFeedback->setWhatsThis ( "" + tr ( "Feedback Protection" ) + ": " +
- tr ( "Prevents acoustic feedback between microphone and speakers." ) );
- chbDetectFeedback->setAccessibleName ( tr ( "Feedback Protection check box" ) );
-
- // audio alerts
- chbAudioAlerts->setWhatsThis ( "" + tr ( "Audio Alerts" ) + ": " +
- tr ( "Trigger an audio alert when receiving a chat message and when a new client joins the session. "
- "A second sound device may be required to hear the alerts." ) );
- chbAudioAlerts->setAccessibleName ( tr ( "Audio Alerts check box" ) );
-
- // init driver button
-#if defined( _WIN32 ) && !defined( WITH_JACK )
- butDriverSetup->setText ( tr ( "ASIO Device Settings" ) );
-#else
- // no use for this button for MacOS/Linux right now or when using JACK -> hide it
- butDriverSetup->hide();
-#endif
-
- // init audio in fader
- sldAudioPan->setRange ( AUD_FADER_IN_MIN, AUD_FADER_IN_MAX );
- sldAudioPan->setTickInterval ( AUD_FADER_IN_MAX / 5 );
- UpdateAudioFaderSlider();
-
- // init delay and other information controls
- lblUpstreamValue->setText ( "---" );
- lblUpstreamUnit->setText ( "" );
- edtNewClientLevel->setValidator ( new QIntValidator ( 0, 100, this ) ); // % range from 0-100
-
- // init slider controls ---
- // network buffer sliders
- sldNetBuf->setRange ( MIN_NET_BUF_SIZE_NUM_BL, MAX_NET_BUF_SIZE_NUM_BL );
- sldNetBufServer->setRange ( MIN_NET_BUF_SIZE_NUM_BL, MAX_NET_BUF_SIZE_NUM_BL );
- UpdateJitterBufferFrame();
-
- // init sound card channel selection frame
- UpdateSoundDeviceChannelSelectionFrame();
-
- // Audio Channels combo box
- cbxAudioChannels->clear();
- cbxAudioChannels->addItem ( tr ( "Mono" ) ); // CC_MONO
- cbxAudioChannels->addItem ( tr ( "Mono-in/Stereo-out" ) ); // CC_MONO_IN_STEREO_OUT
- cbxAudioChannels->addItem ( tr ( "Stereo" ) ); // CC_STEREO
- cbxAudioChannels->setCurrentIndex ( static_cast ( pClient->GetAudioChannels() ) );
-
- // Audio Quality combo box
- cbxAudioQuality->clear();
- cbxAudioQuality->addItem ( tr ( "Low" ) ); // AQ_LOW
- cbxAudioQuality->addItem ( tr ( "Normal" ) ); // AQ_NORMAL
- cbxAudioQuality->addItem ( tr ( "High" ) ); // AQ_HIGH
- cbxAudioQuality->setCurrentIndex ( static_cast ( pClient->GetAudioQuality() ) );
-
- // GUI design (skin) combo box
- cbxSkin->clear();
- cbxSkin->addItem ( tr ( "Normal" ) ); // GD_STANDARD
- cbxSkin->addItem ( tr ( "Fancy" ) ); // GD_ORIGINAL
- cbxSkin->addItem ( tr ( "Compact" ) ); // GD_SLIMFADER
- cbxSkin->setCurrentIndex ( static_cast ( pClient->GetGUIDesign() ) );
-
- // MeterStyle combo box
- cbxMeterStyle->clear();
- cbxMeterStyle->addItem ( tr ( "Bar (narrow)" ) ); // MT_BAR_NARROW
- cbxMeterStyle->addItem ( tr ( "Bar (wide)" ) ); // MT_BAR_WIDE
- cbxMeterStyle->addItem ( tr ( "LEDs (stripe)" ) ); // MT_LED_STRIPE
- cbxMeterStyle->addItem ( tr ( "LEDs (round, small)" ) ); // MT_LED_ROUND_SMALL
- cbxMeterStyle->addItem ( tr ( "LEDs (round, big)" ) ); // MT_LED_ROUND_BIG
- cbxMeterStyle->setCurrentIndex ( static_cast ( pClient->GetMeterStyle() ) );
-
- // language combo box (corrects the setting if language not found)
- cbxLanguage->Init ( pSettings->strLanguage );
-
- // init custom directories combo box (max MAX_NUM_SERVER_ADDR_ITEMS entries)
- cbxCustomDirectories->setMaxCount ( MAX_NUM_SERVER_ADDR_ITEMS );
- cbxCustomDirectories->setInsertPolicy ( QComboBox::NoInsert );
-
- // update new client fader level edit box
- edtNewClientLevel->setText ( QString::number ( pSettings->iNewClientFaderLevel ) );
-
- // Input Boost combo box
- cbxInputBoost->clear();
- cbxInputBoost->addItem ( tr ( "None" ) );
- for ( int i = 2; i <= 10; i++ )
- {
- cbxInputBoost->addItem ( QString ( "%1x" ).arg ( i ) );
- }
- // factor is 1-based while index is 0-based:
- cbxInputBoost->setCurrentIndex ( pSettings->iInputBoost - 1 );
-
- // init number of mixer rows
- spnMixerRows->setValue ( pSettings->iNumMixerPanelRows );
-
- // init audio alerts
- chbAudioAlerts->setCheckState ( pSettings->bEnableAudioAlerts ? Qt::Checked : Qt::Unchecked );
-
- // update feedback detection
- chbDetectFeedback->setCheckState ( pSettings->bEnableFeedbackDetection ? Qt::Checked : Qt::Unchecked );
-
- // update enable small network buffers check box
- chbSmallNetworkBuffers->setCheckState ( pClient->GetEnableOPUS64() ? Qt::Checked : Qt::Unchecked );
-
- // set text for sound card buffer delay radio buttons
- rbtBufferDelayPreferred->setText ( GenSndCrdBufferDelayString ( FRAME_SIZE_FACTOR_PREFERRED * SYSTEM_FRAME_SIZE_SAMPLES ) );
-
- rbtBufferDelayDefault->setText ( GenSndCrdBufferDelayString ( FRAME_SIZE_FACTOR_DEFAULT * SYSTEM_FRAME_SIZE_SAMPLES ) );
-
- rbtBufferDelaySafe->setText ( GenSndCrdBufferDelayString ( FRAME_SIZE_FACTOR_SAFE * SYSTEM_FRAME_SIZE_SAMPLES ) );
-
- // sound card buffer delay inits
- SndCrdBufferDelayButtonGroup.addButton ( rbtBufferDelayPreferred );
- SndCrdBufferDelayButtonGroup.addButton ( rbtBufferDelayDefault );
- SndCrdBufferDelayButtonGroup.addButton ( rbtBufferDelaySafe );
-
- UpdateSoundCardFrame();
-
- // Add help text to controls -----------------------------------------------
- // Musician Profile
- QString strFaderTag = "" + tr ( "Musician Profile" ) + ": " +
- tr ( "Write your name or an alias here so the other musicians you want to "
- "play with know who you are. You may also add a picture of the instrument "
- "you play and a flag of the country or region you are located in. "
- "Your city and skill level playing your instrument may also be added." ) +
- "
" +
- tr ( "What you set here will appear at your fader on the mixer "
- "board when you are connected to a %1 server. This tag will "
- "also be shown at each client which is connected to the same server as "
- "you." )
- .arg ( APP_NAME );
-
- plblAlias->setWhatsThis ( strFaderTag );
- pedtAlias->setAccessibleName ( tr ( "Alias or name edit box" ) );
- plblInstrument->setWhatsThis ( strFaderTag );
- pcbxInstrument->setAccessibleName ( tr ( "Instrument picture button" ) );
- plblCountry->setWhatsThis ( strFaderTag );
- pcbxCountry->setAccessibleName ( tr ( "Country/region flag button" ) );
- plblCity->setWhatsThis ( strFaderTag );
- pedtCity->setAccessibleName ( tr ( "City edit box" ) );
- plblSkill->setWhatsThis ( strFaderTag );
- pcbxSkill->setAccessibleName ( tr ( "Skill level combo box" ) );
-
- // Instrument pictures combo box -------------------------------------------
- // add an entry for all known instruments
- for ( int iCurInst = 0; iCurInst < CInstPictures::GetNumAvailableInst(); iCurInst++ )
- {
- // create a combo box item with text, image and background color
- QColor InstrColor;
-
- pcbxInstrument->addItem ( QIcon ( CInstPictures::GetResourceReference ( iCurInst ) ), CInstPictures::GetName ( iCurInst ), iCurInst );
-
- switch ( CInstPictures::GetCategory ( iCurInst ) )
- {
- case CInstPictures::IC_OTHER_INSTRUMENT:
- InstrColor = QColor ( Qt::blue );
- break;
- case CInstPictures::IC_WIND_INSTRUMENT:
- InstrColor = QColor ( Qt::green );
- break;
- case CInstPictures::IC_STRING_INSTRUMENT:
- InstrColor = QColor ( Qt::red );
- break;
- case CInstPictures::IC_PLUCKING_INSTRUMENT:
- InstrColor = QColor ( Qt::cyan );
- break;
- case CInstPictures::IC_PERCUSSION_INSTRUMENT:
- InstrColor = QColor ( Qt::white );
- break;
- case CInstPictures::IC_KEYBOARD_INSTRUMENT:
- InstrColor = QColor ( Qt::yellow );
- break;
- case CInstPictures::IC_MULTIPLE_INSTRUMENT:
- InstrColor = QColor ( Qt::black );
- break;
- }
-
- InstrColor.setAlpha ( 10 );
- pcbxInstrument->setItemData ( iCurInst, InstrColor, Qt::BackgroundRole );
- }
-
- // sort the items in alphabetical order
- pcbxInstrument->model()->sort ( 0 );
-
- // Country flag icons combo box --------------------------------------------
- // add an entry for all known country flags
- for ( int iCurCntry = static_cast ( QLocale::AnyCountry ); iCurCntry < static_cast ( QLocale::LastCountry ); iCurCntry++ )
- {
- // exclude the "None" entry since it is added after the sorting
- if ( static_cast ( iCurCntry ) == QLocale::AnyCountry )
- {
- continue;
- }
-
- if ( !CLocale::IsCountryCodeSupported ( iCurCntry ) )
- {
- // The current Qt version which is the base for the loop may support
- // more country codes than our protocol does. Therefore, skip
- // the unsupported options to avoid surprises.
- continue;
- }
-
- // get current country enum
- QLocale::Country eCountry = static_cast ( iCurCntry );
-
- // try to load icon from resource file name
- QIcon CurFlagIcon;
- CurFlagIcon.addFile ( CLocale::GetCountryFlagIconsResourceReference ( eCountry ) );
-
- // only add the entry if a flag is available
- if ( !CurFlagIcon.isNull() )
- {
- // create a combo box item with text and image
- pcbxCountry->addItem ( QIcon ( CurFlagIcon ), QLocale::countryToString ( eCountry ), iCurCntry );
- }
- }
-
- // sort country combo box items in alphabetical order
- pcbxCountry->model()->sort ( 0, Qt::AscendingOrder );
-
- // the "None" country gets a special icon and is the very first item
- QIcon FlagNoneIcon;
- FlagNoneIcon.addFile ( ":/png/flags/res/flags/flagnone.png" );
- pcbxCountry->insertItem ( 0, FlagNoneIcon, tr ( "None" ), static_cast ( QLocale::AnyCountry ) );
-
- // Skill level combo box ---------------------------------------------------
- // create a pixmap showing the skill level colors
- QPixmap SLPixmap ( 16, 11 ); // same size as the country flags
-
- SLPixmap.fill ( QColor::fromRgb ( RGBCOL_R_SL_NOT_SET, RGBCOL_G_SL_NOT_SET, RGBCOL_B_SL_NOT_SET ) );
-
- pcbxSkill->addItem ( QIcon ( SLPixmap ), tr ( "None" ), SL_NOT_SET );
-
- SLPixmap.fill ( QColor::fromRgb ( RGBCOL_R_SL_BEGINNER, RGBCOL_G_SL_BEGINNER, RGBCOL_B_SL_BEGINNER ) );
-
- pcbxSkill->addItem ( QIcon ( SLPixmap ), tr ( "Beginner" ), SL_BEGINNER );
-
- SLPixmap.fill ( QColor::fromRgb ( RGBCOL_R_SL_INTERMEDIATE, RGBCOL_G_SL_INTERMEDIATE, RGBCOL_B_SL_INTERMEDIATE ) );
-
- pcbxSkill->addItem ( QIcon ( SLPixmap ), tr ( "Intermediate" ), SL_INTERMEDIATE );
-
- SLPixmap.fill ( QColor::fromRgb ( RGBCOL_R_SL_SL_PROFESSIONAL, RGBCOL_G_SL_SL_PROFESSIONAL, RGBCOL_B_SL_SL_PROFESSIONAL ) );
-
- pcbxSkill->addItem ( QIcon ( SLPixmap ), tr ( "Expert" ), SL_PROFESSIONAL );
-
- // Connections -------------------------------------------------------------
- // timers
- QObject::connect ( &TimerStatus, &QTimer::timeout, this, &CClientSettingsDlg::OnTimerStatus );
-
- // slider controls
- QObject::connect ( sldNetBuf, &QSlider::valueChanged, this, &CClientSettingsDlg::OnNetBufValueChanged );
-
- QObject::connect ( sldNetBufServer, &QSlider::valueChanged, this, &CClientSettingsDlg::OnNetBufServerValueChanged );
-
- // check boxes
- QObject::connect ( chbAutoJitBuf, &QCheckBox::stateChanged, this, &CClientSettingsDlg::OnAutoJitBufStateChanged );
-
- QObject::connect ( chbSmallNetworkBuffers, &QCheckBox::stateChanged, this, &CClientSettingsDlg::OnEnableOPUS64StateChanged );
-
- QObject::connect ( chbDetectFeedback, &QCheckBox::stateChanged, this, &CClientSettingsDlg::OnFeedbackDetectionChanged );
-
- QObject::connect ( chbAudioAlerts, &QCheckBox::stateChanged, this, &CClientSettingsDlg::OnAudioAlertsChanged );
-
- // line edits
- QObject::connect ( edtNewClientLevel, &QLineEdit::editingFinished, this, &CClientSettingsDlg::OnNewClientLevelEditingFinished );
-
- // combo boxes
- QObject::connect ( cbxSoundcard,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnSoundcardActivated );
-
- QObject::connect ( cbxLInChan,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnLInChanActivated );
-
- QObject::connect ( cbxRInChan,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnRInChanActivated );
-
- QObject::connect ( cbxLOutChan,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnLOutChanActivated );
-
- QObject::connect ( cbxROutChan,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnROutChanActivated );
-
- QObject::connect ( cbxAudioChannels,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnAudioChannelsActivated );
-
- QObject::connect ( cbxAudioQuality,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnAudioQualityActivated );
-
- QObject::connect ( cbxSkin,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnGUIDesignActivated );
-
- QObject::connect ( cbxMeterStyle,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnMeterStyleActivated );
-
- QObject::connect ( cbxCustomDirectories->lineEdit(), &QLineEdit::editingFinished, this, [this] {
- CClientSettingsDlg::OnCustomDirectoriesChanged ( false );
- } );
-
- QObject::connect ( cbxLanguage, &CLanguageComboBox::LanguageChanged, this, &CClientSettingsDlg::OnLanguageChanged );
-
- QObject::connect ( cbxInputBoost,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnInputBoostChanged );
-
- // buttons
-#if defined( _WIN32 ) && !defined( WITH_JACK )
- // Driver Setup button is only available for Windows when JACK is not used
- QObject::connect ( butDriverSetup, &QPushButton::clicked, this, &CClientSettingsDlg::OnDriverSetupClicked );
-#endif
-
- // tool buttons
- QObject::connect ( tbtDeleteCustomDirectory, &QToolButton::clicked, this, [this] { CClientSettingsDlg::OnCustomDirectoriesChanged ( true ); } );
-
- // misc
- // sliders
- QObject::connect ( sldAudioPan, &QSlider::valueChanged, this, &CClientSettingsDlg::OnAudioPanValueChanged );
-
- QObject::connect ( &SndCrdBufferDelayButtonGroup,
- static_cast ( &QButtonGroup::buttonClicked ),
- this,
- &CClientSettingsDlg::OnSndCrdBufferDelayButtonGroupClicked );
-
- // spinners
- QObject::connect ( spnMixerRows,
- static_cast ( &QSpinBox::valueChanged ),
- this,
- &CClientSettingsDlg::NumMixerPanelRowsChanged );
-
- // Musician Profile
- QObject::connect ( pedtAlias, &QLineEdit::textChanged, this, &CClientSettingsDlg::OnAliasTextChanged );
-
- QObject::connect ( pcbxInstrument,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnInstrumentActivated );
-
- QObject::connect ( pcbxCountry,
- static_cast ( &QComboBox::activated ),
- this,
- &CClientSettingsDlg::OnCountryActivated );
-
- QObject::connect ( pedtCity, &QLineEdit::textChanged, this, &CClientSettingsDlg::OnCityTextChanged );
-
- QObject::connect ( pcbxSkill, static_cast ( &QComboBox::activated ), this, &CClientSettingsDlg::OnSkillActivated );
-
- QObject::connect ( tabSettings, &QTabWidget::currentChanged, this, &CClientSettingsDlg::OnTabChanged );
-
- tabSettings->setCurrentIndex ( pSettings->iSettingsTab );
-
- // Timers ------------------------------------------------------------------
- // start timer for status bar
- TimerStatus.start ( DISPLAY_UPDATE_TIME );
-}
-
-void CClientSettingsDlg::showEvent ( QShowEvent* )
-{
- UpdateDisplay();
- UpdateDirectoryComboBox();
-
- // set the name
- pedtAlias->setText ( pClient->ChannelInfo.strName );
-
- // select current instrument
- pcbxInstrument->setCurrentIndex ( pcbxInstrument->findData ( pClient->ChannelInfo.iInstrument ) );
-
- // select current country
- pcbxCountry->setCurrentIndex ( pcbxCountry->findData ( static_cast ( pClient->ChannelInfo.eCountry ) ) );
-
- // set the city
- pedtCity->setText ( pClient->ChannelInfo.strCity );
-
- // select the skill level
- pcbxSkill->setCurrentIndex ( pcbxSkill->findData ( static_cast ( pClient->ChannelInfo.eSkillLevel ) ) );
-}
-
-void CClientSettingsDlg::UpdateJitterBufferFrame()
-{
- // update slider value and text
- const int iCurNumNetBuf = pClient->GetSockBufNumFrames();
- sldNetBuf->setValue ( iCurNumNetBuf );
- lblNetBuf->setText ( tr ( "Size: " ) + QString::number ( iCurNumNetBuf ) );
-
- const int iCurNumNetBufServer = pClient->GetServerSockBufNumFrames();
- sldNetBufServer->setValue ( iCurNumNetBufServer );
- lblNetBufServer->setText ( tr ( "Size: " ) + QString::number ( iCurNumNetBufServer ) );
-
- // if auto setting is enabled, disable slider control
- const bool bIsAutoSockBufSize = pClient->GetDoAutoSockBufSize();
-
- chbAutoJitBuf->setChecked ( bIsAutoSockBufSize );
- sldNetBuf->setEnabled ( !bIsAutoSockBufSize );
- lblNetBuf->setEnabled ( !bIsAutoSockBufSize );
- lblNetBufLabel->setEnabled ( !bIsAutoSockBufSize );
- sldNetBufServer->setEnabled ( !bIsAutoSockBufSize );
- lblNetBufServer->setEnabled ( !bIsAutoSockBufSize );
- lblNetBufServerLabel->setEnabled ( !bIsAutoSockBufSize );
-}
-
-QString CClientSettingsDlg::GenSndCrdBufferDelayString ( const int iFrameSize, const QString strAddText )
-{
- // use two times the buffer delay for the entire delay since
- // we have input and output
- return QString().setNum ( static_cast ( iFrameSize ) * 2 * 1000 / SYSTEM_SAMPLE_RATE_HZ, 'f', 2 ) + " ms (" +
- QString().setNum ( iFrameSize ) + strAddText + ")";
-}
-
-void CClientSettingsDlg::UpdateSoundCardFrame()
-{
- // get current actual buffer size value
- const int iCurActualBufSize = pClient->GetSndCrdActualMonoBlSize();
-
- // check which predefined size is used (it is possible that none is used)
- const bool bPreferredChecked = ( iCurActualBufSize == SYSTEM_FRAME_SIZE_SAMPLES * FRAME_SIZE_FACTOR_PREFERRED );
- const bool bDefaultChecked = ( iCurActualBufSize == SYSTEM_FRAME_SIZE_SAMPLES * FRAME_SIZE_FACTOR_DEFAULT );
- const bool bSafeChecked = ( iCurActualBufSize == SYSTEM_FRAME_SIZE_SAMPLES * FRAME_SIZE_FACTOR_SAFE );
-
- // Set radio buttons according to current value (To make it possible
- // to have all radio buttons unchecked, we have to disable the
- // exclusive check for the radio button group. We require all radio
- // buttons to be unchecked in the case when the sound card does not
- // support any of the buffer sizes and therefore all radio buttons
- // are disabeld and unchecked.).
- SndCrdBufferDelayButtonGroup.setExclusive ( false );
- rbtBufferDelayPreferred->setChecked ( bPreferredChecked );
- rbtBufferDelayDefault->setChecked ( bDefaultChecked );
- rbtBufferDelaySafe->setChecked ( bSafeChecked );
- SndCrdBufferDelayButtonGroup.setExclusive ( true );
-
- // disable radio buttons which are not supported by audio interface
- rbtBufferDelayPreferred->setEnabled ( pClient->GetFraSiFactPrefSupported() );
- rbtBufferDelayDefault->setEnabled ( pClient->GetFraSiFactDefSupported() );
- rbtBufferDelaySafe->setEnabled ( pClient->GetFraSiFactSafeSupported() );
-
- // If any of our predefined sizes is chosen, use the regular group box
- // title text. If not, show the actual buffer size. Otherwise the user
- // would not know which buffer size is actually used.
- if ( bPreferredChecked || bDefaultChecked || bSafeChecked )
- {
- // default title text
- grbSoundCrdBufDelay->setTitle ( tr ( "Buffer Delay" ) );
- }
- else
- {
- // special title text with buffer size information added
- grbSoundCrdBufDelay->setTitle ( tr ( "Buffer Delay: " ) + GenSndCrdBufferDelayString ( iCurActualBufSize ) );
- }
-}
-
-void CClientSettingsDlg::UpdateSoundDeviceChannelSelectionFrame()
-{
- // update combo box containing all available sound cards in the system
- QStringList slSndCrdDevNames = pClient->GetSndCrdDevNames();
- cbxSoundcard->clear();
-
- foreach ( QString strDevName, slSndCrdDevNames )
- {
- cbxSoundcard->addItem ( strDevName );
- }
-
- cbxSoundcard->setCurrentText ( pClient->GetSndCrdDev() );
-
- // update input/output channel selection
-#if defined( _WIN32 ) || defined( __APPLE__ ) || defined( __MACOSX )
-
- // Definition: The channel selection frame shall only be visible,
- // if more than two input or output channels are available
- const int iNumInChannels = pClient->GetSndCrdNumInputChannels();
- const int iNumOutChannels = pClient->GetSndCrdNumOutputChannels();
-
- if ( ( iNumInChannels <= 2 ) && ( iNumOutChannels <= 2 ) )
- {
- // as defined, make settings invisible
- FrameSoundcardChannelSelection->setVisible ( false );
- }
- else
- {
- // update combo boxes
- FrameSoundcardChannelSelection->setVisible ( true );
-
- // input
- cbxLInChan->clear();
- cbxRInChan->clear();
-
- for ( int iSndChanIdx = 0; iSndChanIdx < pClient->GetSndCrdNumInputChannels(); iSndChanIdx++ )
- {
- cbxLInChan->addItem ( pClient->GetSndCrdInputChannelName ( iSndChanIdx ) );
- cbxRInChan->addItem ( pClient->GetSndCrdInputChannelName ( iSndChanIdx ) );
- }
- if ( pClient->GetSndCrdNumInputChannels() > 0 )
- {
- cbxLInChan->setCurrentIndex ( pClient->GetSndCrdLeftInputChannel() );
- cbxRInChan->setCurrentIndex ( pClient->GetSndCrdRightInputChannel() );
- }
-
- // output
- cbxLOutChan->clear();
- cbxROutChan->clear();
- for ( int iSndChanIdx = 0; iSndChanIdx < pClient->GetSndCrdNumOutputChannels(); iSndChanIdx++ )
- {
- cbxLOutChan->addItem ( pClient->GetSndCrdOutputChannelName ( iSndChanIdx ) );
- cbxROutChan->addItem ( pClient->GetSndCrdOutputChannelName ( iSndChanIdx ) );
- }
- if ( pClient->GetSndCrdNumOutputChannels() > 0 )
- {
- cbxLOutChan->setCurrentIndex ( pClient->GetSndCrdLeftOutputChannel() );
- cbxROutChan->setCurrentIndex ( pClient->GetSndCrdRightOutputChannel() );
- }
- }
-#else
- // for other OS, no sound card channel selection is supported
- FrameSoundcardChannelSelection->setVisible ( false );
-#endif
-}
-
-void CClientSettingsDlg::SetEnableFeedbackDetection ( bool enable )
-{
- pSettings->bEnableFeedbackDetection = enable;
- chbDetectFeedback->setCheckState ( pSettings->bEnableFeedbackDetection ? Qt::Checked : Qt::Unchecked );
-}
-
-#if defined( _WIN32 ) && !defined( WITH_JACK )
-void CClientSettingsDlg::OnDriverSetupClicked() { pClient->OpenSndCrdDriverSetup(); }
-#endif
-
-void CClientSettingsDlg::OnNetBufValueChanged ( int value )
-{
- pClient->SetSockBufNumFrames ( value, true );
- UpdateJitterBufferFrame();
-}
-
-void CClientSettingsDlg::OnNetBufServerValueChanged ( int value )
-{
- pClient->SetServerSockBufNumFrames ( value );
- UpdateJitterBufferFrame();
-}
-
-void CClientSettingsDlg::OnSoundcardActivated ( int iSndDevIdx )
-{
- pClient->SetSndCrdDev ( cbxSoundcard->itemText ( iSndDevIdx ) );
-
- UpdateSoundDeviceChannelSelectionFrame();
- UpdateDisplay();
-}
-
-void CClientSettingsDlg::OnLInChanActivated ( int iChanIdx )
-{
- pClient->SetSndCrdLeftInputChannel ( iChanIdx );
- UpdateSoundDeviceChannelSelectionFrame();
-}
-
-void CClientSettingsDlg::OnRInChanActivated ( int iChanIdx )
-{
- pClient->SetSndCrdRightInputChannel ( iChanIdx );
- UpdateSoundDeviceChannelSelectionFrame();
-}
-
-void CClientSettingsDlg::OnLOutChanActivated ( int iChanIdx )
-{
- pClient->SetSndCrdLeftOutputChannel ( iChanIdx );
- UpdateSoundDeviceChannelSelectionFrame();
-}
-
-void CClientSettingsDlg::OnROutChanActivated ( int iChanIdx )
-{
- pClient->SetSndCrdRightOutputChannel ( iChanIdx );
- UpdateSoundDeviceChannelSelectionFrame();
-}
-
-void CClientSettingsDlg::OnAudioChannelsActivated ( int iChanIdx )
-{
- pClient->SetAudioChannels ( static_cast ( iChanIdx ) );
- emit AudioChannelsChanged();
- UpdateDisplay(); // upload rate will be changed
-}
-
-void CClientSettingsDlg::OnAudioQualityActivated ( int iQualityIdx )
-{
- pClient->SetAudioQuality ( static_cast ( iQualityIdx ) );
- UpdateDisplay(); // upload rate will be changed
-}
-
-void CClientSettingsDlg::OnGUIDesignActivated ( int iDesignIdx )
-{
- pClient->SetGUIDesign ( static_cast ( iDesignIdx ) );
- emit GUIDesignChanged();
- UpdateDisplay();
-}
-
-void CClientSettingsDlg::OnMeterStyleActivated ( int iMeterStyleIdx )
-{
- pClient->SetMeterStyle ( static_cast ( iMeterStyleIdx ) );
- emit MeterStyleChanged();
- UpdateDisplay();
-}
-
-void CClientSettingsDlg::OnAudioAlertsChanged ( int value ) { pSettings->bEnableAudioAlerts = value == Qt::Checked; }
-
-void CClientSettingsDlg::OnAutoJitBufStateChanged ( int value )
-{
- pClient->SetDoAutoSockBufSize ( value == Qt::Checked );
- UpdateJitterBufferFrame();
-}
-
-void CClientSettingsDlg::OnEnableOPUS64StateChanged ( int value )
-{
- pClient->SetEnableOPUS64 ( value == Qt::Checked );
- UpdateDisplay();
-}
-
-void CClientSettingsDlg::OnFeedbackDetectionChanged ( int value ) { pSettings->bEnableFeedbackDetection = value == Qt::Checked; }
-
-void CClientSettingsDlg::OnCustomDirectoriesChanged ( bool bDelete )
-{
- if ( bDelete )
- {
- if ( !cbxCustomDirectories->currentData().isValid() )
- {
- // no selected directory to delete
- return;
- }
- // delete the selected directory
- pSettings->vstrDirectoryAddress[cbxCustomDirectories->currentData().toInt()] = QString();
- }
- else
- {
-
- if ( cbxCustomDirectories->currentText().isEmpty() ||
- ( cbxCustomDirectories->currentData().isValid() && pSettings->vstrDirectoryAddress[cbxCustomDirectories->currentData().toInt()].compare (
- NetworkUtil::FixAddress ( cbxCustomDirectories->currentText() ) ) == 0 ) )
- {
- // no need to add a already added directory
- return;
- }
- // store new address at the top of the list, if the list was already
- // full, the last element is thrown out
- pSettings->vstrDirectoryAddress.StringFiFoWithCompare ( NetworkUtil::FixAddress ( cbxCustomDirectories->currentText() ) );
- }
- // update combo box list and inform connect dialog about the new address
- UpdateDirectoryComboBox();
- emit CustomDirectoriesChanged();
-}
-
-void CClientSettingsDlg::OnSndCrdBufferDelayButtonGroupClicked ( QAbstractButton* button )
-{
- if ( button == rbtBufferDelayPreferred )
- {
- pClient->SetSndCrdPrefFrameSizeFactor ( FRAME_SIZE_FACTOR_PREFERRED );
- }
-
- if ( button == rbtBufferDelayDefault )
- {
- pClient->SetSndCrdPrefFrameSizeFactor ( FRAME_SIZE_FACTOR_DEFAULT );
- }
-
- if ( button == rbtBufferDelaySafe )
- {
- pClient->SetSndCrdPrefFrameSizeFactor ( FRAME_SIZE_FACTOR_SAFE );
- }
-
- UpdateDisplay();
-}
-
-/// @method
-/// @brief Sets upstream rate label to current upload rate if the client is connected, else resets label
-void CClientSettingsDlg::UpdateUploadRate()
-{
- // update upstream rate information label if needed
- if ( pClient->IsConnected() )
- {
- lblUpstreamValue->setText ( QString().setNum ( pClient->GetUploadRateKbps() ) );
- lblUpstreamUnit->setText ( "kbps" );
- }
- else
- {
- // clear text labels with client parameters
- lblUpstreamValue->setText ( "---" );
- lblUpstreamUnit->setText ( "" );
- }
-}
-
-/// @method
-/// @brief Updates slider controls (settings might have been changed) and upstream rate information label
-void CClientSettingsDlg::UpdateDisplay()
-{
- UpdateJitterBufferFrame();
- UpdateSoundCardFrame();
- UpdateUploadRate();
-}
-
-void CClientSettingsDlg::UpdateDirectoryComboBox()
-{
- cbxCustomDirectories->clear();
- cbxCustomDirectories->clearEditText();
-
- for ( int iLEIdx = 0; iLEIdx < MAX_NUM_SERVER_ADDR_ITEMS; iLEIdx++ )
- {
- if ( !pSettings->vstrDirectoryAddress[iLEIdx].isEmpty() )
- {
- // store the index as user data to the combo box item, too
- cbxCustomDirectories->addItem ( pSettings->vstrDirectoryAddress[iLEIdx], iLEIdx );
- }
- }
-}
-
-void CClientSettingsDlg::OnInputBoostChanged()
-{
- // index is zero-based while boost factor must be 1-based:
- pSettings->iInputBoost = cbxInputBoost->currentIndex() + 1;
- pClient->SetInputBoost ( pSettings->iInputBoost );
-}
-
-void CClientSettingsDlg::OnAliasTextChanged ( const QString& strNewName )
-{
- // check length
- if ( strNewName.length() <= MAX_LEN_FADER_TAG )
- {
- // refresh internal name parameter
- pClient->ChannelInfo.strName = strNewName;
-
- // update channel info at the server
- pClient->SetRemoteInfo();
- }
- else
- {
- // text is too long, update control with shortened text
- pedtAlias->setText ( TruncateString ( strNewName, MAX_LEN_FADER_TAG ) );
- }
-}
-
-void CClientSettingsDlg::OnInstrumentActivated ( int iCntryListItem )
-{
- // set the new value in the data base
- pClient->ChannelInfo.iInstrument = pcbxInstrument->itemData ( iCntryListItem ).toInt();
-
- // update channel info at the server
- pClient->SetRemoteInfo();
-}
-
-void CClientSettingsDlg::OnCountryActivated ( int iCntryListItem )
-{
- // set the new value in the data base
- pClient->ChannelInfo.eCountry = static_cast ( pcbxCountry->itemData ( iCntryListItem ).toInt() );
-
- // update channel info at the server
- pClient->SetRemoteInfo();
-}
-
-void CClientSettingsDlg::OnCityTextChanged ( const QString& strNewCity )
-{
- // check length
- if ( strNewCity.length() <= MAX_LEN_SERVER_CITY )
- {
- // refresh internal name parameter
- pClient->ChannelInfo.strCity = strNewCity;
-
- // update channel info at the server
- pClient->SetRemoteInfo();
- }
- else
- {
- // text is too long, update control with shortened text
- pedtCity->setText ( strNewCity.left ( MAX_LEN_SERVER_CITY ) );
- }
-}
-
-void CClientSettingsDlg::OnSkillActivated ( int iCntryListItem )
-{
- // set the new value in the data base
- pClient->ChannelInfo.eSkillLevel = static_cast ( pcbxSkill->itemData ( iCntryListItem ).toInt() );
-
- // update channel info at the server
- pClient->SetRemoteInfo();
-}
-
-void CClientSettingsDlg::OnMakeTabChange ( int iTab )
-{
- tabSettings->setCurrentIndex ( iTab );
-
- pSettings->iSettingsTab = iTab;
-}
-
-void CClientSettingsDlg::OnTabChanged ( void ) { pSettings->iSettingsTab = tabSettings->currentIndex(); }
-
-void CClientSettingsDlg::UpdateAudioFaderSlider()
-{
- // update slider and label of audio fader
- const int iCurAudInFader = pClient->GetAudioInFader();
- sldAudioPan->setValue ( iCurAudInFader );
-
- // show in label the center position and what channel is
- // attenuated
- if ( iCurAudInFader == AUD_FADER_IN_MIDDLE )
- {
- lblAudioPanValue->setText ( tr ( "Center" ) );
- }
- else
- {
- if ( iCurAudInFader > AUD_FADER_IN_MIDDLE )
- {
- // attenuation on right channel
- lblAudioPanValue->setText ( tr ( "L" ) + " -" + QString().setNum ( iCurAudInFader - AUD_FADER_IN_MIDDLE ) );
- }
- else
- {
- // attenuation on left channel
- lblAudioPanValue->setText ( tr ( "R" ) + " -" + QString().setNum ( AUD_FADER_IN_MIDDLE - iCurAudInFader ) );
- }
- }
-}
-
-void CClientSettingsDlg::OnAudioPanValueChanged ( int value )
-{
- pClient->SetAudioInFader ( value );
- UpdateAudioFaderSlider();
-}
diff --git a/src/clientsettingsdlg.h b/src/clientsettingsdlg.h
deleted file mode 100644
index 4678aeb32f..0000000000
--- a/src/clientsettingsdlg.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/******************************************************************************\
- * Copyright (c) 2004-2024
- *
- * Author(s):
- * Volker Fischer
- *
- ******************************************************************************
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- *
-\******************************************************************************/
-
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "global.h"
-#include "util.h"
-#include "client.h"
-#include "settings.h"
-#include "multicolorled.h"
-#include "ui_clientsettingsdlgbase.h"
-
-/* Definitions ****************************************************************/
-// update time for GUI controls
-#define DISPLAY_UPDATE_TIME 1000 // ms
-
-/* Classes ********************************************************************/
-class CClientSettingsDlg : public CBaseDlg, private Ui_CClientSettingsDlgBase
-{
- Q_OBJECT
-
-public:
- CClientSettingsDlg ( CClient* pNCliP, CClientSettings* pNSetP, QWidget* parent = nullptr );
-
- void UpdateUploadRate();
- void UpdateDisplay();
- void UpdateSoundDeviceChannelSelectionFrame();
-
- void SetEnableFeedbackDetection ( bool enable );
-
-protected:
- void UpdateJitterBufferFrame();
- void UpdateSoundCardFrame();
- void UpdateDirectoryComboBox();
- void UpdateAudioFaderSlider();
- QString GenSndCrdBufferDelayString ( const int iFrameSize, const QString strAddText = "" );
-
- virtual void showEvent ( QShowEvent* );
-
- CClient* pClient;
- CClientSettings* pSettings;
- QTimer TimerStatus;
- QButtonGroup SndCrdBufferDelayButtonGroup;
-
-public slots:
- void OnTimerStatus() { UpdateDisplay(); }
- void OnNetBufValueChanged ( int value );
- void OnNetBufServerValueChanged ( int value );
- void OnAutoJitBufStateChanged ( int value );
- void OnEnableOPUS64StateChanged ( int value );
- void OnFeedbackDetectionChanged ( int value );
- void OnCustomDirectoriesChanged ( bool bDelete );
- void OnNewClientLevelEditingFinished() { pSettings->iNewClientFaderLevel = edtNewClientLevel->text().toInt(); }
- void OnInputBoostChanged();
- void OnSndCrdBufferDelayButtonGroupClicked ( QAbstractButton* button );
- void OnSoundcardActivated ( int iSndDevIdx );
- void OnLInChanActivated ( int iChanIdx );
- void OnRInChanActivated ( int iChanIdx );
- void OnLOutChanActivated ( int iChanIdx );
- void OnROutChanActivated ( int iChanIdx );
- void OnAudioChannelsActivated ( int iChanIdx );
- void OnAudioQualityActivated ( int iQualityIdx );
- void OnGUIDesignActivated ( int iDesignIdx );
- void OnMeterStyleActivated ( int iMeterStyleIdx );
- void OnAudioAlertsChanged ( int value );
- void OnLanguageChanged ( QString strLanguage ) { pSettings->strLanguage = strLanguage; }
- void OnAliasTextChanged ( const QString& strNewName );
- void OnInstrumentActivated ( int iCntryListItem );
- void OnCountryActivated ( int iCntryListItem );
- void OnCityTextChanged ( const QString& strNewName );
- void OnSkillActivated ( int iCntryListItem );
- void OnTabChanged();
- void OnMakeTabChange ( int iTabIdx );
- void OnAudioPanValueChanged ( int value );
-
-#if defined( _WIN32 ) && !defined( WITH_JACK )
- // Only include this slot for Windows when JACK is NOT used
- void OnDriverSetupClicked();
-#endif
-
-signals:
- void GUIDesignChanged();
- void MeterStyleChanged();
- void AudioAlertsChanged();
- void AudioChannelsChanged();
- void CustomDirectoriesChanged();
- void NumMixerPanelRowsChanged ( int value );
-};
diff --git a/src/clientsettingsdlgbase.ui b/src/clientsettingsdlgbase.ui
deleted file mode 100644
index 7ee311701a..0000000000
--- a/src/clientsettingsdlgbase.ui
+++ /dev/null
@@ -1,1387 +0,0 @@
-
-
- CClientSettingsDlgBase
-
-
-
- 0
- 0
- 436
- 524
-
-
-
- Settings
-
-
-
- :/png/main/res/fronticon.png:/png/main/res/fronticon.png
-
-
- true
-
-
- -
-
-
-
- 0
- 0
-
-
-
- 1
-
-
- true
-
-
-
- My Profile
-
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 0
- 20
-
-
-
-
- -
-
-
-
-
-
- Qt::Vertical
-
-
- QSizePolicy::Preferred
-
-
-
- 20
- 13
-
-
-
-
- -
-
-
- Musician's Profile
-
-
-
-
-
-
-
-
-
-
-
-
- Alias/Name
-
-
- pedtAlias
-
-
-
- -
-
-
- Instrument
-
-
- pcbxInstrument
-
-
-
- -
-
-
- Country/Region
-
-
- pcbxCountry
-
-
-
- -
-
-
- City
-
-
- pedtCity
-
-
-
- -
-
-
- Skill
-
-
- pcbxSkill
-
-
-
-
-
- -
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 150
- 0
-
-
-
-
- -
-
-
-
- 150
- 0
-
-
-
-
- -
-
-
-
- 150
- 0
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 150
- 0
-
-
-
-
- -
-
-
-
- 150
- 0
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- User Interface
-
-
-
-
-
-
-
-
-
-
-
-
- Skin
-
-
- cbxSkin
-
-
-
- -
-
-
- Meter Style
-
-
- cbxMeterStyle
-
-
-
- -
-
-
- Language
-
-
- cbxLanguage
-
-
-
- -
-
-
- Mixer Rows
-
-
- spnMixerRows
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
- -
-
-
-
- 150
- 0
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- 1
-
-
- 8
-
-
-
- -
-
-
- Audio Alerts
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 14
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 0
- 20
-
-
-
-
-
-
-
-
-
-
- Audio/Network Setup
-
-
- -
-
-
-
-
-
-
-
-
- Audio Device
-
-
- cbxSoundcard
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Expanding
-
-
-
- 20
- 10
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Driver Setup
-
-
- false
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 10
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- QFrame::NoFrame
-
-
- QFrame::Plain
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Input Channel Mapping
-
-
-
- -
-
-
- 3
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- L
-
-
- cbxLInChan
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- R
-
-
- cbxRInChan
-
-
-
-
-
- -
-
-
- 3
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- Output Channel Mapping
-
-
-
- -
-
-
- 3
-
-
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- L
-
-
- cbxLOutChan
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- R
-
-
- cbxROutChan
-
-
-
-
-
- -
-
-
- 3
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Expanding
-
-
-
- 20
- 10
-
-
-
-
- -
-
-
-
-
-
-
-
-
- Audio Channels
-
-
- cbxAudioChannels
-
-
-
- -
-
-
- Audio Quality
-
-
- cbxAudioQuality
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 10
-
-
-
-
- -
-
-
- Buffer Delay
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- (preferred)
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- (default)
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- (safe)
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::MinimumExpanding
-
-
-
- 0
- 20
-
-
-
-
- -
-
-
-
-
-
- Jitter Buffer
-
-
-
-
-
-
-
- 0
- 0
-
-
-
- Auto
-
-
-
- -
-
-
-
-
-
- Local
-
-
- Qt::AlignCenter
-
-
- false
-
-
-
- -
-
-
- Server
-
-
- Qt::AlignCenter
-
-
- false
-
-
-
-
-
- -
-
-
-
-
-
- Size
-
-
- Qt::AlignCenter
-
-
- false
-
-
-
- -
-
-
- Size
-
-
- Qt::AlignCenter
-
-
- false
-
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Minimum
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
- 1
-
-
- 20
-
-
- 1
-
-
- Qt::Vertical
-
-
- QSlider::TicksBothSides
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Minimum
-
-
-
- 0
- 0
-
-
-
-
- -
-
-
- 1
-
-
- 20
-
-
- 1
-
-
- Qt::Vertical
-
-
- QSlider::TicksBothSides
-
-
-
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Small Network Buffers
-
-
-
- -
-
-
- Audio Stream Rate
-
-
-
- 2
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 1
- 5
-
-
-
-
- -
-
-
- kbps
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
- val
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
- 2
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 1
- 5
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Minimum
-
-
-
- 0
- 20
-
-
-
-
-
-
-
-
-
-
- Advanced Setup
-
-
- -
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 10
- 20
-
-
-
-
- -
-
-
-
-
-
- Qt::Vertical
-
-
- QSizePolicy::MinimumExpanding
-
-
-
- 17
- 20
-
-
-
-
- -
-
-
- Custom Directories:
-
-
- cbxCustomDirectories
-
-
-
- -
-
-
-
-
-
- true
-
-
-
- -
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- New Client Level
-
-
- edtNewClientLevel
-
-
-
- -
-
-
-
-
-
- -
-
-
- %
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
- Input Boost
-
-
- cbxInputBoost
-
-
-
- -
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Feedback Protection
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 10
- 20
-
-
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Preferred
-
-
-
- 20
- 20
-
-
-
-
- -
-
-
- Input Balance
-
-
-
-
-
-
- 3
-
-
-
-
-
- Pan
-
-
- Qt::AlignCenter
-
-
- sldAudioPan
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Minimum
-
-
-
- 0
- 20
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
-
-
-
- 1
-
-
- Qt::Horizontal
-
-
- QSlider::TicksBothSides
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Minimum
-
-
-
- 0
- 20
-
-
-
-
-
-
- -
-
-
-
- 50
- 0
-
-
-
- Center
-
-
- Qt::AlignCenter
-
-
- false
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QSizePolicy::Preferred
-
-
-
- 20
- 20
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 367
- 13
-
-
-
-
-
-
-
-
-
-
-
-
- CLanguageComboBox
- QComboBox
-
-
-
-
- pedtAlias
- pcbxInstrument
- pcbxCountry
- pedtCity
- pcbxSkill
- cbxSkin
- cbxMeterStyle
- cbxLanguage
- spnMixerRows
- chbAudioAlerts
- cbxSoundcard
- butDriverSetup
- cbxLInChan
- cbxRInChan
- cbxLOutChan
- cbxROutChan
- cbxAudioChannels
- cbxAudioQuality
- rbtBufferDelayPreferred
- rbtBufferDelayDefault
- rbtBufferDelaySafe
- chbAutoJitBuf
- sldNetBuf
- sldNetBufServer
- chbSmallNetworkBuffers
- cbxCustomDirectories
- tbtDeleteCustomDirectory
- edtNewClientLevel
- cbxInputBoost
- chbDetectFeedback
- sldAudioPan
-
-
-
-
-
-
diff --git a/src/connectdlg.cpp b/src/connectdlg.cpp
deleted file mode 100644
index 06c0dfccfc..0000000000
--- a/src/connectdlg.cpp
+++ /dev/null
@@ -1,1034 +0,0 @@
-/******************************************************************************\
- * Copyright (c) 2004-2024
- *
- * Author(s):
- * Volker Fischer
- *
- ******************************************************************************
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- *
-\******************************************************************************/
-
-#include "connectdlg.h"
-
-/* Implementation *************************************************************/
-CConnectDlg::CConnectDlg ( CClientSettings* pNSetP, const bool bNewShowCompleteRegList, const bool bNEnableIPv6, QWidget* parent ) :
- CBaseDlg ( parent, Qt::Dialog ),
- pSettings ( pNSetP ),
- strSelectedAddress ( "" ),
- strSelectedServerName ( "" ),
- bShowCompleteRegList ( bNewShowCompleteRegList ),
- bServerListReceived ( false ),
- bReducedServerListReceived ( false ),
- bServerListItemWasChosen ( false ),
- bListFilterWasActive ( false ),
- bShowAllMusicians ( true ),
- bEnableIPv6 ( bNEnableIPv6 )
-{
- setupUi ( this );
-
- // Add help text to controls -----------------------------------------------
- // directory
- QString strDirectoryWT = "" + tr ( "Directory" ) + ": " +
- tr ( "Shows the servers listed by the selected directory. "
- "You can add custom directories in Advanced Settings." );
- QString strDirectoryAN = tr ( "Directory combo box" );
-
- lblList->setWhatsThis ( strDirectoryWT );
- lblList->setAccessibleName ( strDirectoryAN );
- cbxDirectory->setWhatsThis ( strDirectoryWT );
- cbxDirectory->setAccessibleName ( strDirectoryAN );
-
- // filter
- QString strFilterWT = "" + tr ( "Filter" ) + ": " +
- tr ( "Filters the server list by the given text. Note that the filter is case insensitive. "
- "A single # character will filter for those servers with at least one person connected." );
- QString strFilterAN = tr ( "Filter edit box" );
- lblFilter->setWhatsThis ( strFilterWT );
- edtFilter->setWhatsThis ( strFilterWT );
-
- lblFilter->setAccessibleName ( strFilterAN );
- edtFilter->setAccessibleName ( strFilterAN );
-
- // show all mucisians
- chbExpandAll->setWhatsThis ( "" + tr ( "Show All Musicians" ) + ": " +
- tr ( "Uncheck to collapse the server list to show just the server details. "
- "Check to show everyone on the servers." ) );
-
- chbExpandAll->setAccessibleName ( tr ( "Show all musicians check box" ) );
-
- // server list view
- lvwServers->setWhatsThis ( "" + tr ( "Server List" ) + ": " +
- tr ( "The Connection Setup window lists the available servers registered with "
- "the selected directory. Use the Directory dropdown to change the directory, "
- "find the server you want to join in the server list, click on it, and "
- "then click the Connect button to connect. Alternatively, double click on "
- "the server name to connect." ) +
- "
" + tr ( "Permanent servers (those that have been listed for longer than 48 hours) are shown in bold." ) +
- "
" + tr ( "You can add custom directories in Advanced Settings." ) );
-
- lvwServers->setAccessibleName ( tr ( "Server list view" ) );
-
- // server address
- QString strServAddrH = "" + tr ( "Server Address" ) + ": " +
- tr ( "If you know the server address, you can connect to it "
- "using the Server name/Address field. An optional port number can be added after the server "
- "address using a colon as a separator, e.g. %1. "
- "The field will also show a list of the most recently used server addresses." )
- .arg ( QString ( "example.org:%1" ).arg ( DEFAULT_PORT_NUMBER ) );
-
- lblServerAddr->setWhatsThis ( strServAddrH );
- cbxServerAddr->setWhatsThis ( strServAddrH );
-
- cbxServerAddr->setAccessibleName ( tr ( "Server address edit box" ) );
- cbxServerAddr->setAccessibleDescription ( tr ( "Holds the current server address. It also stores old addresses in the combo box list." ) );
-
- tbtDeleteServerAddr->setAccessibleName ( tr ( "Delete server address button" ) );
- tbtDeleteServerAddr->setWhatsThis ( "" + tr ( "Delete Server Address" ) + ": " +
- tr ( "Click the button to clear the currently selected server address "
- "and delete it from the list of stored servers." ) );
- tbtDeleteServerAddr->setText ( u8"\u232B" );
-
- UpdateDirectoryComboBox();
-
- // init server address combo box (max MAX_NUM_SERVER_ADDR_ITEMS entries)
- cbxServerAddr->setMaxCount ( MAX_NUM_SERVER_ADDR_ITEMS );
- cbxServerAddr->setInsertPolicy ( QComboBox::NoInsert );
-
- // set up list view for connected clients (note that the last column size
- // must not be specified since this column takes all the remaining space)
-#ifdef ANDROID
- // for Android we need larger numbers because of the default font size
- lvwServers->setColumnWidth ( LVC_NAME, 200 );
- lvwServers->setColumnWidth ( LVC_PING, 130 );
- lvwServers->setColumnWidth ( LVC_CLIENTS, 100 );
- lvwServers->setColumnWidth ( LVC_VERSION, 110 );
-#else
- lvwServers->setColumnWidth ( LVC_NAME, 180 );
- lvwServers->setColumnWidth ( LVC_PING, 75 );
- lvwServers->setColumnWidth ( LVC_CLIENTS, 70 );
- lvwServers->setColumnWidth ( LVC_LOCATION, 220 );
- lvwServers->setColumnWidth ( LVC_VERSION, 65 );
-#endif
- lvwServers->clear();
-
- // make sure we do not get a too long horizontal scroll bar
- lvwServers->header()->setStretchLastSection ( false );
-
- // add invisible columns which are used for sorting the list and storing
- // the current/maximum number of clients
- // 0: server name
- // 1: ping time
- // 2: number of musicians (including additional strings like " (full)")
- // 3: location
- // 4: server version
- // 5: minimum ping time (invisible)
- // 6: maximum number of clients (invisible)
- // (see EConnectListViewColumns in connectdlg.h, which must match the above)
-
- lvwServers->setColumnCount ( LVC_COLUMNS );
- lvwServers->hideColumn ( LVC_PING_MIN_HIDDEN );
- lvwServers->hideColumn ( LVC_CLIENTS_MAX_HIDDEN );
-
- // per default the root shall not be decorated (to save space)
- lvwServers->setRootIsDecorated ( false );
-
- // make sure the connect button has the focus
- butConnect->setFocus();
-
- // for "show all servers" mode make sort by click on header possible
- if ( bShowCompleteRegList )
- {
- lvwServers->setSortingEnabled ( true );
- lvwServers->sortItems ( LVC_NAME, Qt::AscendingOrder );
- }
-
- // set a placeholder text to explain how to filter occupied servers (#397)
- edtFilter->setPlaceholderText ( tr ( "Filter text, or # for occupied servers" ) );
-
- // setup timers
- TimerInitialSort.setSingleShot ( true ); // only once after list request
-
-#if defined( ANDROID ) || defined( Q_OS_IOS )
- // for the Android and iOS version maximize the window
- setWindowState ( Qt::WindowMaximized );
-#endif
-
- // Connections -------------------------------------------------------------
- // list view
- QObject::connect ( lvwServers, &QTreeWidget::itemDoubleClicked, this, &CConnectDlg::OnServerListItemDoubleClicked );
-
- // to get default return key behaviour working
- QObject::connect ( lvwServers, &QTreeWidget::activated, this, &CConnectDlg::OnConnectClicked );
-
- // line edit
- QObject::connect ( edtFilter, &QLineEdit::textEdited, this, &CConnectDlg::OnFilterTextEdited );
-
- // combo boxes
- QObject::connect ( cbxServerAddr, &QComboBox::editTextChanged, this, &CConnectDlg::OnServerAddrEditTextChanged );
-
- QObject::connect ( cbxDirectory, static_cast ( &QComboBox::activated ), this, &CConnectDlg::OnDirectoryChanged );
-
- // check boxes
- QObject::connect ( chbExpandAll, &QCheckBox::stateChanged, this, &CConnectDlg::OnExpandAllStateChanged );
-
- // buttons
- QObject::connect ( butCancel, &QPushButton::clicked, this, &CConnectDlg::close );
-
- QObject::connect ( butConnect, &QPushButton::clicked, this, &CConnectDlg::OnConnectClicked );
-
- // tool buttons
- QObject::connect ( tbtDeleteServerAddr, &QToolButton::clicked, this, &CConnectDlg::OnDeleteServerAddrClicked );
-
- // timers
- QObject::connect ( &TimerPing, &QTimer::timeout, this, &CConnectDlg::OnTimerPing );
-
- QObject::connect ( &TimerReRequestServList, &QTimer::timeout, this, &CConnectDlg::OnTimerReRequestServList );
-}
-
-void CConnectDlg::showEvent ( QShowEvent* )
-{
- // load stored IP addresses in combo box
- cbxServerAddr->clear();
- cbxServerAddr->clearEditText();
-
- for ( int iLEIdx = 0; iLEIdx < MAX_NUM_SERVER_ADDR_ITEMS; iLEIdx++ )
- {
- if ( !pSettings->vstrIPAddress[iLEIdx].isEmpty() )
- {
- cbxServerAddr->addItem ( pSettings->vstrIPAddress[iLEIdx] );
- }
- }
-
- // on opening the connect dialg, we always want to request a
- // new updated server list per definition
- RequestServerList();
-}
-
-void CConnectDlg::RequestServerList()
-{
- // reset flags
- bServerListReceived = false;
- bReducedServerListReceived = false;
- bServerListItemWasChosen = false;
- bListFilterWasActive = false;
-
- // clear current address and name
- strSelectedAddress = "";
- strSelectedServerName = "";
-
- // clear server list view
- lvwServers->clear();
-
- // update list combo box (disable events to avoid a signal)
- cbxDirectory->blockSignals ( true );
- if ( pSettings->eDirectoryType == AT_CUSTOM )
- {
- // iCustomDirectoryIndex is non-zero only if eDirectoryType == AT_CUSTOM
- // find the combobox item that corresponds to vstrDirectoryAddress[iCustomDirectoryIndex]
- // (the current selected custom directory)
- cbxDirectory->setCurrentIndex ( cbxDirectory->findData ( QVariant ( pSettings->iCustomDirectoryIndex ) ) );
- }
- else
- {
- cbxDirectory->setCurrentIndex ( static_cast ( pSettings->eDirectoryType ) );
- }
- cbxDirectory->blockSignals ( false );
-
- // Get the IP address of the directory server (using the ParseNetworAddress
- // function) when the connect dialog is opened, this seems to be the correct
- // time to do it. Note that in case of custom directories we
- // use iCustomDirectoryIndex as an index into the vector.
-
- // Allow IPv4 only for communicating with Directories
- if ( NetworkUtil().ParseNetworkAddress (
- NetworkUtil::GetDirectoryAddress ( pSettings->eDirectoryType, pSettings->vstrDirectoryAddress[pSettings->iCustomDirectoryIndex] ),
- haDirectoryAddress,
- false ) )
- {
- // send the request for the server list
- emit ReqServerListQuery ( haDirectoryAddress );
-
- // start timer, if this message did not get any respond to retransmit
- // the server list request message
- TimerReRequestServList.start ( SERV_LIST_REQ_UPDATE_TIME_MS );
- TimerInitialSort.start ( SERV_LIST_REQ_UPDATE_TIME_MS ); // reuse the time value
- }
-}
-
-void CConnectDlg::hideEvent ( QHideEvent* )
-{
- // if window is closed, stop timers
- TimerPing.stop();
- TimerReRequestServList.stop();
-}
-
-void CConnectDlg::OnDirectoryChanged ( int iTypeIdx )
-{
- // store the new directory type and request new list
- // if iTypeIdx == AT_CUSTOM, then iCustomDirectoryIndex is the index into the vector holding the user's custom directory servers
- // if iTypeIdx != AT_CUSTOM, then iCustomDirectoryIndex MUST be 0;
- if ( iTypeIdx >= AT_CUSTOM )
- {
- // the value for the index into the vector vstrDirectoryAddress is in the user data of the combobox item
- pSettings->iCustomDirectoryIndex = cbxDirectory->itemData ( iTypeIdx ).toInt();
- iTypeIdx = AT_CUSTOM;
- }
- else
- {
- pSettings->iCustomDirectoryIndex = 0;
- }
- pSettings->eDirectoryType = static_cast ( iTypeIdx );
- RequestServerList();
-}
-
-void CConnectDlg::OnTimerReRequestServList()
-{
- // if the server list is not yet received, retransmit the request for the
- // server list
- if ( !bServerListReceived )
- {
- // note that this is a connection less message which may get lost
- // and therefore it makes sense to re-transmit it
- emit ReqServerListQuery ( haDirectoryAddress );
- }
-}
-
-void CConnectDlg::SetServerList ( const CHostAddress& InetAddr, const CVector& vecServerInfo, const bool bIsReducedServerList )
-{
- // If the normal list was received, we do not accept any further list
- // updates (to avoid the reduced list overwrites the normal list (#657)). Also,
- // we only accept a server list from the server address we have sent the
- // request for this to (note that we cannot use the port number since the
- // receive port and send port might be different at the directory server).
- if ( bServerListReceived || ( InetAddr.InetAddr != haDirectoryAddress.InetAddr ) )
- {
- return;
- }
-
- // special treatment if a reduced server list was received
- if ( bIsReducedServerList )
- {
- // make sure we only apply the reduced version list once
- if ( bReducedServerListReceived )
- {
- // do nothing
- return;
- }
- else
- {
- bReducedServerListReceived = true;
- }
- }
- else
- {
- // set flag and disable timer for resend server list request if full list
- // was received (i.e. not the reduced list)
- bServerListReceived = true;
- TimerReRequestServList.stop();
- }
-
- // first clear list
- lvwServers->clear();
-
- // add list item for each server in the server list
- const int iServerInfoLen = vecServerInfo.Size();
-
- for ( int iIdx = 0; iIdx < iServerInfoLen; iIdx++ )
- {
- // get the host address, note that for the very first entry which is
- // the directory server, we have to use the receive host address
- // instead
- CHostAddress CurHostAddress;
-
- if ( iIdx > 0 )
- {
- CurHostAddress = vecServerInfo[iIdx].HostAddr;
- }
- else
- {
- // substitute the receive host address for directory server
- CurHostAddress = InetAddr;
- }
-
- // create new list view item
- QTreeWidgetItem* pNewListViewItem = new QTreeWidgetItem ( lvwServers );
-
- // make the entry invisible (will be set to visible on successful ping
- // result) if the complete list of registered servers shall not be shown
- if ( !bShowCompleteRegList )
- {
- pNewListViewItem->setHidden ( true );
- }
-
- // server name (if empty, show host address instead)
- if ( !vecServerInfo[iIdx].strName.isEmpty() )
- {
- pNewListViewItem->setText ( LVC_NAME, vecServerInfo[iIdx].strName );
- }
- else
- {
- // IP address and port (use IP number without last byte)
- // Definition: If the port number is the default port number, we do
- // not show it.
- if ( vecServerInfo[iIdx].HostAddr.iPort == DEFAULT_PORT_NUMBER )
- {
- // only show IP number, no port number
- pNewListViewItem->setText ( LVC_NAME, CurHostAddress.toString ( CHostAddress::SM_IP_NO_LAST_BYTE ) );
- }
- else
- {
- // show IP number and port
- pNewListViewItem->setText ( LVC_NAME, CurHostAddress.toString ( CHostAddress::SM_IP_NO_LAST_BYTE_PORT ) );
- }
- }
-
- // in case of all servers shown, add the registration number at the beginning
- if ( bShowCompleteRegList )
- {
- pNewListViewItem->setText ( LVC_NAME, QString ( "%1: " ).arg ( 1 + iIdx, 3 ) + pNewListViewItem->text ( LVC_NAME ) );
- }
-
- // show server name in bold font if it is a permanent server
- QFont CurServerNameFont = pNewListViewItem->font ( LVC_NAME );
- CurServerNameFont.setBold ( vecServerInfo[iIdx].bPermanentOnline );
- pNewListViewItem->setFont ( LVC_NAME, CurServerNameFont );
-
- // the ping time shall be shown in bold font
- QFont CurPingTimeFont = pNewListViewItem->font ( LVC_PING );
- CurPingTimeFont.setBold ( true );
- pNewListViewItem->setFont ( LVC_PING, CurPingTimeFont );
-
- // server location (city and country)
- QString strLocation = vecServerInfo[iIdx].strCity;
-
- if ( ( !strLocation.isEmpty() ) && ( vecServerInfo[iIdx].eCountry != QLocale::AnyCountry ) )
- {
- strLocation += ", ";
- }
-
- if ( vecServerInfo[iIdx].eCountry != QLocale::AnyCountry )
- {
- QString strCountryToString = QLocale::countryToString ( vecServerInfo[iIdx].eCountry );
-
- // Qt countryToString does not use spaces in between country name
- // parts but they use upper case letters which we can detect and
- // insert spaces as a post processing
-#if QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 )
- if ( !strCountryToString.contains ( " " ) )
- {
- QRegularExpressionMatchIterator reMatchIt = QRegularExpression ( "[A-Z][^A-Z]*" ).globalMatch ( strCountryToString );
- QStringList slNames;
- while ( reMatchIt.hasNext() )
- {
- slNames << reMatchIt.next().capturedTexts();
- }
- strCountryToString = slNames.join ( " " );
- }
-#endif
-
- strLocation += strCountryToString;
- }
-
- pNewListViewItem->setText ( LVC_LOCATION, strLocation );
-
- // init the minimum ping time with a large number (note that this number
- // must fit in an integer type)
- pNewListViewItem->setText ( LVC_PING_MIN_HIDDEN, "99999999" );
-
- // store the maximum number of clients
- pNewListViewItem->setText ( LVC_CLIENTS_MAX_HIDDEN, QString().setNum ( vecServerInfo[iIdx].iMaxNumClients ) );
-
- // store host address
- pNewListViewItem->setData ( LVC_NAME, Qt::UserRole, CurHostAddress.toString() );
-
- // per default expand the list item (if not "show all servers")
- if ( bShowAllMusicians )
- {
- lvwServers->expandItem ( pNewListViewItem );
- }
- }
-
- // immediately issue the ping measurements and start the ping timer since
- // the server list is filled now
- OnTimerPing();
- TimerPing.start ( PING_UPDATE_TIME_SERVER_LIST_MS );
-}
-
-void CConnectDlg::SetConnClientsList ( const CHostAddress& InetAddr, const CVector& vecChanInfo )
-{
- // find the server with the correct address
- QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
-
- if ( pCurListViewItem )
- {
- // first remove any existing children
- DeleteAllListViewItemChilds ( pCurListViewItem );
-
- // get number of connected clients
- const int iNumConnectedClients = vecChanInfo.Size();
-
- for ( int i = 0; i < iNumConnectedClients; i++ )
- {
- // create new list view item
- QTreeWidgetItem* pNewChildListViewItem = new QTreeWidgetItem ( pCurListViewItem );
-
- // child items shall use only one column
- pNewChildListViewItem->setFirstColumnSpanned ( true );
-
- // set the clients name
- QString sClientText = vecChanInfo[i].strName;
-
- // set the icon: country flag has priority over instrument
- bool bCountryFlagIsUsed = false;
-
- if ( vecChanInfo[i].eCountry != QLocale::AnyCountry )
- {
- // try to load the country flag icon
- QPixmap CountryFlagPixmap ( CLocale::GetCountryFlagIconsResourceReference ( vecChanInfo[i].eCountry ) );
-
- // first check if resource reference was valid
- if ( !CountryFlagPixmap.isNull() )
- {
- // set correct picture
- pNewChildListViewItem->setIcon ( LVC_NAME, QIcon ( CountryFlagPixmap ) );
-
- bCountryFlagIsUsed = true;
- }
- }
-
- if ( !bCountryFlagIsUsed )
- {
- // get the resource reference string for this instrument
- const QString strCurResourceRef = CInstPictures::GetResourceReference ( vecChanInfo[i].iInstrument );
-
- // first check if instrument picture is used or not and if it is valid
- if ( !( CInstPictures::IsNotUsedInstrument ( vecChanInfo[i].iInstrument ) || strCurResourceRef.isEmpty() ) )
- {
- // set correct picture
- pNewChildListViewItem->setIcon ( LVC_NAME, QIcon ( QPixmap ( strCurResourceRef ) ) );
- }
- }
-
- // add the instrument information as text
- if ( !CInstPictures::IsNotUsedInstrument ( vecChanInfo[i].iInstrument ) )
- {
- sClientText.append ( " (" + CInstPictures::GetName ( vecChanInfo[i].iInstrument ) + ")" );
- }
-
- // apply the client text to the list view item
- pNewChildListViewItem->setText ( LVC_NAME, sClientText );
-
- // add the new child to the corresponding server item
- pCurListViewItem->addChild ( pNewChildListViewItem );
-
- // at least one server has children now, show decoration to be able
- // to show the children
- lvwServers->setRootIsDecorated ( true );
- }
-
- // the clients list may have changed, update the filter selection
- UpdateListFilter();
- }
-}
-
-void CConnectDlg::OnServerListItemDoubleClicked ( QTreeWidgetItem* Item, int )
-{
- // if a server list item was double clicked, it is the same as if the
- // connect button was clicked
- if ( Item != nullptr )
- {
- OnConnectClicked();
- }
-}
-
-void CConnectDlg::OnServerAddrEditTextChanged ( const QString& )
-{
- // in the server address combo box, a text was changed, remove selection
- // in the server list (if any)
- lvwServers->clearSelection();
-}
-
-void CConnectDlg::OnCustomDirectoriesChanged()
-{
-
- QString strPreviousSelection = cbxDirectory->currentText();
- UpdateDirectoryComboBox();
- // after updating the combobox, we must re-select the previous directory selection
-
- if ( pSettings->eDirectoryType == AT_CUSTOM )
- {
- // check if the currently select custom directory still exists in the now potentially re-ordered vector,
- // if so, then change to its new index. (addresses Issue #1899)
- int iNewIndex = cbxDirectory->findText ( strPreviousSelection, Qt::MatchExactly );
- if ( iNewIndex == INVALID_INDEX )
- {
- // previously selected custom directory has been deleted. change to default directory
- pSettings->eDirectoryType = static_cast ( AT_DEFAULT );
- pSettings->iCustomDirectoryIndex = 0;
- RequestServerList();
- }
- else
- {
- // find previously selected custom directory in the now potentially re-ordered vector
- pSettings->eDirectoryType = static_cast ( AT_CUSTOM );
- pSettings->iCustomDirectoryIndex = cbxDirectory->itemData ( iNewIndex ).toInt();
- cbxDirectory->blockSignals ( true );
- cbxDirectory->setCurrentIndex ( cbxDirectory->findData ( QVariant ( pSettings->iCustomDirectoryIndex ) ) );
- cbxDirectory->blockSignals ( false );
- }
- }
- else
- {
- // selected directory was not a custom directory
- cbxDirectory->blockSignals ( true );
- cbxDirectory->setCurrentIndex ( static_cast ( pSettings->eDirectoryType ) );
- cbxDirectory->blockSignals ( false );
- }
-}
-
-void CConnectDlg::ShowAllMusicians ( const bool bState )
-{
- bShowAllMusicians = bState;
-
- // update list
- if ( bState )
- {
- lvwServers->expandAll();
- }
- else
- {
- lvwServers->collapseAll();
- }
-
- // update check box if necessary
- if ( ( chbExpandAll->checkState() == Qt::Checked && !bShowAllMusicians ) || ( chbExpandAll->checkState() == Qt::Unchecked && bShowAllMusicians ) )
- {
- chbExpandAll->setCheckState ( bState ? Qt::Checked : Qt::Unchecked );
- }
-}
-
-void CConnectDlg::UpdateListFilter()
-{
- const QString sFilterText = edtFilter->text();
-
- if ( !sFilterText.isEmpty() )
- {
- bListFilterWasActive = true;
- const int iServerListLen = lvwServers->topLevelItemCount();
-
- for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ )
- {
- QTreeWidgetItem* pCurListViewItem = lvwServers->topLevelItem ( iIdx );
- bool bFilterFound = false;
-
- // DEFINITION: if "#" is set at the beginning of the filter text, we show
- // occupied servers (#397)
- if ( ( sFilterText.indexOf ( "#" ) == 0 ) && ( sFilterText.length() == 1 ) )
- {
- // special case: filter for occupied servers
- if ( pCurListViewItem->childCount() > 0 )
- {
- bFilterFound = true;
- }
- }
- else
- {
- // search server name
- if ( pCurListViewItem->text ( LVC_NAME ).indexOf ( sFilterText, 0, Qt::CaseInsensitive ) >= 0 )
- {
- bFilterFound = true;
- }
-
- // search location
- if ( pCurListViewItem->text ( LVC_LOCATION ).indexOf ( sFilterText, 0, Qt::CaseInsensitive ) >= 0 )
- {
- bFilterFound = true;
- }
-
- // search children
- for ( int iCCnt = 0; iCCnt < pCurListViewItem->childCount(); iCCnt++ )
- {
- if ( pCurListViewItem->child ( iCCnt )->text ( LVC_NAME ).indexOf ( sFilterText, 0, Qt::CaseInsensitive ) >= 0 )
- {
- bFilterFound = true;
- }
- }
- }
-
- // only update Hide state if ping time was received
- if ( !pCurListViewItem->text ( LVC_PING ).isEmpty() || bShowCompleteRegList )
- {
- // only update hide and expand status if the hide state has to be changed to
- // preserve if user clicked on expand icon manually
- if ( ( pCurListViewItem->isHidden() && bFilterFound ) || ( !pCurListViewItem->isHidden() && !bFilterFound ) )
- {
- pCurListViewItem->setHidden ( !bFilterFound );
- pCurListViewItem->setExpanded ( bShowAllMusicians );
- }
- }
- }
- }
- else
- {
- // if the filter was active but is now disabled, we have to update all list
- // view items for the "ping received" hide state
- if ( bListFilterWasActive )
- {
- const int iServerListLen = lvwServers->topLevelItemCount();
-
- for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ )
- {
- QTreeWidgetItem* pCurListViewItem = lvwServers->topLevelItem ( iIdx );
-
- // if ping time is empty, hide item (if not already hidden)
- if ( pCurListViewItem->text ( LVC_PING ).isEmpty() && !bShowCompleteRegList )
- {
- pCurListViewItem->setHidden ( true );
- }
- else
- {
- // in case it was hidden, show it and take care of expand
- if ( pCurListViewItem->isHidden() )
- {
- pCurListViewItem->setHidden ( false );
- pCurListViewItem->setExpanded ( bShowAllMusicians );
- }
- }
- }
-
- bListFilterWasActive = false;
- }
- }
-}
-
-void CConnectDlg::OnConnectClicked()
-{
- // get the IP address to be used according to the following definitions:
- // - if the list has focus and a line is selected, use this line
- // - if the list has no focus, use the current combo box text
- QList CurSelListItemList = lvwServers->selectedItems();
-
- if ( CurSelListItemList.count() > 0 )
- {
- // get the parent list view item
- QTreeWidgetItem* pCurSelTopListItem = GetParentListViewItem ( CurSelListItemList[0] );
-
- // get host address from selected list view item as a string
- strSelectedAddress = pCurSelTopListItem->data ( LVC_NAME, Qt::UserRole ).toString();
-
- // store selected server name
- strSelectedServerName = pCurSelTopListItem->text ( LVC_NAME );
-
- // set flag that a server list item was chosen to connect
- bServerListItemWasChosen = true;
- }
- else
- {
- strSelectedAddress = NetworkUtil::FixAddress ( cbxServerAddr->currentText() );
- }
-
- // tell the parent window that the connection shall be initiated
- done ( QDialog::Accepted );
-}
-
-void CConnectDlg::OnDeleteServerAddrClicked()
-{
- if ( cbxServerAddr->currentText().isEmpty() )
- {
- return;
- }
-
- // move later items down one
- for ( int iLEIdx = 0; iLEIdx < MAX_NUM_SERVER_ADDR_ITEMS - 1; iLEIdx++ )
- {
- while ( pSettings->vstrIPAddress[iLEIdx].compare ( cbxServerAddr->currentText() ) == 0 )
- {
- for ( int jLEIdx = iLEIdx + 1; jLEIdx < MAX_NUM_SERVER_ADDR_ITEMS; jLEIdx++ )
- {
- pSettings->vstrIPAddress[jLEIdx - 1] = pSettings->vstrIPAddress[jLEIdx];
- }
- }
- }
- // empty last entry
- pSettings->vstrIPAddress[MAX_NUM_SERVER_ADDR_ITEMS - 1] = QString();
-
- // redisplay to pick up updated list
- showEvent ( nullptr );
-}
-
-void CConnectDlg::OnTimerPing()
-{
- // send ping messages to the servers in the list
- const int iServerListLen = lvwServers->topLevelItemCount();
-
- for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ )
- {
- QTreeWidgetItem* pCurListViewItem = lvwServers->topLevelItem ( iIdx );
-
- // we need to ask for the server version only if we have not received it
- const bool bNeedVersion = pCurListViewItem->text ( LVC_VERSION ).isEmpty();
-
- CHostAddress haServerAddress;
-
- // try to parse host address string which is stored as user data
- // in the server list item GUI control element
- if ( NetworkUtil().ParseNetworkAddress ( pCurListViewItem->data ( LVC_NAME, Qt::UserRole ).toString(), haServerAddress, bEnableIPv6 ) )
- {
- // if address is valid, send ping message using a new thread
-#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
- QFuture f = QtConcurrent::run ( &CConnectDlg::EmitCLServerListPingMes, this, haServerAddress, bNeedVersion );
- Q_UNUSED ( f );
-#else
- QtConcurrent::run ( this, &CConnectDlg::EmitCLServerListPingMes, haServerAddress, bNeedVersion );
-#endif
- }
- }
-}
-
-void CConnectDlg::EmitCLServerListPingMes ( const CHostAddress& haServerAddress, const bool bNeedVersion )
-{
- // The ping time messages for all servers should not be sent all in a very
- // short time since it showed that this leads to errors in the ping time
- // measurement (#49). We therefore introduce a short delay for each server
- // (since we are doing this in a separate thread for each server, we do not
- // block the GUI).
- QThread::msleep ( 11 );
-
- // first request the server version if we have not already received it
- if ( bNeedVersion )
- {
- emit CreateCLServerListReqVerAndOSMes ( haServerAddress );
- }
-
- emit CreateCLServerListPingMes ( haServerAddress );
-}
-
-void CConnectDlg::SetPingTimeAndNumClientsResult ( const CHostAddress& InetAddr, const int iPingTime, const int iNumClients )
-{
- // apply the received ping time to the correct server list entry
- QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
-
- if ( pCurListViewItem )
- {
- // check if this is the first time a ping time is set
- const bool bIsFirstPing = pCurListViewItem->text ( LVC_PING ).isEmpty();
- bool bDoSorting = false;
-
- // update minimum ping time column (invisible, used for sorting) if
- // the new value is smaller than the old value
- int iMinPingTime = pCurListViewItem->text ( LVC_PING_MIN_HIDDEN ).toInt();
-
- if ( iMinPingTime > iPingTime )
- {
- // update the minimum ping time with the new lowest value
- iMinPingTime = iPingTime;
-
- // we pad to a total of 8 characters with zeros to make sure the
- // sorting is done correctly
- pCurListViewItem->setText ( LVC_PING_MIN_HIDDEN, QString ( "%1" ).arg ( iPingTime, 8, 10, QLatin1Char ( '0' ) ) );
-
- // update the sorting (lowest number on top)
- bDoSorting = true;
- }
-
- // for debugging it is good to see the current ping time in the list
- // and not the minimum ping time -> overwrite the value for debugging
- if ( bShowCompleteRegList )
- {
- iMinPingTime = iPingTime;
- }
-
- // Only show minimum ping time in the list since this is the important
- // value. Temporary bad ping measurements are of no interest.
- // Color definition: <= 25 ms green, <= 50 ms yellow, otherwise red
- if ( iMinPingTime <= 25 )
- {
- pCurListViewItem->setForeground ( LVC_PING, Qt::darkGreen );
- }
- else
- {
- if ( iMinPingTime <= 50 )
- {
- pCurListViewItem->setForeground ( LVC_PING, Qt::darkYellow );
- }
- else
- {
- pCurListViewItem->setForeground ( LVC_PING, Qt::red );
- }
- }
-
- // update ping text, take special care if ping time exceeds a
- // certain value
- if ( iMinPingTime > 500 )
- {
- pCurListViewItem->setText ( LVC_PING, ">500 ms" );
- }
- else
- {
- // prepend spaces so that we can sort correctly (fieldWidth of
- // 4 is sufficient since the maximum width is ">500") (#201)
- pCurListViewItem->setText ( LVC_PING, QString ( "%1 ms" ).arg ( iMinPingTime, 4, 10, QLatin1Char ( ' ' ) ) );
- }
-
- // update number of clients text
- if ( pCurListViewItem->text ( LVC_CLIENTS_MAX_HIDDEN ).toInt() == 0 )
- {
- // special case: reduced server list
- pCurListViewItem->setText ( LVC_CLIENTS, QString().setNum ( iNumClients ) );
- }
- else if ( iNumClients >= pCurListViewItem->text ( LVC_CLIENTS_MAX_HIDDEN ).toInt() )
- {
- pCurListViewItem->setText ( LVC_CLIENTS, QString().setNum ( iNumClients ) + " (full)" );
- }
- else
- {
- pCurListViewItem->setText ( LVC_CLIENTS, QString().setNum ( iNumClients ) + "/" + pCurListViewItem->text ( LVC_CLIENTS_MAX_HIDDEN ) );
- }
-
- // check if the number of child list items matches the number of
- // connected clients, if not then request the client names
- if ( iNumClients != pCurListViewItem->childCount() )
- {
- emit CreateCLServerListReqConnClientsListMes ( InetAddr );
- }
-
- // this is the first time a ping time was received, set item to visible
- if ( bIsFirstPing )
- {
- pCurListViewItem->setHidden ( false );
- }
-
- // Update sorting. Note that the sorting must be the last action for the
- // current item since the topLevelItem(iIdx) is then no longer valid.
- // To avoid that the list is sorted shortly before a double click (which
- // could lead to connecting an incorrect server) the sorting is disabled
- // as long as the mouse is over the list (but it is not disabled for the
- // initial timer of about 2s, see TimerInitialSort) (#293).
- if ( bDoSorting && !bShowCompleteRegList &&
- ( TimerInitialSort.isActive() || !lvwServers->underMouse() ) ) // do not sort if "show all servers"
- {
- lvwServers->sortByColumn ( LVC_PING_MIN_HIDDEN, Qt::AscendingOrder );
- }
- }
-
- // if no server item has children, do not show decoration
- bool bAnyListItemHasChilds = false;
- const int iServerListLen = lvwServers->topLevelItemCount();
-
- for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ )
- {
- // check if the current list item has children
- if ( lvwServers->topLevelItem ( iIdx )->childCount() > 0 )
- {
- bAnyListItemHasChilds = true;
- }
- }
-
- if ( !bAnyListItemHasChilds )
- {
- lvwServers->setRootIsDecorated ( false );
- }
-
- // we may have changed the Hidden state for some items, if a filter was active, we now
- // have to update it to void lines appear which do not satisfy the filter criteria
- UpdateListFilter();
-}
-
-void CConnectDlg::SetServerVersionResult ( const CHostAddress& InetAddr, const QString& strVersion )
-{
- // apply the received server version to the correct server list entry
- QTreeWidgetItem* pCurListViewItem = FindListViewItem ( InetAddr );
-
- if ( pCurListViewItem )
- {
- pCurListViewItem->setText ( LVC_VERSION, strVersion );
- }
-}
-
-QTreeWidgetItem* CConnectDlg::FindListViewItem ( const CHostAddress& InetAddr )
-{
- const int iServerListLen = lvwServers->topLevelItemCount();
-
- for ( int iIdx = 0; iIdx < iServerListLen; iIdx++ )
- {
- // compare the received address with the user data string of the
- // host address by a string compare
- if ( !lvwServers->topLevelItem ( iIdx )->data ( LVC_NAME, Qt::UserRole ).toString().compare ( InetAddr.toString() ) )
- {
- return lvwServers->topLevelItem ( iIdx );
- }
- }
-
- return nullptr;
-}
-
-QTreeWidgetItem* CConnectDlg::GetParentListViewItem ( QTreeWidgetItem* pItem )
-{
- // check if the current item is already the top item, i.e. the parent
- // query fails and returns null
- if ( pItem->parent() )
- {
- // we only have maximum one level, i.e. if we call the parent function
- // we are at the top item
- return pItem->parent();
- }
- else
- {
- // this item is already the top item
- return pItem;
- }
-}
-
-void CConnectDlg::DeleteAllListViewItemChilds ( QTreeWidgetItem* pItem )
-{
- // loop over all children
- while ( pItem->childCount() > 0 )
- {
- // get the first child in the list
- QTreeWidgetItem* pCurChildItem = pItem->child ( 0 );
-
- // remove it from the item (note that the object is not deleted)
- pItem->removeChild ( pCurChildItem );
-
- // delete the object to avoid a memory leak
- delete pCurChildItem;
- }
-}
-
-void CConnectDlg::UpdateDirectoryComboBox()
-{
- // directory type combo box
- cbxDirectory->clear();
- cbxDirectory->addItem ( DirectoryTypeToString ( AT_DEFAULT ) );
- cbxDirectory->addItem ( DirectoryTypeToString ( AT_ANY_GENRE2 ) );
- cbxDirectory->addItem ( DirectoryTypeToString ( AT_ANY_GENRE3 ) );
- cbxDirectory->addItem ( DirectoryTypeToString ( AT_GENRE_ROCK ) );
- cbxDirectory->addItem ( DirectoryTypeToString ( AT_GENRE_JAZZ ) );
- cbxDirectory->addItem ( DirectoryTypeToString ( AT_GENRE_CLASSICAL_FOLK ) );
- cbxDirectory->addItem ( DirectoryTypeToString ( AT_GENRE_CHORAL ) );
-
- // because custom directories are always added to the top of the vector, add the vector
- // contents to the combobox in reverse order
- for ( int i = MAX_NUM_SERVER_ADDR_ITEMS - 1; i >= 0; i-- )
- {
- if ( pSettings->vstrDirectoryAddress[i] != "" )
- {
- // add vector index (i) to the combobox as user data
- cbxDirectory->addItem ( pSettings->vstrDirectoryAddress[i], i );
- }
- }
-}
diff --git a/src/connectdlg.h b/src/connectdlg.h
deleted file mode 100644
index 9be91cf657..0000000000
--- a/src/connectdlg.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/******************************************************************************\
- * Copyright (c) 2004-2024
- *
- * Author(s):
- * Volker Fischer
- *
- ******************************************************************************
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- *
-\******************************************************************************/
-
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "global.h"
-#include "util.h"
-#include "settings.h"
-#include "multicolorled.h"
-#include "ui_connectdlgbase.h"
-
-/* Definitions ****************************************************************/
-// defines the time interval at which the request server list message is re-
-// transmitted until it is received
-#define SERV_LIST_REQ_UPDATE_TIME_MS 2000 // ms
-
-/* Classes ********************************************************************/
-class CConnectDlg : public CBaseDlg, private Ui_CConnectDlgBase
-{
- Q_OBJECT
-
-public:
- CConnectDlg ( CClientSettings* pNSetP, const bool bNewShowCompleteRegList, const bool bNEnableIPv6, QWidget* parent = nullptr );
-
- void SetShowAllMusicians ( const bool bState ) { ShowAllMusicians ( bState ); }
- bool GetShowAllMusicians() { return bShowAllMusicians; }
-
- void SetServerList ( const CHostAddress& InetAddr, const CVector& vecServerInfo, const bool bIsReducedServerList = false );
-
- void SetConnClientsList ( const CHostAddress& InetAddr, const CVector& vecChanInfo );
-
- void SetPingTimeAndNumClientsResult ( const CHostAddress& InetAddr, const int iPingTime, const int iNumClients );
- void SetServerVersionResult ( const CHostAddress& InetAddr, const QString& strVersion );
-
- bool GetServerListItemWasChosen() const { return bServerListItemWasChosen; }
- QString GetSelectedAddress() const { return strSelectedAddress; }
- QString GetSelectedServerName() const { return strSelectedServerName; }
-
-protected:
- // NOTE: This enum must list the columns in the same order
- // as their column headings in connectdlgbase.ui
- enum EConnectListViewColumns
- {
- LVC_NAME, // server name
- LVC_PING, // ping time
- LVC_CLIENTS, // number of connected clients (including additional strings like " (full)")
- LVC_LOCATION, // location
- LVC_VERSION, // server version
- LVC_PING_MIN_HIDDEN, // minimum ping time (invisible)
- LVC_CLIENTS_MAX_HIDDEN, // maximum number of clients (invisible)
- LVC_COLUMNS // total number of columns
- };
-
- virtual void showEvent ( QShowEvent* );
- virtual void hideEvent ( QHideEvent* );
-
- QTreeWidgetItem* FindListViewItem ( const CHostAddress& InetAddr );
- QTreeWidgetItem* GetParentListViewItem ( QTreeWidgetItem* pItem );
- void DeleteAllListViewItemChilds ( QTreeWidgetItem* pItem );
- void UpdateListFilter();
- void ShowAllMusicians ( const bool bState );
- void RequestServerList();
- void EmitCLServerListPingMes ( const CHostAddress& haServerAddress, const bool bNeedVersion );
- void UpdateDirectoryComboBox();
-
- CClientSettings* pSettings;
-
- QTimer TimerPing;
- QTimer TimerReRequestServList;
- QTimer TimerInitialSort;
- CHostAddress haDirectoryAddress;
- QString strSelectedAddress;
- QString strSelectedServerName;
- bool bShowCompleteRegList;
- bool bServerListReceived;
- bool bReducedServerListReceived;
- bool bServerListItemWasChosen;
- bool bListFilterWasActive;
- bool bShowAllMusicians;
- bool bEnableIPv6;
-
-public slots:
- void OnServerListItemDoubleClicked ( QTreeWidgetItem* Item, int );
- void OnServerAddrEditTextChanged ( const QString& );
- void OnDirectoryChanged ( int iTypeIdx );
- void OnFilterTextEdited ( const QString& ) { UpdateListFilter(); }
- void OnExpandAllStateChanged ( int value ) { ShowAllMusicians ( value == Qt::Checked ); }
- void OnCustomDirectoriesChanged();
- void OnConnectClicked();
- void OnDeleteServerAddrClicked();
- void OnTimerPing();
- void OnTimerReRequestServList();
-
-signals:
- void ReqServerListQuery ( CHostAddress InetAddr );
- void CreateCLServerListPingMes ( CHostAddress InetAddr );
- void CreateCLServerListReqVerAndOSMes ( CHostAddress InetAddr );
- void CreateCLServerListReqConnClientsListMes ( CHostAddress InetAddr );
-};
diff --git a/src/connectdlgbase.ui b/src/connectdlgbase.ui
deleted file mode 100644
index f12cdbe39a..0000000000
--- a/src/connectdlgbase.ui
+++ /dev/null
@@ -1,160 +0,0 @@
-
-
- CConnectDlgBase
-
-
-
- 0
- 0
- 648
- 493
-
-
-
- Connection Setup
-
-
-
- :/png/main/res/fronticon.png:/png/main/res/fronticon.png
-
-
-
-
-
- true
-
-
- -
-
-
- 0
-
-
-
-
-
- Directory
-
-
-
- -
-
-
- -
-
-
- Filter
-
-
-
- -
-
-
- -
-
-
- Show All Musicians
-
-
-
-
-
- -
-
-
- QAbstractItemView::NoEditTriggers
-
-
- true
-
-
-
- Server Name
-
-
-
-
- Ping Time
-
-
-
-
- Musicians
-
-
-
-
- Location
-
-
-
-
- Version
-
-
-
-
- -
-
-
-
-
-
- Server Address
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- true
-
-
-
- -
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 351
- 25
-
-
-
-
- -
-
-
- C&ancel
-
-
-
- -
-
-
- &Connect
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/global.h b/src/global.h
index 12c2bde9c2..170cef628f 100644
--- a/src/global.h
+++ b/src/global.h
@@ -1,376 +1,376 @@
-/******************************************************************************\
- * \Copyright (c) 2004-2024
- * \author Volker Fischer
- *
-
-\mainpage Jamulus source code documentation
-
-\section intro_sec Introduction
-
-The Jamulus software enables musicians to perform real-time jam sessions over the
-internet. There is one server running the Jamulus server software which collects
-the audio data from each Jamulus client, mixes the audio data and sends the mix
-back to each client.
-
-
-Prefix definitions for the GUI:
-
-label: lbl
-combo box: cbx
-line edit: edt
-list view: lvw
-check box: chb
-radio button: rbt
-button: but
-text view: txv
-slider: sld
-LED: led
-group box: grb
-pixmap label: pxl
-LED bar: lbr
-
- ******************************************************************************
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option) any later
- * version.
- *
- * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- *
-\******************************************************************************/
-
-#pragma once
-
-#if _WIN32
-# define _CRT_SECURE_NO_WARNINGS
-#endif
-
-#include
-#include
-#include
-#include
-#include
-#include
-#ifndef _WIN32
-# include // solves a compile problem on recent Ubuntu
-#endif
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-/* Definitions ****************************************************************/
-// define this macro to get debug output
-//#define _DEBUG_
-#undef _DEBUG_
-
-// version and application name (use version from qt prject file)
-#undef VERSION
-#define VERSION APP_VERSION
-#define APP_NAME "Jamulus"
-
-// Windows registry key name of auto run entry for the server
-#define AUTORUN_SERVER_REG_NAME "Jamulus server"
-
-// default names of the ini-file for client and server
-#define DEFAULT_INI_FILE_NAME "Jamulus.ini"
-#define DEFAULT_INI_FILE_NAME_SERVER "Jamulusserver.ini"
-
-// file name for logging file
-#define DEFAULT_LOG_FILE_NAME "Jamulussrvlog.txt"
-
-// System block size, this is the block size on which the audio coder works.
-// All other block sizes must be a multiple of this size.
-// Note that the UpdateAutoSetting() function assumes a value of 128.
-#define SYSTEM_FRAME_SIZE_SAMPLES 64
-#define DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ( 2 * SYSTEM_FRAME_SIZE_SAMPLES )
-
-// additional buffer for delay panning
-#define MAX_DELAY_PANNING_SAMPLES 64
-
-// default server address and port numbers
-#define DEFAULT_QOS_NUMBER 128 // CS4 (Quality of Service)
-#define DEFAULT_SERVER_ADDRESS "anygenre1.jamulus.io"
-#define DEFAULT_PORT_NUMBER 22124
-#define CENTSERV_ANY_GENRE2 "anygenre2.jamulus.io:22224"
-#define CENTSERV_ANY_GENRE3 "anygenre3.jamulus.io:22624"
-#define CENTSERV_GENRE_ROCK "rock.jamulus.io:22424"
-#define CENTSERV_GENRE_JAZZ "jazz.jamulus.io:22324"
-#define CENTSERV_GENRE_CLASSICAL_FOLK "classical.jamulus.io:22524"
-#define CENTSERV_GENRE_CHORAL "choral.jamulus.io:22724"
-
-// specify an invalid port to disable the server
-#define INVALID_PORT -1
-
-// servers to check for new versions
-#define UPDATECHECK1_ADDRESS "updatecheck1.jamulus.io"
-#define UPDATECHECK2_ADDRESS "updatecheck2.jamulus.io"
-
-// getting started and software manual URL
-#define CLIENT_GETTING_STARTED_URL "https://jamulus.io/wiki/Getting-Started"
-#define SERVER_GETTING_STARTED_URL "https://jamulus.io/wiki/Running-a-Server"
-#define SOFTWARE_MANUAL_URL "https://jamulus.io/wiki/Software-Manual"
-
-// app update message
-#define APP_UPGRADE_AVAILABLE_MSG_TEXT \
- QCoreApplication::translate ( \
- "global", \
- "A %1 upgrade is available: go to details and downloads" )
-
-// determining server internal address uses well-known host and port
-// We just need a valid, public Internet IP here. We will not send any
-// traffic there as we will only set up an UDP socket without sending any
-// data.
-#define WELL_KNOWN_HOST "1.1.1.1" // CloudFlare
-#define WELL_KNOWN_HOST6 "2606:4700:4700::1111" // CloudFlare
-#define WELL_KNOWN_PORT DEFAULT_PORT_NUMBER
-#define IP_LOOKUP_TIMEOUT 500 // ms
-
-// system sample rate (the sound card and audio coder works on this sample rate)
-#define SYSTEM_SAMPLE_RATE_HZ 48000 // Hz
-
-// define the allowed audio frame size factors (since the
-// "SYSTEM_FRAME_SIZE_SAMPLES" is quite small, it may be that on some
-// computers a larger value is required)
-#define FRAME_SIZE_FACTOR_PREFERRED 1 // 64 samples accumulated frame size
-#define FRAME_SIZE_FACTOR_DEFAULT 2 // 128 samples accumulated frame size
-#define FRAME_SIZE_FACTOR_SAFE 4 // 256 samples accumulated frame size
-
-// define the minimum allowed number of coded bytes for CELT (the encoder
-// gets in trouble if the value is too low)
-#define CELT_MINIMUM_NUM_BYTES 10
-
-// Maximum block size for network input buffer. It is defined by the longest
-// protocol message which is PROTMESSID_CLM_SERVER_LIST: Worst case:
-// (2+2+1+2+2)+200*(4+2+2+1+1+2+20+2+32+2+20)=17609
-// We add some headroom to that value.
-#define MAX_SIZE_BYTES_NETW_BUF 20000
-
-// minimum/maximum network buffer size (which can be chosen by slider)
-#define MIN_NET_BUF_SIZE_NUM_BL 1 // number of blocks
-#define MAX_NET_BUF_SIZE_NUM_BL 20 // number of blocks
-#define AUTO_NET_BUF_SIZE_FOR_PROTOCOL ( MAX_NET_BUF_SIZE_NUM_BL + 1 ) // auto set parameter (only used for protocol)
-
-// default network buffer size
-#define DEF_NET_BUF_SIZE_NUM_BL 10 // number of blocks
-
-// audio mixer fader and panning maximum value
-#define AUD_MIX_FADER_MAX 100
-#define AUD_MIX_PAN_MAX 100
-
-// range of audio mixer fader
-#define AUD_MIX_FADER_RANGE_DB 35.0f
-
-// coefficient for averaging channel levels for automatic fader adjustment
-#define AUTO_FADER_ADJUST_ALPHA 0.2f
-
-// target level for auto fader adjustment in decibels
-#define AUTO_FADER_TARGET_LEVEL_DB -30.0f
-
-// threshold in decibels below which the channel is considered as noise
-// and not adjusted
-#define AUTO_FADER_NOISE_THRESHOLD_DB -40.0f
-
-// maximum number of fader groups (must be consistent to audiomixerboard implementation)
-#define MAX_NUM_FADER_GROUPS 8
-
-// maximum number of recognized sound cards installed in the system
-#define MAX_NUMBER_SOUND_CARDS 129 // e.g. 16 inputs, 8 outputs + default entry (MacOS)
-
-// define the maximum number of audio channel for input/output we can store
-// channel infos for (and therefore this is the maximum number of entries in
-// the channel selection combo box regardless of the actual available number
-// of channels by the audio device)
-#define MAX_NUM_IN_OUT_CHANNELS 64
-
-// maximum number of elemts in the server address combo box
-#define MAX_NUM_SERVER_ADDR_ITEMS 12
-
-// maximum number of fader settings to be stored (together with the fader tags)
-#define MAX_NUM_STORED_FADER_SETTINGS 250
-
-// range for signal level meter
-#define LOW_BOUND_SIG_METER ( -50.0 ) // dB
-#define UPPER_BOUND_SIG_METER ( 0.0 ) // dB
-
-// defines for LED level meter CLevelMeter
-#define NUM_STEPS_LED_BAR 8
-#define RED_BOUND_LED_BAR 7
-#define YELLOW_BOUND_LED_BAR 5
-
-// maximum number of connected clients at the server (must not be larger than 256)
-#define MAX_NUM_CHANNELS 150 // max number channels for server
-
-// actual number of used channels in the server
-// this parameter can safely be changed from 1 to MAX_NUM_CHANNELS
-// without any other changes in the code
-#define DEFAULT_USED_NUM_CHANNELS 10 // default used number channels for server
-
-// Maximum number of servers registered in the server list. If you want to
-// change this parameter, you most probably have to adjust MAX_SIZE_BYTES_NETW_BUF.
-#define MAX_NUM_SERVERS_IN_SERVER_LIST 150 // reduced to 150 because we now have genre-based server lists
-
-// defines the time interval at which the ping time is updated in the GUI
-#define PING_UPDATE_TIME_MS 500 // ms
-
-// defines the time interval at which the ping time is updated for the server list
-#define PING_UPDATE_TIME_SERVER_LIST_MS 2500 // ms
-
-// defines the interval between Channel Level updates from the server
-#define CHANNEL_LEVEL_UPDATE_INTERVAL 200 // number of frames at 64 samples frame size
-
-// time-out until a registered server is deleted from the server list if no
-// new registering was made in minutes
-#define SERVLIST_TIME_OUT_MINUTES 33 // minutes (should include 3 UDP registration messages)
-
-// poll time for server list (to check if entries are time-out)
-#define SERVLIST_POLL_TIME_MINUTES 1 // minute
-
-// time interval for sending ping messages to servers in the server list
-#define SERVLIST_UPDATE_PING_SERVERS_MS 59000 // ms
-
-// time between server registration refreshes
-#define SERVLIST_REGIST_INTERV_MINUTES 15 // minutes
-
-// defines the minimum time a server must run to be a permanent server
-#define SERVLIST_TIME_PERMSERV_MINUTES 2880 // minutes, 2880 = 60 min * 24 h * 2 d
-
-// registration response timeout
-#define REGISTER_SERVER_TIME_OUT_MS 500 // ms
-
-// defines the maximum number of times to retry server registration
-// when no response is received within the timeout (before reverting
-// to SERVLIST_REGIST_INTERV_MINUTES)
-#define REGISTER_SERVER_RETRY_LIMIT 5 // count
-
-// Maximum length of fader tag and text message strings (Since for chat messages
-// some HTML code is added, we also have to define a second length which includes
-// this additionl HTML code. Right now the length of the HTML code is approx. 66
-// characters. Here, we add some headroom to this number)
-#define MAX_LEN_FADER_TAG 16
-#define MAX_LEN_CHAT_TEXT 1600
-#define MAX_LEN_CHAT_TEXT_PLUS_HTML 1800
-#define MAX_LEN_SERVER_NAME 20
-#define MAX_LEN_IP_ADDRESS 15
-#define MAX_LEN_SERVER_CITY 20
-#define MAX_LEN_VERSION_TEXT 30
-
-// define Settings tab indexes
-#define SETTING_TAB_USER 0
-#define SETTING_TAB_AUDIONET 1
-#define SETTING_TAB_ADVANCED 2
-
-// common tool tip bottom line text
-#define TOOLTIP_COM_END_TEXT \
- "
" + \
- QCoreApplication::translate ( "global", \
- "For more information use the \"What's " \
- "This\" help (help menu, right mouse button or Shift+F1)" ) + \
- "
"
-
-// server welcome message title (do not change for compatibility!)
-#define WELCOME_MESSAGE_PREFIX "Server Welcome Message: "
-
-// mixer settings file name suffix
-#define MIX_SETTINGS_FILE_SUFFIX "jch"
-
-// minimum length of JSON-RPC secret string (main.cpp)
-#define JSON_RPC_MINIMUM_SECRET_LENGTH 16
-
-// JSON-RPC listen address (Default)
-#define DEFAULT_JSON_RPC_LISTEN_ADDRESS "127.0.0.1"
-
-#define _MAXSHORT 32767
-#define _MINSHORT ( -32768 )
-#define INVALID_INDEX -1 // define invalid index as a negative value (a valid index must always be >= 0)
-
-#if HAVE_STDINT_H
-# include
-#elif HAVE_INTTYPES_H
-# include
-#elif defined( _WIN32 )
-typedef __int64 int64_t;
-typedef __int32 int32_t;
-typedef __int16 int16_t;
-typedef unsigned __int64 uint64_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int8 uint8_t;
-#elif defined( ANDROID )
-// don't redfine types for android as these ones below don't work
-#else
-typedef long long int64_t;
-typedef int int32_t;
-typedef short int16_t;
-typedef unsigned long long uint64_t;
-typedef unsigned int uint32_t;
-typedef unsigned short uint16_t;
-typedef unsigned char uint8_t;
-#endif
-
-/* Pseudo enum definitions -------------------------------------------------- */
-// definition for custom event
-#define MS_PACKET_RECEIVED 0
-
-/* Classes ********************************************************************/
-class CGenErr
-{
-public:
- CGenErr ( QString strNewErrorMsg, QString strNewErrorType = "" ) : strErrorMsg ( strNewErrorMsg ), strErrorType ( strNewErrorType ) {}
-
- QString GetErrorText() const
- {
- // return formatted error text
- if ( strErrorType.isEmpty() )
- {
- return strErrorMsg;
- }
- else
- {
- return strErrorType + ": " + strErrorMsg;
- }
- }
-
-protected:
- QString strErrorMsg;
- QString strErrorType;
-};
-
-class CCustomEvent : public QEvent
-{
-public:
- CCustomEvent ( int iNewMeTy, int iNewSt, int iNewChN = 0 ) :
- QEvent ( QEvent::Type ( QEvent::User + 11 ) ),
- iMessType ( iNewMeTy ),
- iStatus ( iNewSt ),
- iChanNum ( iNewChN )
- {}
-
- int iMessType;
- int iStatus;
- int iChanNum;
-};
-
-/* Prototypes for global functions ********************************************/
-// command line parsing, TODO do not declare functions globally but in a class
-QString UsageArguments ( char** argv );
-
-bool GetFlagArgument ( char** argv, int& i, QString strShortOpt, QString strLongOpt );
-
-bool GetStringArgument ( int argc, char** argv, int& i, QString strShortOpt, QString strLongOpt, QString& strArg );
-
-bool GetNumericArgument ( int argc,
- char** argv,
- int& i,
- QString strShortOpt,
- QString strLongOpt,
- double rRangeStart,
- double rRangeStop,
- double& rValue );
+/******************************************************************************\
+ * \Copyright (c) 2004-2024
+ * \author Volker Fischer
+ *
+
+\mainpage Jamulus source code documentation
+
+\section intro_sec Introduction
+
+The Jamulus software enables musicians to perform real-time jam sessions over the
+internet. There is one server running the Jamulus server software which collects
+the audio data from each Jamulus client, mixes the audio data and sends the mix
+back to each client.
+
+
+Prefix definitions for the GUI:
+
+label: lbl
+combo box: cbx
+line edit: edt
+list view: lvw
+check box: chb
+radio button: rbt
+button: but
+text view: txv
+slider: sld
+LED: led
+group box: grb
+pixmap label: pxl
+LED bar: lbr
+
+ ******************************************************************************
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * 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, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+\******************************************************************************/
+
+#pragma once
+
+#if _WIN32
+# define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#ifndef _WIN32
+# include // solves a compile problem on recent Ubuntu
+#endif
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+/* Definitions ****************************************************************/
+// define this macro to get debug output
+//#define _DEBUG_
+#undef _DEBUG_
+
+// version and application name (use version from qt prject file)
+#undef VERSION
+#define VERSION APP_VERSION
+#define APP_NAME "Jamulus"
+
+// Windows registry key name of auto run entry for the server
+#define AUTORUN_SERVER_REG_NAME "Jamulus server"
+
+// default names of the ini-file for client and server
+#define DEFAULT_INI_FILE_NAME "Jamulus.ini"
+#define DEFAULT_INI_FILE_NAME_SERVER "Jamulusserver.ini"
+
+// file name for logging file
+#define DEFAULT_LOG_FILE_NAME "Jamulussrvlog.txt"
+
+// System block size, this is the block size on which the audio coder works.
+// All other block sizes must be a multiple of this size.
+// Note that the UpdateAutoSetting() function assumes a value of 128.
+#define SYSTEM_FRAME_SIZE_SAMPLES 64
+#define DOUBLE_SYSTEM_FRAME_SIZE_SAMPLES ( 2 * SYSTEM_FRAME_SIZE_SAMPLES )
+
+// additional buffer for delay panning
+#define MAX_DELAY_PANNING_SAMPLES 64
+
+// default server address and port numbers
+#define DEFAULT_QOS_NUMBER 128 // CS4 (Quality of Service)
+#define DEFAULT_SERVER_ADDRESS "anygenre1.jamulus.io"
+#define DEFAULT_PORT_NUMBER 22124
+#define CENTSERV_ANY_GENRE2 "anygenre2.jamulus.io:22224"
+#define CENTSERV_ANY_GENRE3 "anygenre3.jamulus.io:22624"
+#define CENTSERV_GENRE_ROCK "rock.jamulus.io:22424"
+#define CENTSERV_GENRE_JAZZ "jazz.jamulus.io:22324"
+#define CENTSERV_GENRE_CLASSICAL_FOLK "classical.jamulus.io:22524"
+#define CENTSERV_GENRE_CHORAL "choral.jamulus.io:22724"
+
+// specify an invalid port to disable the server
+#define INVALID_PORT -1
+
+// servers to check for new versions
+#define UPDATECHECK1_ADDRESS "updatecheck1.jamulus.io"
+#define UPDATECHECK2_ADDRESS "updatecheck2.jamulus.io"
+
+// getting started and software manual URL
+#define CLIENT_GETTING_STARTED_URL "https://jamulus.io/wiki/Getting-Started"
+#define SERVER_GETTING_STARTED_URL "https://jamulus.io/wiki/Running-a-Server"
+#define SOFTWARE_MANUAL_URL "https://jamulus.io/wiki/Software-Manual"
+
+// app update message
+#define APP_UPGRADE_AVAILABLE_MSG_TEXT \
+ QCoreApplication::translate ( \
+ "global", \
+ "A %1 upgrade is available: go to details and downloads" )
+
+// determining server internal address uses well-known host and port
+// We just need a valid, public Internet IP here. We will not send any
+// traffic there as we will only set up an UDP socket without sending any
+// data.
+#define WELL_KNOWN_HOST "1.1.1.1" // CloudFlare
+#define WELL_KNOWN_HOST6 "2606:4700:4700::1111" // CloudFlare
+#define WELL_KNOWN_PORT DEFAULT_PORT_NUMBER
+#define IP_LOOKUP_TIMEOUT 500 // ms
+
+// system sample rate (the sound card and audio coder works on this sample rate)
+#define SYSTEM_SAMPLE_RATE_HZ 48000 // Hz
+
+// define the allowed audio frame size factors (since the
+// "SYSTEM_FRAME_SIZE_SAMPLES" is quite small, it may be that on some
+// computers a larger value is required)
+#define FRAME_SIZE_FACTOR_PREFERRED 1 // 64 samples accumulated frame size
+#define FRAME_SIZE_FACTOR_DEFAULT 2 // 128 samples accumulated frame size
+#define FRAME_SIZE_FACTOR_SAFE 4 // 256 samples accumulated frame size
+
+// define the minimum allowed number of coded bytes for CELT (the encoder
+// gets in trouble if the value is too low)
+#define CELT_MINIMUM_NUM_BYTES 10
+
+// Maximum block size for network input buffer. It is defined by the longest
+// protocol message which is PROTMESSID_CLM_SERVER_LIST: Worst case:
+// (2+2+1+2+2)+200*(4+2+2+1+1+2+20+2+32+2+20)=17609
+// We add some headroom to that value.
+#define MAX_SIZE_BYTES_NETW_BUF 20000
+
+// minimum/maximum network buffer size (which can be chosen by slider)
+#define MIN_NET_BUF_SIZE_NUM_BL 1 // number of blocks
+#define MAX_NET_BUF_SIZE_NUM_BL 20 // number of blocks
+#define AUTO_NET_BUF_SIZE_FOR_PROTOCOL ( MAX_NET_BUF_SIZE_NUM_BL + 1 ) // auto set parameter (only used for protocol)
+
+// default network buffer size
+#define DEF_NET_BUF_SIZE_NUM_BL 10 // number of blocks
+
+// audio mixer fader and panning maximum value
+#define AUD_MIX_FADER_MAX 100
+#define AUD_MIX_PAN_MAX 100
+
+// range of audio mixer fader
+#define AUD_MIX_FADER_RANGE_DB 35.0f
+
+// coefficient for averaging channel levels for automatic fader adjustment
+#define AUTO_FADER_ADJUST_ALPHA 0.2f
+
+// target level for auto fader adjustment in decibels
+#define AUTO_FADER_TARGET_LEVEL_DB -30.0f
+
+// threshold in decibels below which the channel is considered as noise
+// and not adjusted
+#define AUTO_FADER_NOISE_THRESHOLD_DB -40.0f
+
+// maximum number of fader groups (must be consistent to audiomixerboard implementation)
+#define MAX_NUM_FADER_GROUPS 8
+
+// maximum number of recognized sound cards installed in the system
+#define MAX_NUMBER_SOUND_CARDS 129 // e.g. 16 inputs, 8 outputs + default entry (MacOS)
+
+// define the maximum number of audio channel for input/output we can store
+// channel infos for (and therefore this is the maximum number of entries in
+// the channel selection combo box regardless of the actual available number
+// of channels by the audio device)
+#define MAX_NUM_IN_OUT_CHANNELS 64
+
+// maximum number of elemts in the server address combo box
+#define MAX_NUM_SERVER_ADDR_ITEMS 12
+
+// maximum number of fader settings to be stored (together with the fader tags)
+#define MAX_NUM_STORED_FADER_SETTINGS 250
+
+// range for signal level meter
+#define LOW_BOUND_SIG_METER ( -50.0 ) // dB
+#define UPPER_BOUND_SIG_METER ( 0.0 ) // dB
+
+// defines for LED level meter CLevelMeter
+#define NUM_STEPS_LED_BAR 8
+#define RED_BOUND_LED_BAR 7
+#define YELLOW_BOUND_LED_BAR 5
+
+// maximum number of connected clients at the server (must not be larger than 256)
+#define MAX_NUM_CHANNELS 150 // max number channels for server
+
+// actual number of used channels in the server
+// this parameter can safely be changed from 1 to MAX_NUM_CHANNELS
+// without any other changes in the code
+#define DEFAULT_USED_NUM_CHANNELS 10 // default used number channels for server
+
+// Maximum number of servers registered in the server list. If you want to
+// change this parameter, you most probably have to adjust MAX_SIZE_BYTES_NETW_BUF.
+#define MAX_NUM_SERVERS_IN_SERVER_LIST 150 // reduced to 150 because we now have genre-based server lists
+
+// defines the time interval at which the ping time is updated in the GUI
+#define PING_UPDATE_TIME_MS 500 // ms
+
+// defines the time interval at which the ping time is updated for the server list
+#define PING_UPDATE_TIME_SERVER_LIST_MS 2500 // ms
+
+// defines the interval between Channel Level updates from the server
+#define CHANNEL_LEVEL_UPDATE_INTERVAL 200 // number of frames at 64 samples frame size
+
+// time-out until a registered server is deleted from the server list if no
+// new registering was made in minutes
+#define SERVLIST_TIME_OUT_MINUTES 33 // minutes (should include 3 UDP registration messages)
+
+// poll time for server list (to check if entries are time-out)
+#define SERVLIST_POLL_TIME_MINUTES 1 // minute
+
+// time interval for sending ping messages to servers in the server list
+#define SERVLIST_UPDATE_PING_SERVERS_MS 59000 // ms
+
+// time between server registration refreshes
+#define SERVLIST_REGIST_INTERV_MINUTES 15 // minutes
+
+// defines the minimum time a server must run to be a permanent server
+#define SERVLIST_TIME_PERMSERV_MINUTES 2880 // minutes, 2880 = 60 min * 24 h * 2 d
+
+// registration response timeout
+#define REGISTER_SERVER_TIME_OUT_MS 500 // ms
+
+// defines the maximum number of times to retry server registration
+// when no response is received within the timeout (before reverting
+// to SERVLIST_REGIST_INTERV_MINUTES)
+#define REGISTER_SERVER_RETRY_LIMIT 5 // count
+
+// Maximum length of fader tag and text message strings (Since for chat messages
+// some HTML code is added, we also have to define a second length which includes
+// this additionl HTML code. Right now the length of the HTML code is approx. 66
+// characters. Here, we add some headroom to this number)
+#define MAX_LEN_FADER_TAG 16
+#define MAX_LEN_CHAT_TEXT 1600
+#define MAX_LEN_CHAT_TEXT_PLUS_HTML 1800
+#define MAX_LEN_SERVER_NAME 20
+#define MAX_LEN_IP_ADDRESS 15
+#define MAX_LEN_SERVER_CITY 20
+#define MAX_LEN_VERSION_TEXT 30
+
+// define Settings tab indexes
+#define SETTING_TAB_USER 0
+#define SETTING_TAB_AUDIONET 1
+#define SETTING_TAB_ADVANCED 2
+
+// common tool tip bottom line text
+#define TOOLTIP_COM_END_TEXT \
+ "
" + \
+ QCoreApplication::translate ( "global", \
+ "For more information use the \"What's " \
+ "This\" help (help menu, right mouse button or Shift+F1)" ) + \
+ "
"
+
+// server welcome message title (do not change for compatibility!)
+#define WELCOME_MESSAGE_PREFIX "Server Welcome Message: "
+
+// mixer settings file name suffix
+#define MIX_SETTINGS_FILE_SUFFIX "jch"
+
+// minimum length of JSON-RPC secret string (main.cpp)
+#define JSON_RPC_MINIMUM_SECRET_LENGTH 16
+
+// JSON-RPC listen address (Default)
+#define DEFAULT_JSON_RPC_LISTEN_ADDRESS "127.0.0.1"
+
+#define _MAXSHORT 32767
+#define _MINSHORT ( -32768 )
+#define INVALID_INDEX -1 // define invalid index as a negative value (a valid index must always be >= 0)
+
+#if HAVE_STDINT_H
+# include
+#elif HAVE_INTTYPES_H
+# include
+#elif defined( _WIN32 )
+typedef __int64 int64_t;
+typedef __int32 int32_t;
+typedef __int16 int16_t;
+typedef unsigned __int64 uint64_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int8 uint8_t;
+#elif defined( ANDROID )
+// don't redfine types for android as these ones below don't work
+#else
+typedef long long int64_t;
+typedef int int32_t;
+typedef short int16_t;
+typedef unsigned long long uint64_t;
+typedef unsigned int uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+#endif
+
+/* Pseudo enum definitions -------------------------------------------------- */
+// definition for custom event
+#define MS_PACKET_RECEIVED 0
+
+/* Classes ********************************************************************/
+class CGenErr
+{
+public:
+ CGenErr ( QString strNewErrorMsg, QString strNewErrorType = "" ) : strErrorMsg ( strNewErrorMsg ), strErrorType ( strNewErrorType ) {}
+
+ QString GetErrorText() const
+ {
+ // return formatted error text
+ if ( strErrorType.isEmpty() )
+ {
+ return strErrorMsg;
+ }
+ else
+ {
+ return strErrorType + ": " + strErrorMsg;
+ }
+ }
+
+protected:
+ QString strErrorMsg;
+ QString strErrorType;
+};
+
+class CCustomEvent : public QEvent
+{
+public:
+ CCustomEvent ( int iNewMeTy, int iNewSt, int iNewChN = 0 ) :
+ QEvent ( QEvent::Type ( QEvent::User + 11 ) ),
+ iMessType ( iNewMeTy ),
+ iStatus ( iNewSt ),
+ iChanNum ( iNewChN )
+ {}
+
+ int iMessType;
+ int iStatus;
+ int iChanNum;
+};
+
+/* Prototypes for global functions ********************************************/
+// command line parsing, TODO do not declare functions globally but in a class
+QString UsageArguments ( char** argv );
+
+bool GetFlagArgument ( char** argv, int& i, QString strShortOpt, QString strLongOpt );
+
+bool GetStringArgument ( int argc, char** argv, int& i, QString strShortOpt, QString strLongOpt, QString& strArg );
+
+bool GetNumericArgument ( int argc,
+ char** argv,
+ int& i,
+ QString strShortOpt,
+ QString strLongOpt,
+ double rRangeStart,
+ double rRangeStop,
+ double& rValue );
diff --git a/src/levelmeter.cpp b/src/levelmeter.cpp
index 11adc17921..b5c47bcbf1 100644
--- a/src/levelmeter.cpp
+++ b/src/levelmeter.cpp
@@ -28,53 +28,11 @@
#include "levelmeter.h"
/* Implementation *************************************************************/
-CLevelMeter::CLevelMeter ( QWidget* parent ) : QWidget ( parent ), eLevelMeterType ( MT_BAR_WIDE )
+CLevelMeter::CLevelMeter ( QObject* parent )
+ : QObject(parent),
+ m_doubleVal(0.0)
{
- // initialize LED meter
- QWidget* pLEDMeter = new QWidget();
- QVBoxLayout* pLEDLayout = new QVBoxLayout ( pLEDMeter );
- pLEDLayout->setAlignment ( Qt::AlignHCenter );
- pLEDLayout->setContentsMargins ( 0, 0, 0, 0 );
- pLEDLayout->setSpacing ( 0 );
-
- // create LEDs plus the clip LED
- vecpLEDs.Init ( NUM_LEDS_INCL_CLIP_LED );
-
- for ( int iLEDIdx = NUM_LEDS_INCL_CLIP_LED - 1; iLEDIdx >= 0; iLEDIdx-- )
- {
- // create LED object
- vecpLEDs[iLEDIdx] = new cLED ( parent );
-
- // add LED to layout with spacer (do not add spacer on the bottom of the first LED)
- if ( iLEDIdx < NUM_LEDS_INCL_CLIP_LED - 1 )
- {
- pLEDLayout->addStretch();
- }
-
- pLEDLayout->addWidget ( vecpLEDs[iLEDIdx]->GetLabelPointer() );
- }
-
- // initialize bar meter
- pBarMeter = new QProgressBar();
- pBarMeter->setOrientation ( Qt::Vertical );
- pBarMeter->setRange ( 0, 100 * NUM_STEPS_LED_BAR ); // use factor 100 to reduce quantization (bar is continuous)
- pBarMeter->setFormat ( "" ); // suppress percent numbers
-
- // setup stacked layout for meter type switching mechanism
- pMinStackedLayout = new CMinimumStackedLayout ( this );
- pMinStackedLayout->addWidget ( pLEDMeter );
- pMinStackedLayout->addWidget ( pBarMeter );
-
- // according to QScrollArea description: "When using a scroll area to display the
- // contents of a custom widget, it is important to ensure that the size hint of
- // the child widget is set to a suitable value."
- pBarMeter->setMinimumSize ( QSize ( 1, 1 ) );
- pLEDMeter->setMinimumSize ( QSize ( 1, 1 ) );
-
- // update the meter type (using the default value of the meter type)
- SetLevelMeterType ( eLevelMeterType );
-
- // setup clip indicator timer
+ // setup clip indicator timer
TimerClip.setSingleShot ( true );
TimerClip.setInterval ( CLIP_IND_TIME_OUT_MS );
@@ -84,243 +42,38 @@ CLevelMeter::CLevelMeter ( QWidget* parent ) : QWidget ( parent ), eLevelMeterTy
CLevelMeter::~CLevelMeter()
{
- // clean up the LED objects
- for ( int iLEDIdx = 0; iLEDIdx < NUM_LEDS_INCL_CLIP_LED; iLEDIdx++ )
- {
- delete vecpLEDs[iLEDIdx];
- }
+ // nothing for now
+ ;
}
-void CLevelMeter::SetLevelMeterType ( const ELevelMeterType eNType )
+bool CLevelMeter::clipStatus()
{
- eLevelMeterType = eNType;
-
- switch ( eNType )
- {
- case MT_LED_STRIPE:
- // initialize all LEDs
- for ( int iLEDIdx = 0; iLEDIdx < NUM_LEDS_INCL_CLIP_LED; iLEDIdx++ )
- {
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_BLACK );
- }
- pMinStackedLayout->setCurrentIndex ( 0 );
- break;
-
- case MT_LED_ROUND_BIG:
- // initialize all LEDs
- for ( int iLEDIdx = 0; iLEDIdx < NUM_LEDS_INCL_CLIP_LED; iLEDIdx++ )
- {
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_ROUND_BIG_BLACK );
- }
- pMinStackedLayout->setCurrentIndex ( 0 );
- break;
-
- case MT_LED_ROUND_SMALL:
- // initialize all LEDs
- for ( int iLEDIdx = 0; iLEDIdx < NUM_LEDS_INCL_CLIP_LED; iLEDIdx++ )
- {
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_ROUND_SMALL_BLACK );
- }
- pMinStackedLayout->setCurrentIndex ( 0 );
- break;
-
- case MT_BAR_WIDE:
- case MT_BAR_NARROW:
- pMinStackedLayout->setCurrentIndex ( 1 );
- break;
- }
-
- // update bar meter style and reset clip state
- SetBarMeterStyleAndClipStatus ( eNType, false );
+ return m_clipStatus;
}
-void CLevelMeter::SetBarMeterStyleAndClipStatus ( const ELevelMeterType eNType, const bool bIsClip )
+void CLevelMeter::setClipStatus( const bool bIsClip )
{
- switch ( eNType )
- {
- case MT_BAR_NARROW:
- if ( bIsClip )
- {
- pBarMeter->setStyleSheet ( "QProgressBar { border: 0px solid red;"
- " margin: 0px;"
- " padding: 0px;"
- " width: 4px;"
- " background: red; }"
- "QProgressBar::chunk { background: green; }" );
- }
- else
- {
- pBarMeter->setStyleSheet ( "QProgressBar { border: 0px;"
- " margin: 0px;"
- " padding: 0px;"
- " width: 4px; }"
- "QProgressBar::chunk { background: green; }" );
- }
- break;
+ m_clipStatus = bIsClip;
- default: /* MT_BAR_WIDE */
- if ( bIsClip )
- {
- pBarMeter->setStyleSheet ( "QProgressBar { border: 2px solid red;"
- " margin: 1px;"
- " padding: 1px;"
- " width: 15px;"
- " background: transparent; }"
- "QProgressBar::chunk { background: green; }" );
- }
- else
- {
- pBarMeter->setStyleSheet ( "QProgressBar { margin: 1px;"
- " padding: 1px;"
- " width: 15px; }"
- "QProgressBar::chunk { background: green; }" );
- }
- break;
- }
+ emit clipStatusChanged();
}
-void CLevelMeter::SetValue ( const double dValue )
+void CLevelMeter::setDoubleVal ( const double value )
{
- switch ( eLevelMeterType )
- {
- case MT_LED_STRIPE:
- // update state of all LEDs for current level value (except of the clip LED)
- for ( int iLEDIdx = 0; iLEDIdx < NUM_STEPS_LED_BAR; iLEDIdx++ )
- {
- // set active LED color if value is above current LED index
- if ( iLEDIdx < dValue )
- {
- // check which color we should use (green, yellow or red)
- if ( iLEDIdx < YELLOW_BOUND_LED_BAR )
- {
- // green region
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_GREEN );
- }
- else
- {
- if ( iLEDIdx < RED_BOUND_LED_BAR )
- {
- // yellow region
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_YELLOW );
- }
- else
- {
- // red region
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_RED );
- }
- }
- }
- else
- {
- // we use black LED for inactive state
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_BLACK );
- }
- }
- break;
-
- case MT_LED_ROUND_BIG:
- // update state of all LEDs for current level value (except of the clip LED)
- for ( int iLEDIdx = 0; iLEDIdx < NUM_STEPS_LED_BAR; iLEDIdx++ )
- {
- // set active LED color if value is above current LED index
- if ( iLEDIdx < dValue )
- {
- // check which color we should use (green, yellow or red)
- if ( iLEDIdx < YELLOW_BOUND_LED_BAR )
- {
- // green region
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_ROUND_BIG_GREEN );
- }
- else
- {
- if ( iLEDIdx < RED_BOUND_LED_BAR )
- {
- // yellow region
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_ROUND_BIG_YELLOW );
- }
- else
- {
- // red region
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_ROUND_BIG_RED );
- }
- }
- }
- else
- {
- // we use black LED for inactive state
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_ROUND_BIG_BLACK );
- }
- }
- break;
-
- case MT_LED_ROUND_SMALL:
- // update state of all LEDs for current level value (except of the clip LED)
- for ( int iLEDIdx = 0; iLEDIdx < NUM_STEPS_LED_BAR; iLEDIdx++ )
- {
- // set active LED color if value is above current LED index
- if ( iLEDIdx < dValue )
- {
- // check which color we should use (green, yellow or red)
- if ( iLEDIdx < YELLOW_BOUND_LED_BAR )
- {
- // green region
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_ROUND_SMALL_GREEN );
- }
- else
- {
- if ( iLEDIdx < RED_BOUND_LED_BAR )
- {
- // yellow region
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_ROUND_SMALL_YELLOW );
- }
- else
- {
- // red region
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_ROUND_SMALL_RED );
- }
- }
- }
- else
- {
- // we use black LED for inactive state
- vecpLEDs[iLEDIdx]->SetColor ( cLED::RL_ROUND_SMALL_BLACK );
- }
- }
- break;
-
- case MT_BAR_WIDE:
- case MT_BAR_NARROW:
- pBarMeter->setValue ( 100 * dValue );
- break;
- }
+ m_doubleVal = value / NUM_STEPS_LED_BAR;
+ emit doubleValChanged();
+ // qDebug() << "Level doubleVal: " << m_doubleVal;
// clip indicator management (note that in case of clipping, i.e. full
// scale level, the value is above NUM_STEPS_LED_BAR since the minimum
// value of int16 is -32768 but we normalize with 32767 -> therefore
// we really only show the clipping indicator, if actually the largest
// value of int16 is used)
- if ( dValue > NUM_STEPS_LED_BAR )
+ if ( value > NUM_STEPS_LED_BAR )
{
- switch ( eLevelMeterType )
- {
- case MT_LED_STRIPE:
- vecpLEDs[NUM_STEPS_LED_BAR]->SetColor ( cLED::RL_RED );
- break;
-
- case MT_LED_ROUND_BIG:
- vecpLEDs[NUM_STEPS_LED_BAR]->SetColor ( cLED::RL_ROUND_BIG_RED );
- break;
-
- case MT_LED_ROUND_SMALL:
- vecpLEDs[NUM_STEPS_LED_BAR]->SetColor ( cLED::RL_ROUND_SMALL_RED );
- break;
-
- case MT_BAR_WIDE:
- case MT_BAR_NARROW:
- SetBarMeterStyleAndClipStatus ( eLevelMeterType, true );
- break;
- }
-
+ qDebug() << "Level value: " << value;
+ setClipStatus(true);
+ emit clipStatusChanged();
TimerClip.start();
}
}
@@ -330,110 +83,6 @@ void CLevelMeter::ClipReset()
// we manually want to reset the clipping indicator: stop timer and reset
// clipping indicator GUI element
TimerClip.stop();
-
- switch ( eLevelMeterType )
- {
- case MT_LED_STRIPE:
- vecpLEDs[NUM_STEPS_LED_BAR]->SetColor ( cLED::RL_BLACK );
- break;
-
- case MT_LED_ROUND_BIG:
- vecpLEDs[NUM_STEPS_LED_BAR]->SetColor ( cLED::RL_ROUND_BIG_BLACK );
- break;
-
- case MT_LED_ROUND_SMALL:
- vecpLEDs[NUM_STEPS_LED_BAR]->SetColor ( cLED::RL_ROUND_SMALL_BLACK );
- break;
-
- case MT_BAR_WIDE:
- case MT_BAR_NARROW:
- SetBarMeterStyleAndClipStatus ( eLevelMeterType, false );
- break;
- }
-}
-
-CLevelMeter::cLED::cLED ( QWidget* parent ) :
- BitmCubeLedBlack ( QString::fromUtf8 ( ":/png/LEDs/res/HLEDBlack.png" ) ),
- BitmCubeLedGreen ( QString::fromUtf8 ( ":/png/LEDs/res/HLEDGreen.png" ) ),
- BitmCubeLedYellow ( QString::fromUtf8 ( ":/png/LEDs/res/HLEDYellow.png" ) ),
- BitmCubeLedRed ( QString::fromUtf8 ( ":/png/LEDs/res/HLEDRed.png" ) ),
- BitmCubeRoundSmallLedBlack ( QString::fromUtf8 ( ":/png/LEDs/res/CLEDBlackSmall.png" ) ),
- BitmCubeRoundSmallLedGreen ( QString::fromUtf8 ( ":/png/LEDs/res/CLEDGreenSmall.png" ) ),
- BitmCubeRoundSmallLedYellow ( QString::fromUtf8 ( ":/png/LEDs/res/CLEDYellowSmall.png" ) ),
- BitmCubeRoundSmallLedRed ( QString::fromUtf8 ( ":/png/LEDs/res/CLEDRedSmall.png" ) ),
- BitmCubeRoundBigLedBlack ( QString::fromUtf8 ( ":/png/LEDs/res/CLEDBlackBig.png" ) ),
- BitmCubeRoundBigLedGreen ( QString::fromUtf8 ( ":/png/LEDs/res/CLEDGreenBig.png" ) ),
- BitmCubeRoundBigLedYellow ( QString::fromUtf8 ( ":/png/LEDs/res/CLEDYellowBig.png" ) ),
- BitmCubeRoundBigLedRed ( QString::fromUtf8 ( ":/png/LEDs/res/CLEDRedBig.png" ) )
-{
- // create LED label
- pLEDLabel = new QLabel ( "", parent );
-
- // set initial bitmap
- pLEDLabel->setPixmap ( BitmCubeLedBlack );
- eCurLightColor = RL_BLACK;
-}
-
-void CLevelMeter::cLED::SetColor ( const ELightColor eNewColor )
-{
- // only update LED if color has changed
- if ( eNewColor != eCurLightColor )
- {
- switch ( eNewColor )
- {
- case RL_DISABLED:
- // note that this is required for the compact channel mode
- pLEDLabel->setPixmap ( QPixmap() );
- break;
-
- case RL_BLACK:
- pLEDLabel->setPixmap ( BitmCubeLedBlack );
- break;
-
- case RL_GREEN:
- pLEDLabel->setPixmap ( BitmCubeLedGreen );
- break;
-
- case RL_YELLOW:
- pLEDLabel->setPixmap ( BitmCubeLedYellow );
- break;
-
- case RL_RED:
- pLEDLabel->setPixmap ( BitmCubeLedRed );
- break;
-
- case RL_ROUND_SMALL_BLACK:
- pLEDLabel->setPixmap ( BitmCubeRoundSmallLedBlack );
- break;
-
- case RL_ROUND_SMALL_GREEN:
- pLEDLabel->setPixmap ( BitmCubeRoundSmallLedGreen );
- break;
-
- case RL_ROUND_SMALL_YELLOW:
- pLEDLabel->setPixmap ( BitmCubeRoundSmallLedYellow );
- break;
-
- case RL_ROUND_SMALL_RED:
- pLEDLabel->setPixmap ( BitmCubeRoundSmallLedRed );
- break;
-
- case RL_ROUND_BIG_BLACK:
- pLEDLabel->setPixmap ( BitmCubeRoundBigLedBlack );
- break;
-
- case RL_ROUND_BIG_GREEN:
- pLEDLabel->setPixmap ( BitmCubeRoundBigLedGreen );
- break;
-
- case RL_ROUND_BIG_YELLOW:
- pLEDLabel->setPixmap ( BitmCubeRoundBigLedYellow );
- break;
-
- case RL_ROUND_BIG_RED:
- pLEDLabel->setPixmap ( BitmCubeRoundBigLedRed );
- break;
- }
- eCurLightColor = eNewColor;
- }
+ setClipStatus(false);
+ emit clipStatusChanged();
}
diff --git a/src/levelmeter.h b/src/levelmeter.h
index 819882d475..0627e7ef0d 100644
--- a/src/levelmeter.h
+++ b/src/levelmeter.h
@@ -24,11 +24,7 @@
#pragma once
-#include
-#include