New upstream version 1.4.2+ds0
authorIOhannes m zmölnig (Debian/GNU) <umlaeute@debian.org>
Tue, 7 Dec 2021 09:44:06 +0000 (10:44 +0100)
committerIOhannes m zmölnig (Debian/GNU) <umlaeute@debian.org>
Tue, 7 Dec 2021 09:44:06 +0000 (10:44 +0100)
21 files changed:
CMakeLists.txt
jacktrip.pro
macos/assemble_app.sh
meson.build
src/JackTrip.cpp
src/JackTrip.h
src/JackTripWorker.h
src/Settings.cpp
src/Settings.h
src/UdpHubListener.h
src/gui/messageDialog.cpp
src/gui/messageDialog.h
src/gui/qjacktrip.cpp
src/gui/qjacktrip.h
src/gui/qjacktrip.ui
src/gui/qjacktrip_novs.ui [new file with mode: 0644]
src/gui/textbuf.cpp [new file with mode: 0644]
src/gui/textbuf.h [new file with mode: 0644]
src/jacktrip_globals.h
src/main.cpp
subprojects/rtaudio.wrap

index aaa2511a452d50c35f1d391bc43a22a3f4495eea..fbba160c2b05332be4b1cb11fee7b4d5a109ffe4 100644 (file)
@@ -5,6 +5,7 @@ project(QJackTrip)
 set(nogui FALSE)
 set(rtaudio TRUE)
 set(weakjack TRUE)
+add_compile_definitions(NO_JTVS)
 add_compile_definitions(QT_OPENSOURCE)
 
 if (nogui)
@@ -111,6 +112,7 @@ if (NOT nogui)
     src/gui/qjacktrip.cpp
     src/gui/about.cpp
     src/gui/messageDialog.cpp
+    src/gui/textbuf.cpp
     src/gui/qjacktrip.qrc
   )
 
index 3a86ce3efce8714b0ee29116c424f758b001cb87..d8ef28504860514b69b578b2d9d73638974f3ef9 100644 (file)
@@ -232,7 +232,8 @@ HEADERS += src/JackAudioInterface.h \
 !nogui {
 HEADERS += src/gui/about.h \
            src/gui/messageDialog.h \
-           src/gui/qjacktrip.h
+           src/gui/qjacktrip.h \
+           src/gui/textbuf.h
 }
 
 rtaudio|bundled_rtaudio {
@@ -270,7 +271,8 @@ SOURCES += src/JackAudioInterface.cpp \
 !nogui {
 SOURCES += src/gui/messageDialog.cpp \
            src/gui/qjacktrip.cpp \
-           src/gui/about.cpp
+           src/gui/about.cpp \
+           src/gui/textbuf.cpp
 }
 
 !nogui {
index 1d89e3f6c35d19aa12baa4618f7f2ce81a25a01c..d52a3f80d43eaca33908c59913847cc4b18700c7 100755 (executable)
@@ -13,7 +13,7 @@ BINARY="../builddir/jacktrip"
 
 OPTIND=1
 
-while getopts ":ic:u:p:a:b:" opt; do
+while getopts ":ihc:u:p:a:b:" opt; do
     case $opt in
       i)
         BUILD_INSTALLER=true
@@ -36,6 +36,23 @@ while getopts ":ic:u:p:a:b:" opt; do
       \?)
         echo "Invalid option -$OPTARG ignored."
         ;;
+      h)
+        echo "JackTrip App Bundle assembly script."
+        echo "Copyright (C) 2020-2021 Aaron Wyatt et al."
+        echo "Relased under the GNU GPLv3 License."
+        echo ""
+        echo "Usage: ./assemble-app.sh [options]"
+        echo ""
+        echo "Options:"
+        echo " -b <filename>      The binary file to be placed in the app bundle. (Defaults to ../builddir/jacktrip)"
+        echo " -i                 Build an installer package as well. (Requires Packages to be installed.)"
+        echo " -c <certname>      Name of the developer certificate to use for signing (No signing by default.)"
+        echo " -u <username>      Apple ID username (email address) for installer notarization."
+        echo " -p <password>      App specific password for installer notarization."
+        echo " -a <ascprovider>   ASC provider for notarization. (Only required if you belong to multiple dev teams.)"
+        echo " -h                 Display this help screen and exit."
+        exit 0
+        ;;
       :)
         echo "Option $OPTARG requires an argument."
         exit 1
index 565d37617ce764b0f188ee55ab9545c36c8c8f8b..258661beac9b438c74772db725f1c2e300a5c25e 100644 (file)
@@ -90,13 +90,15 @@ else
        qt5_dep = dependency('qt5', modules: ['Core', 'Gui', 'Network', 'Widgets'], include_type: 'system')
        src += ['src/gui/qjacktrip.cpp',
                'src/gui/about.cpp',
-               'src/gui/messageDialog.cpp']
+               'src/gui/messageDialog.cpp',
+               'src/gui/textbuf.cpp']
        ui_h += ['src/gui/qjacktrip.ui',
                'src/gui/messageDialog.ui',
                'src/gui/about.ui']
        moc_h += ['src/gui/about.h',
                'src/gui/qjacktrip.h',
-               'src/gui/messageDialog.h']
+               'src/gui/messageDialog.h',
+               'src/gui/textbuf.h']
        qres = ['src/gui/qjacktrip.qrc']
 endif
 deps += qt5_dep
index c489e6f2022fb5bf8ed4b091c1a20febd933b852..e3733d51e4858633b4900daf87f2c138ebb8c7bf 100644 (file)
@@ -582,8 +582,7 @@ void JackTrip::completeConnection()
     if (mIOStatTimeout > 0) {
         cout << "STATS" << mIOStatTimeout << endl;
         if (!mIOStatStream.isNull()) {
-            mIOStatLogStream.rdbuf(
-                (reinterpret_cast<std::ostream*>(mIOStatStream.data()))->rdbuf());
+            mIOStatLogStream.rdbuf((mIOStatStream.data()->rdbuf()));
         }
         QTimer* timer = new QTimer(this);
         connect(timer, SIGNAL(timeout()), this, SLOT(onStatTimer()));
index 5d3dde712b684537f00eee04708da5ea85427788..f7fa1f6b65dd04e20c43963a35cf2a4ec92d9fbb 100644 (file)
@@ -271,7 +271,7 @@ class JackTrip : public QObject
     virtual void setNumOutputChannels(int num_chans) { mNumAudioChansOut = num_chans; }
 
     virtual void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; }
-    virtual void setIOStatStream(QSharedPointer<std::ofstream> statStream)
+    virtual void setIOStatStream(QSharedPointer<std::ostream> statStream)
     {
         mIOStatStream = statStream;
     }
@@ -678,7 +678,7 @@ class JackTrip : public QObject
     volatile bool mHasShutdown;
 
     bool mConnectDefaultAudioPorts;  ///< Connect or not default audio ports
-    QSharedPointer<std::ofstream> mIOStatStream;
+    QSharedPointer<std::ostream> mIOStatStream;
     int mIOStatTimeout;
     std::ostream mIOStatLogStream;
     double mSimulatedLossRate;
index bc6665fab5cfa8ab91a4265682e6efd4cded583a..e05dbdc25e9f5b22b886b88a77e238733b390e86 100644 (file)
@@ -113,7 +113,7 @@ class JackTripWorker : public QObject
     void setUseRtUdpPriority(bool use) { mUseRtUdpPriority = use; }
 
     void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; }
-    void setIOStatStream(QSharedPointer<std::ofstream> statStream)
+    void setIOStatStream(QSharedPointer<std::ostream> statStream)
     {
         mIOStatStream = statStream;
     }
@@ -181,7 +181,7 @@ class JackTripWorker : public QObject
     bool mUseRtUdpPriority      = false;
 
     int mIOStatTimeout = 0;
-    QSharedPointer<std::ofstream> mIOStatStream;
+    QSharedPointer<std::ostream> mIOStatStream;
 #ifdef WAIR                   // wair
     int mNumNetRevChans = 0;  ///< Number of Net Channels = net combs
     bool mWAIR          = false;
index 84299b806abffc5627369779540af7c26b8e7716..d8aa4d98027a906290e5e1f4b9ef10a578ca0fcb 100644 (file)
@@ -461,12 +461,15 @@ void Settings::parseInput(int argc, char** argv)
             break;
         case 'G':  // IO Stat log file
             //-------------------------------------------------------
-            mIOStatStream.reset(new std::ofstream(optarg));
-            if (!mIOStatStream->is_open()) {
-                printUsage();
-                std::cerr << "--iostatlog FAILED to open " << optarg << " for writing."
-                          << endl;
-                std::exit(1);
+            {
+                std::ofstream *outStream = new std::ofstream(optarg);
+                if (!outStream->is_open()) {
+                    printUsage();
+                    std::cerr << "--iostatlog FAILED to open " << optarg << " for writing."
+                            << endl;
+                    std::exit(1);
+                }
+                mIOStatStream.reset(outStream);
             }
             break;
         case OPT_BUFSTRATEGY:  // Buf strategy
index 2dd12b3393575f3138f485cfffd2334536942721..569ca2717ddb750970a302b6ca587595ac6bb500 100644 (file)
@@ -125,7 +125,7 @@ class Settings : public QObject
     unsigned int mHubConnectionMode = JackTrip::SERVERTOCLIENT;
     bool mConnectDefaultAudioPorts  = true;  ///< Connect or not jack audio ports
     int mIOStatTimeout              = 0;
-    QSharedPointer<std::ofstream> mIOStatStream;
+    QSharedPointer<std::ostream> mIOStatStream;
     Effects mEffects            = false;  // outgoing limiter OFF by default
     double mSimulatedLossRate   = 0.0;
     double mSimulatedJitterRate = 0.0;
index e0208fa48a5ad9a35abc058ab2c921d84399e611..07554a8ea6bbf7b716d75d30791cc70231a7485a 100644 (file)
@@ -186,7 +186,7 @@ class UdpHubListener : public QObject
 #endif
 
     int mIOStatTimeout;
-    QSharedPointer<std::ofstream> mIOStatStream;
+    QSharedPointer<std::ostream> mIOStatStream;
 
     int mBufferStrategy;
     int mBroadcastQueue;
@@ -240,7 +240,7 @@ class UdpHubListener : public QObject
     }
 
     void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; }
-    void setIOStatStream(QSharedPointer<std::ofstream> statStream)
+    void setIOStatStream(QSharedPointer<std::ostream> statStream)
     {
         mIOStatStream = statStream;
     }
index 35c70a7dbc9facb4b6708b1b33ea42022d26c897..f4f046bd035e2ec0be2999d467172375e47a455b 100644 (file)
 #include "messageDialog.h"
 
 #include "ui_messageDialog.h"
+#include <iostream>
+#include <QScrollBar>
+#include <QMenu>
+#include <QSettings>
 
-MessageDialog::MessageDialog(QWidget* parent)
-    : QDialog(parent), m_ui(new Ui::MessageDialog), m_ioTimer(new QTimer(this))
+MessageDialog::MessageDialog(QWidget* parent, QString windowFunction, quint32 streamCount)
+    : QDialog(parent)
+    , m_ui(new Ui::MessageDialog)
+    , m_outStreams(streamCount)
+    , m_outBufs(streamCount)
+    , m_windowFunction(windowFunction)
 {
     m_ui->setupUi(this);
-    connect(&m_ioTimer, &QTimer::timeout, this, &MessageDialog::writeOutput);
-    m_ioTimer.setInterval(1000);
+    for (quint32 i = 0; i < streamCount; i++) {
+        m_outBufs[i].reset(new textbuf);
+        m_outStreams[i].reset(new std::ostream(m_outBufs.at(i).data()));
+        connect(m_outBufs.at(i).data(), &textbuf::outputString, this, &MessageDialog::receiveOutput, Qt::QueuedConnection);
+    }
+    
+    m_ui->messagesTextEdit->setContextMenuPolicy(Qt::CustomContextMenu);
+    connect(m_ui->messagesTextEdit, &QPlainTextEdit::customContextMenuRequested, this, &MessageDialog::provideContextMenu);
+    m_ui->messagesTextEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
+    connect(this, &QDialog::rejected, this, &MessageDialog::savePosition);
+    
+    if (!m_windowFunction.isEmpty()) {
+        setWindowTitle(m_windowFunction);
+    }
+}
+
+void MessageDialog::showEvent(QShowEvent* event)
+{
+    QDialog::showEvent(event);
+    if (!m_windowFunction.isEmpty()) {
+        QSettings settings;
+        settings.beginGroup("Window");
+        QByteArray geometry = settings.value(m_windowFunction + "Geometry").toByteArray();
+        if (geometry.size() > 0) {
+            restoreGeometry(geometry);
+        }
+    }
+}
+
+void MessageDialog::closeEvent(QCloseEvent* event)
+{
+    QDialog::closeEvent(event);
+    savePosition();
+}
+
+QSharedPointer<std::ostream> MessageDialog::getOutputStream(int index)
+{
+    if (index >=0 && index < m_outStreams.size()) {
+        return m_outStreams.at(index);
+    }
+    return QSharedPointer<std::ostream>();
+}
+
+bool MessageDialog::setRelayStream(std::ostream *relay, int index)
+{
+    if (index >=0 && index < m_outBufs.size()) {
+        m_outBufs.at(index)->setOutStream(relay);
+    }
+    return false;
 }
 
-void MessageDialog::setStatsFile(QSharedPointer<QTemporaryFile> statsFile)
+void MessageDialog::clearOutput()
 {
     m_ui->messagesTextEdit->clear();
-    m_ioStatsFile = statsFile;
 }
 
-void MessageDialog::startMonitoring() { m_ioTimer.start(); }
+void MessageDialog::receiveOutput(const QString& output)
+{
+    // Automatically scroll if we're at the bottom of the text box.
+    bool autoScroll = (m_ui->messagesTextEdit->verticalScrollBar()->value() == m_ui->messagesTextEdit->verticalScrollBar()->maximum());
+    // Make sure our cursor is at the end.
+    m_ui->messagesTextEdit->moveCursor(QTextCursor::End);
+    m_ui->messagesTextEdit->insertPlainText(output);
+    if (autoScroll) {
+        m_ui->messagesTextEdit->verticalScrollBar()->setValue(m_ui->messagesTextEdit->verticalScrollBar()->maximum());
+    }
+}
 
-void MessageDialog::stopMonitoring() { m_ioTimer.stop(); }
+void MessageDialog::provideContextMenu()
+{
+    // Add a custom context menu entry to clear the output.
+    QMenu *menu = m_ui->messagesTextEdit->createStandardContextMenu();
+    QAction *action = menu->addAction(QIcon::fromTheme("edit-delete"), "Clear");
+    connect(action, &QAction::triggered, this, &MessageDialog::clearOutput);
+    menu->exec(QCursor::pos());
+}
 
-void MessageDialog::writeOutput()
+void MessageDialog::savePosition()
 {
-    while (!m_ioStatsFile->atEnd()) {
-        m_ui->messagesTextEdit->moveCursor(QTextCursor::End);
-        m_ui->messagesTextEdit->insertPlainText(m_ioStatsFile->readLine());
-        (m_ioStatsFile->readLine());
+    if (!m_windowFunction.isEmpty()) {
+        QSettings settings;
+        settings.beginGroup("Window");
+        settings.setValue(m_windowFunction + "Geometry", saveGeometry());
+        settings.endGroup();
     }
 }
 
-MessageDialog::~MessageDialog() = default;
+MessageDialog::~MessageDialog() {
+    if (isVisible()) {
+        savePosition();
+    }
+}
index ccb0bcd93b3f4c19ea59660e1c9fc65bceece273..579d91cfc6850aa9bbd81bb4592d87f0130bb38d 100644 (file)
@@ -28,8 +28,9 @@
 
 #include <QDialog>
 #include <QScopedPointer>
-#include <QTemporaryFile>
-#include <QTimer>
+#include <QSharedPointer>
+#include <QVector>
+#include "textbuf.h"
 
 namespace Ui
 {
@@ -41,21 +42,28 @@ class MessageDialog : public QDialog
     Q_OBJECT
 
    public:
-    explicit MessageDialog(QWidget* parent = nullptr);
+    explicit MessageDialog(QWidget* parent = nullptr, QString windowFunction = "", quint32 streamCount = 1);
     ~MessageDialog() override;
-
-    void setStatsFile(QSharedPointer<QTemporaryFile> statsFile);
-    void startMonitoring();
-    void stopMonitoring();
-
+    
+    void showEvent(QShowEvent* event) override;
+    void closeEvent(QCloseEvent* event) override;
+    
+    QSharedPointer<std::ostream> getOutputStream(int index = 0);
+    bool setRelayStream(std::ostream *relay, int index = 0);
+    
+   public slots:
+    void clearOutput();
+    
    private slots:
-    void writeOutput();
+    void receiveOutput(const QString& output);
+    void provideContextMenu();
+    void savePosition();
 
    private:
     QScopedPointer<Ui::MessageDialog> m_ui;
-    QSharedPointer<QTemporaryFile> m_ioStatsFile;
-    // Using a QFileSystem watcher didn't work on OS X, so use a timer instead.
-    QTimer m_ioTimer;
+    QVector<QSharedPointer<std::ostream>> m_outStreams;
+    QVector<QSharedPointer<textbuf>> m_outBufs;
+    QString m_windowFunction;
 };
 
 #endif  // MESSAGEDIALOG_H
index 1ed8793116d422e53b0e8411c18bc04489386a99..0ccb5a3076c77efd4df454ac6efa9c55e81ca720 100644 (file)
 #include <ctime>
 
 #include "about.h"
+#ifdef NO_JTVS
+#include "ui_qjacktrip_novs.h"
+#else
 #include "ui_qjacktrip.h"
+#endif
 #ifdef USE_WEAK_JACK
 #include "weak_libjack.h"
 #endif
 
 QJackTrip::QJackTrip(QWidget* parent)
     : QMainWindow(parent)
+#ifdef NO_JTVS
     , m_ui(new Ui::QJackTrip)
+#else
+    , m_ui(new Ui::QJackTripVS)
+#endif
     , m_netManager(new QNetworkAccessManager(this))
-    , m_messageDialog(new MessageDialog(this))
+    , m_statsDialog(new MessageDialog(this, "Stats"))
+    , m_debugDialog(new MessageDialog(this, "Debug", 2))
+    , m_realCout(std::cout.rdbuf())
+    , m_realCerr(std::cerr.rdbuf())
     , m_jackTripRunning(false)
     , m_isExiting(false)
     , m_hasIPv4Reply(false)
@@ -64,6 +75,12 @@ QJackTrip::QJackTrip(QWidget* parent)
     QCoreApplication::setOrganizationName("jacktrip");
     QCoreApplication::setOrganizationDomain("jacktrip.org");
     QCoreApplication::setApplicationName("JackTrip");
+    
+    // Set up our debug window, and relay everything to our real cout.
+    std::cout.rdbuf(m_debugDialog->getOutputStream()->rdbuf());
+    std::cerr.rdbuf(m_debugDialog->getOutputStream(1)->rdbuf());
+    m_debugDialog->setRelayStream(&m_realCout);
+    m_debugDialog->setRelayStream(&m_realCerr, 1);
 
     // Create all our UI connections.
     connect(m_ui->typeComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
@@ -113,6 +130,16 @@ QJackTrip::QJackTrip(QWidget* parent)
     connect(m_ui->ioStatsCheckBox, &QCheckBox::stateChanged, this, [=]() {
         m_ui->ioStatsLabel->setEnabled(m_ui->ioStatsCheckBox->isChecked());
         m_ui->ioStatsSpinBox->setEnabled(m_ui->ioStatsCheckBox->isChecked());
+        if (!m_ui->ioStatsCheckBox->isChecked()) {
+            m_statsDialog->hide();
+        }
+    });
+    connect(m_ui->verboseCheckBox, &QCheckBox::stateChanged, this, [=]() {
+        gVerboseFlag = m_ui->verboseCheckBox->isChecked();
+        if (!gVerboseFlag) {
+            m_debugDialog->hide();
+            m_debugDialog->clearOutput();
+        }
     });
     connect(m_ui->jitterCheckBox, &QCheckBox::stateChanged, this, [=]() {
         m_ui->broadcastCheckBox->setEnabled(m_ui->jitterCheckBox->isChecked());
@@ -195,12 +222,9 @@ QJackTrip::QJackTrip(QWidget* parent)
 
     // Set up our interface for the default Client run mode.
     //(loadSettings will take care of the UI in all other cases.)
-    m_ui->remoteNameLabel->setVisible(false);
-    m_ui->remoteNameEdit->setVisible(false);
     m_ui->basePortLabel->setVisible(false);
     m_ui->basePortSpinBox->setVisible(false);
     m_ui->requireAuthGroupBox->setVisible(false);
-    m_ui->authGroupBox->setVisible(false);
 
 #ifdef __RT_AUDIO__
     connect(m_ui->backendComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
@@ -351,11 +375,11 @@ void QJackTrip::showEvent(QShowEvent* event)
 
     // One of our arguments will always be --gui, so if that's the only one
     // then we don't need to show the warning message.
-    if (m_argc > 2) {
+    if ((!gVerboseFlag && m_argc > 2) || m_argc > 3) {
         QMessageBox msgBox;
         msgBox.setText(
             "The GUI version of JackTrip currently\nignores any command line "
-            "options.\n\nThis may change in future.");
+            "options other\nthan the verbose option (-V).\n\nThis may change in future.");
         msgBox.setWindowTitle("Command line options");
         msgBox.exec();
     }
@@ -373,7 +397,6 @@ void QJackTrip::processFinished()
 #ifdef __MAC_OSX__
     m_noNap.enableNap();
 #endif
-    if (m_ui->ioStatsCheckBox->isChecked()) { m_messageDialog->stopMonitoring(); }
     m_ui->disconnectButton->setEnabled(false);
     if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) {
         m_udpHub.reset();
@@ -620,6 +643,10 @@ void QJackTrip::start()
     m_ui->connectButton->setEnabled(false);
     enableUi(false);
     m_jackTripRunning = true;
+    
+    if (gVerboseFlag) {
+        m_debugDialog->show();
+    }
 
     // Start the appropriate JackTrip process.
     try {
@@ -667,10 +694,10 @@ void QJackTrip::start()
 
             // Open our stats window if needed
             if (m_ui->ioStatsCheckBox->isChecked()) {
-                setupStatsWindow();
+                m_statsDialog->clearOutput();
+                m_statsDialog->show();
                 m_udpHub->setIOStatTimeout(m_ui->ioStatsSpinBox->value());
-                m_udpHub->setIOStatStream(QSharedPointer<std::ofstream>(
-                    new std::ofstream(m_ioStatsOutput->fileName().toUtf8().constData())));
+                m_udpHub->setIOStatStream(m_statsDialog->getOutputStream());
             }
 
             QObject::connect(m_udpHub.data(), &UdpHubListener::signalStopped, this,
@@ -785,10 +812,10 @@ void QJackTrip::start()
 
             // Open our stats window if needed
             if (m_ui->ioStatsCheckBox->isChecked()) {
-                setupStatsWindow();
+                m_statsDialog->clearOutput();
+                m_statsDialog->show();
                 m_jackTrip->setIOStatTimeout(m_ui->ioStatsSpinBox->value());
-                m_jackTrip->setIOStatStream(QSharedPointer<std::ofstream>(
-                    new std::ofstream(m_ioStatsOutput->fileName().toUtf8().constData())));
+                m_jackTrip->setIOStatStream(m_statsDialog->getOutputStream());
             }
 
             // Append any plugins
@@ -964,6 +991,8 @@ void QJackTrip::loadSettings()
     m_ui->resolutionComboBox->setCurrentIndex(settings.value("Resolution", 1).toInt());
     m_ui->connectAudioCheckBox->setChecked(settings.value("ConnectAudio", true).toBool());
     m_ui->realTimeCheckBox->setChecked(settings.value("RTNetworking", true).toBool());
+    // This may have been set by the command line, so don't overwrite if that's the case.
+    m_ui->verboseCheckBox->setChecked(gVerboseFlag || settings.value("Debug", 0).toBool());
     m_lastPath = settings.value("LastPath", QDir::homePath()).toString();
 
     settings.beginGroup("RecentServers");
@@ -1055,7 +1084,7 @@ void QJackTrip::loadSettings()
     settings.beginGroup("Window");
     QByteArray geometry = settings.value("Geometry").toByteArray();
     if (geometry.size() > 0) {
-        restoreGeometry(settings.value("Geometry").toByteArray());
+        restoreGeometry(geometry);
     } else {
         // Because of hidden elements in our dialog window, it's vertical size in the
         // creator is getting rediculous. Set it to something sensible by default if this
@@ -1085,6 +1114,7 @@ void QJackTrip::saveSettings()
     settings.setValue("Resolution", m_ui->resolutionComboBox->currentIndex());
     settings.setValue("ConnectAudio", m_ui->connectAudioCheckBox->isChecked());
     settings.setValue("RTNetworking", m_ui->realTimeCheckBox->isChecked());
+    settings.setValue("Debug", m_ui->verboseCheckBox->isChecked());
     settings.setValue("LastPath", m_lastPath);
 
     settings.beginGroup("RecentServers");
@@ -1151,15 +1181,6 @@ void QJackTrip::saveSettings()
     settings.endGroup();
 }
 
-void QJackTrip::setupStatsWindow()
-{
-    m_ioStatsOutput.reset(new QTemporaryFile());
-    m_ioStatsOutput->open();
-    m_messageDialog->setStatsFile(m_ioStatsOutput);
-    m_messageDialog->show();
-    m_messageDialog->startMonitoring();
-}
-
 void QJackTrip::appendPlugins(JackTrip* jackTrip, int numSendChannels,
                               int numRecvChannels)
 {
@@ -1286,7 +1307,7 @@ QString QJackTrip::commandLineFromCurrentOptions()
     // Auth settings
     if (m_ui->typeComboBox->currentIndex() == HUB_SERVER) {
         if (m_ui->requireAuthCheckBox->isChecked()) {
-            commandLine.append(QString(" -A"));
+            commandLine.append(" -A");
             if (!m_ui->certEdit->text().isEmpty()) {
                 commandLine.append(" --certfile ").append(m_ui->certEdit->text());
             }
@@ -1299,7 +1320,7 @@ QString QJackTrip::commandLineFromCurrentOptions()
         }
     } else if (m_ui->typeComboBox->currentIndex() == HUB_CLIENT) {
         if (m_ui->authCheckBox->isChecked()) {
-            commandLine.append(QString(" -A"));
+            commandLine.append(" -A");
             if (!m_ui->usernameEdit->text().isEmpty()) {
                 commandLine.append(" --username ").append(m_ui->usernameEdit->text());
             }
@@ -1382,6 +1403,8 @@ QString QJackTrip::commandLineFromCurrentOptions()
     if (m_ui->ioStatsCheckBox->isChecked()) {
         commandLine.append(QString(" -I %1").arg(m_ui->ioStatsSpinBox->value()));
     }
+    
+    if (m_ui->verboseCheckBox->isChecked()) { commandLine.append(" -V"); }
 
     if (m_ui->realTimeCheckBox->isChecked()) { commandLine.append(" --udprt"); }
 
@@ -1446,4 +1469,9 @@ void QJackTrip::showCommandLineMessageBox()
     msgBox.exec();
 }
 
-QJackTrip::~QJackTrip() = default;
+QJackTrip::~QJackTrip()
+{
+    //Restore cout. (Stops a crash on exit.)
+    std::cout.rdbuf(m_realCout.rdbuf());
+    std::cerr.rdbuf(m_realCerr.rdbuf());
+}
index 6d570804e1196ce2669619bfd3bf16c7c930ce94..124696320119d7ce31979d429bd494cd37bf18e2 100644 (file)
 
 namespace Ui
 {
+#ifdef NO_JTVS
 class QJackTrip;
+#else
+class QJackTripVS;
+#endif
 }
 
 class QJackTrip : public QMainWindow
@@ -102,18 +106,23 @@ class QJackTrip : public QMainWindow
     void populateDeviceMenu(QComboBox* menu, bool isInput);
 #endif
 
-    void setupStatsWindow();
     void appendPlugins(JackTrip* jackTrip, int numSendChannels, int numRecvChannels);
 
     QString commandLineFromCurrentOptions();
     void showCommandLineMessageBox();
 
+#ifdef NO_JTVS
     QScopedPointer<Ui::QJackTrip> m_ui;
+#else
+    QScopedPointer<Ui::QJackTripVS> m_ui;
+#endif
     QScopedPointer<UdpHubListener> m_udpHub;
     QScopedPointer<JackTrip> m_jackTrip;
     QScopedPointer<QNetworkAccessManager> m_netManager;
-    QScopedPointer<MessageDialog> m_messageDialog;
-    QSharedPointer<QTemporaryFile> m_ioStatsOutput;
+    QScopedPointer<MessageDialog> m_statsDialog;
+    QScopedPointer<MessageDialog> m_debugDialog;
+    std::ostream m_realCout;
+    std::ostream m_realCerr;
     bool m_jackTripRunning;
     bool m_isExiting;
 
index 53871039ea7e78576718e252d80b31a1d310a636..3529a1a4ae4b611a0904423c5f6195f59723b8f9 100644 (file)
@@ -1,13 +1,13 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
- <class>QJackTrip</class>
- <widget class="QMainWindow" name="QJackTrip">
+ <class>QJackTripVS</class>
+ <widget class="QMainWindow" name="QJackTripVS">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>409</width>
-    <height>817</height>
+    <height>845</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -25,6 +25,9 @@
        <string>To connect to a p2p (peer to peer) server you need to run as a p2p client.
 To connect to a hub server you need to run as a hub client.</string>
       </property>
+      <property name="currentIndex">
+       <number>2</number>
+      </property>
       <item>
        <property name="text">
         <string>P2P Client</string>
@@ -491,8 +494,8 @@ To connect to a hub server you need to run as a hub client.</string>
         <string>Advanced options</string>
        </attribute>
        <layout class="QGridLayout" name="gridLayout_4">
-        <item row="2" column="0">
-         <widget class="QLabel" name="localPortLabel">
+        <item row="7" column="0">
+         <widget class="QLabel" name="resolutionLabel">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
             <horstretch>0</horstretch>
@@ -500,10 +503,50 @@ To connect to a hub server you need to run as a hub client.</string>
            </sizepolicy>
           </property>
           <property name="text">
-           <string>&amp;Local Port</string>
+           <string>Audio &amp;Bit Resolution</string>
           </property>
           <property name="buddy">
-           <cstring>localPortSpinBox</cstring>
+           <cstring>resolutionComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="7" column="1" colspan="2">
+         <widget class="QComboBox" name="resolutionComboBox">
+          <property name="toolTip">
+           <string>Select the audio bit resolution.</string>
+          </property>
+          <property name="currentIndex">
+           <number>1</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>8</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>16</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>24</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>32</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="1" column="1" colspan="2">
+         <widget class="QLineEdit" name="remoteNameEdit">
+          <property name="toolTip">
+           <string>Set the name of the Jack client as it will appear on the hub server.</string>
+          </property>
+          <property name="maxLength">
+           <number>64</number>
           </property>
          </widget>
         </item>
@@ -523,7 +566,56 @@ To connect to a hub server you need to run as a hub client.</string>
           </property>
          </widget>
         </item>
-        <item row="12" column="0" colspan="3">
+        <item row="1" column="0">
+         <widget class="QLabel" name="remoteNameLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Remote Client &amp;Name</string>
+          </property>
+          <property name="buddy">
+           <cstring>remoteNameEdit</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0">
+         <widget class="QLabel" name="remotePortLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Remote &amp;Port</string>
+          </property>
+          <property name="buddy">
+           <cstring>remotePortSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1" colspan="2">
+         <widget class="QSpinBox" name="localPortSpinBox">
+          <property name="toolTip">
+           <string>Set the local port to use for the connection. The default is 4464.
+(Useful for running multiple hub clients behind the same router.)</string>
+          </property>
+          <property name="minimum">
+           <number>1024</number>
+          </property>
+          <property name="maximum">
+           <number>65535</number>
+          </property>
+          <property name="value">
+           <number>4464</number>
+          </property>
+         </widget>
+        </item>
+        <item row="13" column="0" colspan="3">
          <widget class="QGroupBox" name="authGroupBox">
           <property name="enabled">
            <bool>true</bool>
@@ -597,8 +689,8 @@ To connect to a hub server you need to run as a hub client.</string>
           </layout>
          </widget>
         </item>
-        <item row="1" column="0">
-         <widget class="QLabel" name="remoteNameLabel">
+        <item row="2" column="0">
+         <widget class="QLabel" name="localPortLabel">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
             <horstretch>0</horstretch>
@@ -606,61 +698,15 @@ To connect to a hub server you need to run as a hub client.</string>
            </sizepolicy>
           </property>
           <property name="text">
-           <string>Remote Client &amp;Name</string>
+           <string>&amp;Local Port</string>
           </property>
           <property name="buddy">
-           <cstring>remoteNameEdit</cstring>
-          </property>
-         </widget>
-        </item>
-        <item row="12" column="0">
-         <spacer name="advancedVerticalSpacer">
-          <property name="orientation">
-           <enum>Qt::Vertical</enum>
-          </property>
-          <property name="sizeHint" stdset="0">
-           <size>
-            <width>20</width>
-            <height>40</height>
-           </size>
-          </property>
-         </spacer>
-        </item>
-        <item row="8" column="0" colspan="3">
-         <widget class="QCheckBox" name="connectAudioCheckBox">
-          <property name="toolTip">
-           <string>Connect the Jack client to the default system audio ports.</string>
-          </property>
-          <property name="text">
-           <string>&amp;Connect default audio ports</string>
-          </property>
-          <property name="checked">
-           <bool>true</bool>
-          </property>
-         </widget>
-        </item>
-        <item row="2" column="1" colspan="2">
-         <widget class="QSpinBox" name="localPortSpinBox">
-          <property name="toolTip">
-           <string>Set the local port to use for the connection. The default is 4464.
-(Useful for running multiple hub clients behind the same router.)</string>
-          </property>
-          <property name="minimum">
-           <number>1024</number>
-          </property>
-          <property name="maximum">
-           <number>65535</number>
-          </property>
-          <property name="value">
-           <number>4464</number>
+           <cstring>localPortSpinBox</cstring>
           </property>
          </widget>
         </item>
-        <item row="11" column="2">
-         <widget class="QLabel" name="ioStatsLabel">
-          <property name="enabled">
-           <bool>false</bool>
-          </property>
+        <item row="5" column="0">
+         <widget class="QLabel" name="queueLengthLabel">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
             <horstretch>0</horstretch>
@@ -668,15 +714,28 @@ To connect to a hub server you need to run as a hub client.</string>
            </sizepolicy>
           </property>
           <property name="text">
-           <string>Reporting &amp;Interval (s)</string>
+           <string>&amp;Queue Buffer Length</string>
           </property>
           <property name="buddy">
-           <cstring>ioStatsSpinBox</cstring>
+           <cstring>queueLengthSpinBox</cstring>
           </property>
          </widget>
         </item>
-        <item row="3" column="0">
-         <widget class="QLabel" name="remotePortLabel">
+        <item row="14" column="0">
+         <spacer name="advancedVerticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="4" column="0">
+         <widget class="QLabel" name="basePortLabel">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
             <horstretch>0</horstretch>
@@ -684,15 +743,15 @@ To connect to a hub server you need to run as a hub client.</string>
            </sizepolicy>
           </property>
           <property name="text">
-           <string>Remote &amp;Port</string>
+           <string>&amp;UDP Base Port</string>
           </property>
           <property name="buddy">
-           <cstring>remotePortSpinBox</cstring>
+           <cstring>basePortSpinBox</cstring>
           </property>
          </widget>
         </item>
-        <item row="7" column="0">
-         <widget class="QLabel" name="resolutionLabel">
+        <item row="0" column="0">
+         <widget class="QLabel" name="clientNameLabel">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
             <horstretch>0</horstretch>
@@ -700,28 +759,18 @@ To connect to a hub server you need to run as a hub client.</string>
            </sizepolicy>
           </property>
           <property name="text">
-           <string>Audio &amp;Bit Resolution</string>
+           <string>Custom Client &amp;Name</string>
           </property>
           <property name="buddy">
-           <cstring>resolutionComboBox</cstring>
+           <cstring>clientNameEdit</cstring>
           </property>
          </widget>
         </item>
-        <item row="0" column="1" colspan="2">
-         <widget class="QLineEdit" name="clientNameEdit">
-          <property name="toolTip">
-           <string>Set the name of the Jack client.</string>
-          </property>
-          <property name="maxLength">
-           <number>64</number>
-          </property>
-          <property name="placeholderText">
-           <string>JackTrip</string>
+        <item row="11" column="2">
+         <widget class="QLabel" name="ioStatsLabel">
+          <property name="enabled">
+           <bool>false</bool>
           </property>
-         </widget>
-        </item>
-        <item row="6" column="0">
-         <widget class="QLabel" name="redundancyLabel">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
             <horstretch>0</horstretch>
@@ -729,41 +778,41 @@ To connect to a hub server you need to run as a hub client.</string>
            </sizepolicy>
           </property>
           <property name="text">
-           <string>&amp;Redundancy</string>
+           <string>Reporting &amp;Interval (s)</string>
           </property>
           <property name="buddy">
-           <cstring>redundancySpinBox</cstring>
+           <cstring>ioStatsSpinBox</cstring>
           </property>
          </widget>
         </item>
-        <item row="5" column="0">
-         <widget class="QLabel" name="queueLengthLabel">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
+        <item row="5" column="1" colspan="2">
+         <widget class="QSpinBox" name="queueLengthSpinBox">
+          <property name="toolTip">
+           <string>Set the queue buffer length, in packet size.</string>
           </property>
-          <property name="text">
-           <string>&amp;Queue Buffer Length</string>
+          <property name="minimum">
+           <number>2</number>
           </property>
-          <property name="buddy">
-           <cstring>queueLengthSpinBox</cstring>
+          <property name="value">
+           <number>4</number>
           </property>
          </widget>
         </item>
-        <item row="1" column="1" colspan="2">
-         <widget class="QLineEdit" name="remoteNameEdit">
+        <item row="6" column="1" colspan="2">
+         <widget class="QSpinBox" name="redundancySpinBox">
           <property name="toolTip">
-           <string>Set the name of the Jack client as it will appear on the hub server.</string>
+           <string>Number of redundant packets to be sent to avoid glitches related to packet loss.</string>
           </property>
-          <property name="maxLength">
-           <number>64</number>
+          <property name="minimum">
+           <number>1</number>
+          </property>
+          <property name="value">
+           <number>1</number>
           </property>
          </widget>
         </item>
-        <item row="0" column="0">
-         <widget class="QLabel" name="clientNameLabel">
+        <item row="6" column="0">
+         <widget class="QLabel" name="redundancyLabel">
           <property name="sizePolicy">
            <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
             <horstretch>0</horstretch>
@@ -771,10 +820,10 @@ To connect to a hub server you need to run as a hub client.</string>
            </sizepolicy>
           </property>
           <property name="text">
-           <string>Custom Client &amp;Name</string>
+           <string>&amp;Redundancy</string>
           </property>
           <property name="buddy">
-           <cstring>clientNameEdit</cstring>
+           <cstring>redundancySpinBox</cstring>
           </property>
          </widget>
         </item>
@@ -794,66 +843,53 @@ To connect to a hub server you need to run as a hub client.</string>
           </property>
          </widget>
         </item>
-        <item row="7" column="1" colspan="2">
-         <widget class="QComboBox" name="resolutionComboBox">
+        <item row="3" column="1" colspan="2">
+         <widget class="QSpinBox" name="remotePortSpinBox">
           <property name="toolTip">
-           <string>Select the audio bit resolution.</string>
+           <string>Set the remote port to use for the connection. The default is 4464.</string>
           </property>
-          <property name="currentIndex">
-           <number>1</number>
+          <property name="minimum">
+           <number>1024</number>
+          </property>
+          <property name="maximum">
+           <number>65535</number>
+          </property>
+          <property name="value">
+           <number>4464</number>
           </property>
-          <item>
-           <property name="text">
-            <string>8</string>
-           </property>
-          </item>
-          <item>
-           <property name="text">
-            <string>16</string>
-           </property>
-          </item>
-          <item>
-           <property name="text">
-            <string>24</string>
-           </property>
-          </item>
-          <item>
-           <property name="text">
-            <string>32</string>
-           </property>
-          </item>
          </widget>
         </item>
-        <item row="6" column="1" colspan="2">
-         <widget class="QSpinBox" name="redundancySpinBox">
+        <item row="8" column="0" colspan="3">
+         <widget class="QCheckBox" name="connectAudioCheckBox">
           <property name="toolTip">
-           <string>Number of redundant packets to be sent to avoid glitches related to packet loss.</string>
+           <string>Connect the Jack client to the default system audio ports.</string>
           </property>
-          <property name="minimum">
-           <number>1</number>
+          <property name="text">
+           <string>&amp;Connect default audio ports</string>
           </property>
-          <property name="value">
-           <number>1</number>
+          <property name="checked">
+           <bool>true</bool>
           </property>
          </widget>
         </item>
-        <item row="5" column="1" colspan="2">
-         <widget class="QSpinBox" name="queueLengthSpinBox">
+        <item row="0" column="1" colspan="2">
+         <widget class="QLineEdit" name="clientNameEdit">
           <property name="toolTip">
-           <string>Set the queue buffer length, in packet size.</string>
+           <string>Set the name of the Jack client.</string>
           </property>
-          <property name="minimum">
-           <number>2</number>
+          <property name="maxLength">
+           <number>64</number>
           </property>
-          <property name="value">
-           <number>4</number>
+          <property name="placeholderText">
+           <string>JackTrip</string>
           </property>
          </widget>
         </item>
-        <item row="3" column="1" colspan="2">
-         <widget class="QSpinBox" name="remotePortSpinBox">
+        <item row="4" column="1" colspan="2">
+         <widget class="QSpinBox" name="basePortSpinBox">
           <property name="toolTip">
-           <string>Set the remote port to use for the connection. The default is 4464.</string>
+           <string>Set the base UDP port to be used by connecting hub clients. The default is 61002.
+(You should manually set this if running multiple hub servers on the same machine.)</string>
           </property>
           <property name="minimum">
            <number>1024</number>
@@ -862,11 +898,11 @@ To connect to a hub server you need to run as a hub client.</string>
            <number>65535</number>
           </property>
           <property name="value">
-           <number>4464</number>
+           <number>61002</number>
           </property>
          </widget>
         </item>
-        <item row="13" column="0" colspan="3">
+        <item row="15" column="0" colspan="3">
          <layout class="QHBoxLayout" name="useDefaultsLayout">
           <item>
            <spacer name="useDefaultsSpacer">
@@ -900,39 +936,6 @@ To connect to a hub server you need to run as a hub client.</string>
           </item>
          </layout>
         </item>
-        <item row="4" column="0">
-         <widget class="QLabel" name="basePortLabel">
-          <property name="sizePolicy">
-           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
-            <horstretch>0</horstretch>
-            <verstretch>0</verstretch>
-           </sizepolicy>
-          </property>
-          <property name="text">
-           <string>&amp;UDP Base Port</string>
-          </property>
-          <property name="buddy">
-           <cstring>basePortSpinBox</cstring>
-          </property>
-         </widget>
-        </item>
-        <item row="4" column="1" colspan="2">
-         <widget class="QSpinBox" name="basePortSpinBox">
-          <property name="toolTip">
-           <string>Set the base UDP port to be used by connecting hub clients. The default is 61002.
-(You should manually set this if running multiple hub servers on the same machine.)</string>
-          </property>
-          <property name="minimum">
-           <number>1024</number>
-          </property>
-          <property name="maximum">
-           <number>65535</number>
-          </property>
-          <property name="value">
-           <number>61002</number>
-          </property>
-         </widget>
-        </item>
         <item row="9" column="0" colspan="3">
          <widget class="QCheckBox" name="realTimeCheckBox">
           <property name="toolTip">
@@ -946,6 +949,13 @@ To connect to a hub server you need to run as a hub client.</string>
           </property>
          </widget>
         </item>
+        <item row="12" column="0" colspan="3">
+         <widget class="QCheckBox" name="verboseCheckBox">
+          <property name="text">
+           <string>Show &amp;Debug Information</string>
+          </property>
+         </widget>
+        </item>
        </layout>
       </widget>
       <widget class="QWidget" name="backendTab">
@@ -1189,28 +1199,28 @@ To connect to a hub server you need to run as a hub client.</string>
          </spacer>
         </item>
         <item row="8" column="0" colspan="2">
-          <layout class="QHBoxLayout" name="deviceManagementLayout">
-           <item>
-            <spacer name="backendTabSpacer">
-             <property name="orientation">
-              <enum>Qt::Horizontal</enum>
-             </property>
-             <property name="sizeHint" stdset="0">
-              <size>
-               <width>40</width>
-               <height>20</height>
-              </size>
-             </property>
-            </spacer>
-           </item>
-           <item row="8" column="2">
-            <widget class="QPushButton" name="refreshDevicesButton">
-             <property name="text">
-              <string>&amp;Refresh Device List</string>
-             </property>
-            </widget>
-           </item>
-          </layout>
+         <layout class="QHBoxLayout" name="deviceManagementLayout">
+          <item>
+           <spacer name="backendTabSpacer">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QPushButton" name="refreshDevicesButton">
+            <property name="text">
+             <string>&amp;Refresh Device List</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
         </item>
        </layout>
       </widget>
@@ -1222,7 +1232,7 @@ To connect to a hub server you need to run as a hub client.</string>
         <item row="10" column="2">
          <widget class="QLabel" name="packetsLabel">
           <property name="enabled">
-           <bool>false</bool>
+           <bool>true</bool>
           </property>
           <property name="text">
            <string>Packets</string>
@@ -1237,12 +1247,15 @@ To connect to a hub server you need to run as a hub client.</string>
           <property name="text">
            <string>Automatically set the &amp;queue length</string>
           </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
          </widget>
         </item>
         <item row="9" column="0" colspan="2">
          <widget class="QLabel" name="autoQueueLabel">
           <property name="enabled">
-           <bool>false</bool>
+           <bool>true</bool>
           </property>
           <property name="sizePolicy">
            <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
@@ -1271,7 +1284,7 @@ To connect to a hub server you need to run as a hub client.</string>
         <item row="9" column="2">
          <widget class="QSpinBox" name="autoQueueSpinBox">
           <property name="enabled">
-           <bool>false</bool>
+           <bool>true</bool>
           </property>
           <property name="sizePolicy">
            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@@ -1317,7 +1330,7 @@ for better quality at the expense of latency.</string>
         <item row="11" column="0" colspan="3">
          <widget class="QLabel" name="autoQueueExplanationLabel">
           <property name="enabled">
-           <bool>false</bool>
+           <bool>true</bool>
           </property>
           <property name="text">
            <string>This will override the queue buffer length entered in the advanced options tab. (The default value is 500.)</string>
@@ -1750,9 +1763,6 @@ and wetness is the essence of beauty.</string>
   <tabstop>keyBrowse</tabstop>
   <tabstop>credsEdit</tabstop>
   <tabstop>credsBrowse</tabstop>
-  <tabstop>authCheckBox</tabstop>
-  <tabstop>usernameEdit</tabstop>
-  <tabstop>passwordEdit</tabstop>
   <tabstop>aboutButton</tabstop>
   <tabstop>clientNameEdit</tabstop>
   <tabstop>remoteNameEdit</tabstop>
@@ -1766,6 +1776,9 @@ and wetness is the essence of beauty.</string>
   <tabstop>realTimeCheckBox</tabstop>
   <tabstop>ioStatsCheckBox</tabstop>
   <tabstop>ioStatsSpinBox</tabstop>
+  <tabstop>authCheckBox</tabstop>
+  <tabstop>usernameEdit</tabstop>
+  <tabstop>passwordEdit</tabstop>
   <tabstop>commandLineButton</tabstop>
   <tabstop>useDefaultsButton</tabstop>
   <tabstop>backendComboBox</tabstop>
diff --git a/src/gui/qjacktrip_novs.ui b/src/gui/qjacktrip_novs.ui
new file mode 100644 (file)
index 0000000..9d67bd1
--- /dev/null
@@ -0,0 +1,1815 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QJackTrip</class>
+ <widget class="QMainWindow" name="QJackTrip">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>409</width>
+    <height>817</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>JackTrip</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="qjacktrip.qrc">
+    <normaloff>:/qjacktrip/icon.png</normaloff>:/qjacktrip/icon.png</iconset>
+  </property>
+  <widget class="QWidget" name="centralWidget">
+   <layout class="QGridLayout" name="gridLayout">
+    <item row="0" column="1">
+     <widget class="QComboBox" name="typeComboBox">
+      <property name="toolTip">
+       <string>To connect to a p2p (peer to peer) server you need to run as a p2p client.
+To connect to a hub server you need to run as a hub client.</string>
+      </property>
+      <property name="currentIndex">
+       <number>2</number>
+      </property>
+      <item>
+       <property name="text">
+        <string>P2P Client</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>P2P Server</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>Hub Client</string>
+       </property>
+      </item>
+      <item>
+       <property name="text">
+        <string>Hub Server</string>
+       </property>
+      </item>
+     </widget>
+    </item>
+    <item row="6" column="0" colspan="2">
+     <layout class="QHBoxLayout" name="buttonLayout">
+      <item>
+       <widget class="QPushButton" name="connectButton">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="text">
+         <string>Connect</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="disconnectButton">
+        <property name="enabled">
+         <bool>false</bool>
+        </property>
+        <property name="text">
+         <string>Disconnect</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="exitButton">
+        <property name="text">
+         <string>Exit</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+    <item row="3" column="1">
+     <widget class="QLabel" name="ipLabel">
+      <property name="toolTip">
+       <string>If running as a server, this is the address you should supply to the other clients.
+(You will need to enable any port forwarding on your router manually.)</string>
+      </property>
+      <property name="text">
+       <string>Looking up external IP address...</string>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="1">
+     <widget class="QComboBox" name="addressComboBox">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="toolTip">
+       <string>Enter the IP address or the hostname of the server you want to connect to.</string>
+      </property>
+      <property name="editable">
+       <bool>true</bool>
+      </property>
+      <property name="maxCount">
+       <number>5</number>
+      </property>
+      <property name="insertPolicy">
+       <enum>QComboBox::NoInsert</enum>
+      </property>
+     </widget>
+    </item>
+    <item row="1" column="0">
+     <widget class="QLabel" name="addressLabel">
+      <property name="enabled">
+       <bool>true</bool>
+      </property>
+      <property name="text">
+       <string>&amp;Address of server</string>
+      </property>
+      <property name="buddy">
+       <cstring>addressComboBox</cstring>
+      </property>
+     </widget>
+    </item>
+    <item row="0" column="0">
+     <widget class="QLabel" name="typeLabel">
+      <property name="text">
+       <string>&amp;Run JackTrip as</string>
+      </property>
+      <property name="buddy">
+       <cstring>typeComboBox</cstring>
+      </property>
+     </widget>
+    </item>
+    <item row="5" column="0" colspan="2">
+     <widget class="QTabWidget" name="optionsTabWidget">
+      <property name="enabled">
+       <bool>true</bool>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>391</width>
+        <height>0</height>
+       </size>
+      </property>
+      <property name="currentIndex">
+       <number>0</number>
+      </property>
+      <property name="tabsClosable">
+       <bool>false</bool>
+      </property>
+      <property name="movable">
+       <bool>false</bool>
+      </property>
+      <widget class="QWidget" name="basicTab">
+       <property name="enabled">
+        <bool>true</bool>
+       </property>
+       <attribute name="title">
+        <string>Basic options</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_3">
+        <item row="2" column="0" colspan="3">
+         <widget class="QGroupBox" name="channelGroupBox">
+          <layout class="QGridLayout" name="gridLayout_9">
+           <item row="3" column="0">
+            <widget class="QLabel" name="channelRecvLabel">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="text">
+              <string>&amp;Received from network:</string>
+             </property>
+             <property name="buddy">
+              <cstring>channelRecvSpinBox</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QSpinBox" name="channelRecvSpinBox">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="toolTip">
+              <string>Number of audio channels toaccept from the network.</string>
+             </property>
+             <property name="minimum">
+              <number>1</number>
+             </property>
+             <property name="value">
+              <number>2</number>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="1">
+            <widget class="QSpinBox" name="channelSendSpinBox">
+             <property name="toolTip">
+              <string>Number of audio channels to send to the network.</string>
+             </property>
+             <property name="minimum">
+              <number>1</number>
+             </property>
+             <property name="value">
+              <number>2</number>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="0">
+            <widget class="QLabel" name="channelSendLabel">
+             <property name="text">
+              <string>&amp;Sent to network:</string>
+             </property>
+             <property name="buddy">
+              <cstring>channelSendSpinBox</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0" colspan="2">
+            <widget class="QLabel" name="channelLabel">
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <property name="text">
+              <string>&amp;Number of channels</string>
+             </property>
+             <property name="buddy">
+              <cstring>channelRecvSpinBox</cstring>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item row="8" column="0" colspan="3">
+         <widget class="QGroupBox" name="authGroupBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="title">
+           <string/>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_6">
+           <item row="0" column="0" colspan="2">
+            <widget class="QCheckBox" name="authCheckBox">
+             <property name="toolTip">
+              <string>Supply a username and password to connect to the server.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Use Authentication</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QLineEdit" name="passwordEdit">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Enter your password. (This will not be shown or saved.)</string>
+             </property>
+             <property name="echoMode">
+              <enum>QLineEdit::Password</enum>
+             </property>
+             <property name="cursorPosition">
+              <number>0</number>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="1">
+            <widget class="QLineEdit" name="usernameEdit">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Enter your username for the server.</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QLabel" name="passwordLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>&amp;Password</string>
+             </property>
+             <property name="buddy">
+              <cstring>passwordEdit</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0">
+            <widget class="QLabel" name="usernameLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>&amp;Username</string>
+             </property>
+             <property name="buddy">
+              <cstring>usernameEdit</cstring>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item row="3" column="1" colspan="2">
+         <widget class="QComboBox" name="autoPatchComboBox">
+          <property name="toolTip">
+           <string>Select how you want audio to be routed by the hub server.</string>
+          </property>
+          <property name="currentIndex">
+           <number>0</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>Server to clients</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Client loopback</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Client fan out/in but no loopback</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>Full Mix</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>No auto patching</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="11" column="0" colspan="3">
+         <layout class="QHBoxLayout" name="aboutLayout">
+          <item>
+           <spacer name="aboutSpacer">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QPushButton" name="aboutButton">
+            <property name="text">
+             <string>About</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item row="7" column="0" colspan="3">
+         <widget class="QGroupBox" name="requireAuthGroupBox">
+          <property name="title">
+           <string/>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_7">
+           <item row="3" column="2">
+            <widget class="QPushButton" name="keyBrowse">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Browse</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0" colspan="3">
+            <widget class="QLabel" name="authDisclaimerLabel">
+             <property name="text">
+              <string>(This is a work in progress and needs to be manually configured outside of the app. Only use if you know what you're doing.)</string>
+             </property>
+             <property name="wordWrap">
+              <bool>true</bool>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0">
+            <widget class="QLabel" name="certLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>&amp;Certificate File</string>
+             </property>
+             <property name="buddy">
+              <cstring>certEdit</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QLabel" name="keyLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>&amp;Key File</string>
+             </property>
+             <property name="buddy">
+              <cstring>keyEdit</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QLineEdit" name="keyEdit">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Choose the private key that the server should use for the SSL connection.</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="1">
+            <widget class="QLineEdit" name="certEdit">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Choose the certificate file that the server should use to establish an initial SSL connection.</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="2">
+            <widget class="QPushButton" name="certBrowse">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Browse</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="0" colspan="2">
+            <widget class="QCheckBox" name="requireAuthCheckBox">
+             <property name="toolTip">
+              <string>Require clients to connect with a username and password.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Require Authentication</string>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="0">
+            <widget class="QLabel" name="credsLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>&amp;Credentials File</string>
+             </property>
+             <property name="buddy">
+              <cstring>credsEdit</cstring>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="1">
+            <widget class="QLineEdit" name="credsEdit">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Choose the file containing the list of usernames and passwords.</string>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="2">
+            <widget class="QPushButton" name="credsBrowse">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Browse</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item row="6" column="0" colspan="3">
+         <widget class="QCheckBox" name="timeoutCheckBox">
+          <property name="toolTip">
+           <string>Stop JackTrip if no network traffic has been received for 10 seconds.</string>
+          </property>
+          <property name="text">
+           <string>&amp;Disconnect after 10 seconds of no network activity</string>
+          </property>
+         </widget>
+        </item>
+        <item row="9" column="0">
+         <spacer name="basicVerticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeType">
+           <enum>QSizePolicy::Expanding</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="5" column="0" colspan="3">
+         <widget class="QCheckBox" name="zeroCheckBox">
+          <property name="toolTip">
+           <string>Silence the audio when there's a buffer underrun.</string>
+          </property>
+          <property name="text">
+           <string>Set buffer to &amp;zero when underrun occurs</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0">
+         <widget class="QLabel" name="autoPatchLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Hub auto&amp;patch mode</string>
+          </property>
+          <property name="buddy">
+           <cstring>autoPatchComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="advancedTab">
+       <property name="enabled">
+        <bool>true</bool>
+       </property>
+       <attribute name="title">
+        <string>Advanced options</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_4">
+        <item row="5" column="0">
+         <widget class="QLabel" name="queueLengthLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Queue Buffer Length</string>
+          </property>
+          <property name="buddy">
+           <cstring>queueLengthSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1" colspan="2">
+         <widget class="QLineEdit" name="clientNameEdit">
+          <property name="toolTip">
+           <string>Set the name of the Jack client.</string>
+          </property>
+          <property name="maxLength">
+           <number>64</number>
+          </property>
+          <property name="placeholderText">
+           <string>JackTrip</string>
+          </property>
+         </widget>
+        </item>
+        <item row="13" column="0">
+         <spacer name="advancedVerticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="7" column="0">
+         <widget class="QLabel" name="resolutionLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Audio &amp;Bit Resolution</string>
+          </property>
+          <property name="buddy">
+           <cstring>resolutionComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1" colspan="2">
+         <widget class="QLineEdit" name="remoteNameEdit">
+          <property name="toolTip">
+           <string>Set the name of the Jack client as it will appear on the hub server.</string>
+          </property>
+          <property name="maxLength">
+           <number>64</number>
+          </property>
+         </widget>
+        </item>
+        <item row="7" column="1" colspan="2">
+         <widget class="QComboBox" name="resolutionComboBox">
+          <property name="toolTip">
+           <string>Select the audio bit resolution.</string>
+          </property>
+          <property name="currentIndex">
+           <number>1</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>8</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>16</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>24</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>32</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="9" column="0" colspan="3">
+         <widget class="QCheckBox" name="realTimeCheckBox">
+          <property name="toolTip">
+           <string>Use real time priority for the networking threads.</string>
+          </property>
+          <property name="text">
+           <string>Enable real&amp;time priority for networking threads</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="11" column="1">
+         <widget class="QSpinBox" name="ioStatsSpinBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="toolTip">
+           <string>Choose how often stats should be reported.</string>
+          </property>
+          <property name="minimum">
+           <number>1</number>
+          </property>
+          <property name="maximum">
+           <number>120</number>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="1" colspan="2">
+         <widget class="QSpinBox" name="basePortSpinBox">
+          <property name="toolTip">
+           <string>Set the base UDP port to be used by connecting hub clients. The default is 61002.
+(You should manually set this if running multiple hub servers on the same machine.)</string>
+          </property>
+          <property name="minimum">
+           <number>1024</number>
+          </property>
+          <property name="maximum">
+           <number>65535</number>
+          </property>
+          <property name="value">
+           <number>61002</number>
+          </property>
+         </widget>
+        </item>
+        <item row="14" column="0" colspan="3">
+         <layout class="QHBoxLayout" name="useDefaultsLayout">
+          <item>
+           <spacer name="useDefaultsSpacer">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QPushButton" name="commandLineButton">
+            <property name="toolTip">
+             <string>Show the equivalent command line for the current settings.</string>
+            </property>
+            <property name="text">
+             <string>Get Command &amp;Line</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QPushButton" name="useDefaultsButton">
+            <property name="text">
+             <string>Use &amp;Defaults</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="remoteNameLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Remote Client &amp;Name</string>
+          </property>
+          <property name="buddy">
+           <cstring>remoteNameEdit</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="11" column="0">
+         <widget class="QCheckBox" name="ioStatsCheckBox">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="toolTip">
+           <string>Display IO stats in another window.</string>
+          </property>
+          <property name="text">
+           <string>Display &amp;IO Stats</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0">
+         <widget class="QLabel" name="remotePortLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Remote &amp;Port</string>
+          </property>
+          <property name="buddy">
+           <cstring>remotePortSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="0">
+         <widget class="QLabel" name="clientNameLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Custom Client &amp;Name</string>
+          </property>
+          <property name="buddy">
+           <cstring>clientNameEdit</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="6" column="0">
+         <widget class="QLabel" name="redundancyLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Redundancy</string>
+          </property>
+          <property name="buddy">
+           <cstring>redundancySpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="8" column="0" colspan="3">
+         <widget class="QCheckBox" name="connectAudioCheckBox">
+          <property name="toolTip">
+           <string>Connect the Jack client to the default system audio ports.</string>
+          </property>
+          <property name="text">
+           <string>&amp;Connect default audio ports</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1" colspan="2">
+         <widget class="QSpinBox" name="localPortSpinBox">
+          <property name="toolTip">
+           <string>Set the local port to use for the connection. The default is 4464.
+(Useful for running multiple hub clients behind the same router.)</string>
+          </property>
+          <property name="minimum">
+           <number>1024</number>
+          </property>
+          <property name="maximum">
+           <number>65535</number>
+          </property>
+          <property name="value">
+           <number>4464</number>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="1" colspan="2">
+         <widget class="QSpinBox" name="remotePortSpinBox">
+          <property name="toolTip">
+           <string>Set the remote port to use for the connection. The default is 4464.</string>
+          </property>
+          <property name="minimum">
+           <number>1024</number>
+          </property>
+          <property name="maximum">
+           <number>65535</number>
+          </property>
+          <property name="value">
+           <number>4464</number>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="0">
+         <widget class="QLabel" name="basePortLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;UDP Base Port</string>
+          </property>
+          <property name="buddy">
+           <cstring>basePortSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QLabel" name="localPortLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Local Port</string>
+          </property>
+          <property name="buddy">
+           <cstring>localPortSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="6" column="1" colspan="2">
+         <widget class="QSpinBox" name="redundancySpinBox">
+          <property name="toolTip">
+           <string>Number of redundant packets to be sent to avoid glitches related to packet loss.</string>
+          </property>
+          <property name="minimum">
+           <number>1</number>
+          </property>
+          <property name="value">
+           <number>1</number>
+          </property>
+         </widget>
+        </item>
+        <item row="11" column="2">
+         <widget class="QLabel" name="ioStatsLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Reporting &amp;Interval (s)</string>
+          </property>
+          <property name="buddy">
+           <cstring>ioStatsSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="5" column="1" colspan="2">
+         <widget class="QSpinBox" name="queueLengthSpinBox">
+          <property name="toolTip">
+           <string>Set the queue buffer length, in packet size.</string>
+          </property>
+          <property name="minimum">
+           <number>2</number>
+          </property>
+          <property name="value">
+           <number>4</number>
+          </property>
+         </widget>
+        </item>
+        <item row="12" column="0" colspan="3">
+         <widget class="QCheckBox" name="verboseCheckBox">
+          <property name="text">
+           <string>Show &amp;Debug Information</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="backendTab">
+       <attribute name="title">
+        <string>Audio Backend</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_11">
+        <item row="0" column="0">
+         <widget class="QLabel" name="backendLabel">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Audio &amp;Backend:</string>
+          </property>
+          <property name="buddy">
+           <cstring>backendComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1">
+         <widget class="QComboBox" name="backendComboBox">
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Choose the audio backend to use. JACK is the default and is well tested, but requires the JACK audio server to be installed.&lt;/p&gt;&lt;p&gt;RtAudio is still a work in progress, but it works with your operating system's native audio drivers and requires no additional software.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <item>
+           <property name="text">
+            <string>JACK</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>RtAudio</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="1" column="0">
+         <widget class="QLabel" name="sampleRateLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Sampling Rate:</string>
+          </property>
+          <property name="buddy">
+           <cstring>sampleRateComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1">
+         <widget class="QComboBox" name="sampleRateComboBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the audio sample rate to use with the RtAudio backend. This setting should be the same on both ends of the connection.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="currentText">
+           <string>48000</string>
+          </property>
+          <property name="currentIndex">
+           <number>3</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>22050</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>32000</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>44100</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>48000</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>88200</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>96000</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>192000</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QLabel" name="bufferSizeLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Buffer Size:</string>
+          </property>
+          <property name="buddy">
+           <cstring>bufferSizeComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1">
+         <widget class="QComboBox" name="bufferSizeComboBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Set the driver's buffer size to use with the RtAudio backend.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="currentIndex">
+           <number>3</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>16</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>32</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>64</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>128</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>256</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>512</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>1024</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="3" column="0">
+         <widget class="QLabel" name="inputDeviceLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Input Device:</string>
+          </property>
+          <property name="buddy">
+           <cstring>inputDeviceComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="1">
+         <widget class="QComboBox" name="inputDeviceComboBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="0">
+         <widget class="QLabel" name="outputDeviceLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>&amp;Output Device:</string>
+          </property>
+          <property name="buddy">
+           <cstring>outputDeviceComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="1">
+         <widget class="QComboBox" name="outputDeviceComboBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="5" column="1">
+         <spacer name="backendSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>444</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="8" column="0" colspan="2">
+         <layout class="QHBoxLayout" name="deviceManagementLayout">
+          <item>
+           <spacer name="backendTabSpacer">
+            <property name="orientation">
+             <enum>Qt::Horizontal</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>40</width>
+              <height>20</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+          <item>
+           <widget class="QPushButton" name="refreshDevicesButton">
+            <property name="text">
+             <string>&amp;Refresh Device List</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="JitterTab">
+       <attribute name="title">
+        <string>Jitter Buffer</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout_8">
+        <item row="10" column="2">
+         <widget class="QLabel" name="packetsLabel">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="text">
+           <string>Packets</string>
+          </property>
+         </widget>
+        </item>
+        <item row="8" column="0" colspan="3">
+         <widget class="QCheckBox" name="autoQueueCheckBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="text">
+           <string>Automatically set the &amp;queue length</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="9" column="0" colspan="2">
+         <widget class="QLabel" name="autoQueueLabel">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Aim to &amp;drop no more than one in every</string>
+          </property>
+          <property name="buddy">
+           <cstring>autoQueueSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="5" column="0" colspan="3">
+         <widget class="Line" name="bufferLine">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="orientation">
+           <enum>Qt::Horizontal</enum>
+          </property>
+         </widget>
+        </item>
+        <item row="9" column="2">
+         <widget class="QSpinBox" name="autoQueueSpinBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="maximum">
+           <number>1000000</number>
+          </property>
+          <property name="singleStep">
+           <number>100</number>
+          </property>
+          <property name="value">
+           <number>500</number>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0" colspan="3">
+         <widget class="QCheckBox" name="broadcastCheckBox">
+          <property name="toolTip">
+           <string>Enable a second, broadcast output with a higher queue length
+for better quality at the expense of latency.</string>
+          </property>
+          <property name="text">
+           <string>Enable &amp;Broadcast Output</string>
+          </property>
+         </widget>
+        </item>
+        <item row="12" column="0">
+         <spacer name="verticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="11" column="0" colspan="3">
+         <widget class="QLabel" name="autoQueueExplanationLabel">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="text">
+           <string>This will override the queue buffer length entered in the advanced options tab. (The default value is 500.)</string>
+          </property>
+          <property name="wordWrap">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="0" colspan="2">
+         <widget class="QCheckBox" name="jitterCheckBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="toolTip">
+           <string>Enable the new jitter buffer. This is now the default.</string>
+          </property>
+          <property name="text">
+           <string>Enable &amp;Jitter Buffer</string>
+          </property>
+          <property name="checked">
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1" colspan="2">
+         <widget class="QComboBox" name="bufferStrategyComboBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="toolTip">
+           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Buffer strategy 1 attempts to drop as little audio data as possible without exceeding the maximum queue length. It operates very similarly to the original buffer implementation with a few fixes to drop even less audio.&lt;/p&gt;&lt;p&gt;Buffer strategy 2 is optimized to keep the latency stable, so that the delay experienced over the connection doesn't fluctuate and is as predictable as possible. The trade off is that more audio might be dropped, but the difference should be negligible with the right queue length.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          </property>
+          <property name="currentIndex">
+           <number>0</number>
+          </property>
+          <item>
+           <property name="text">
+            <string>1</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>2</string>
+           </property>
+          </item>
+          <item>
+           <property name="text">
+            <string>3 (experimental)</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+        <item row="2" column="0">
+         <widget class="QLabel" name="bufferStrategyLabel">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text">
+           <string>Use buffer &amp;strategy</string>
+          </property>
+          <property name="buddy">
+           <cstring>bufferStrategyComboBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="0">
+         <widget class="QLabel" name="broadcastQueueLabel">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="text">
+           <string>Broadcast &amp;Queue Length</string>
+          </property>
+          <property name="buddy">
+           <cstring>broadcastQueueSpinBox</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="1" colspan="2">
+         <widget class="QSpinBox" name="broadcastQueueSpinBox">
+          <property name="enabled">
+           <bool>false</bool>
+          </property>
+          <property name="toolTip">
+           <string>Set the broadcast queue buffer length, in packet size.</string>
+          </property>
+          <property name="value">
+           <number>8</number>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="pluginsTab">
+       <attribute name="title">
+        <string>Plugins</string>
+       </attribute>
+       <layout class="QVBoxLayout" name="verticalLayout">
+        <item>
+         <widget class="QGroupBox" name="incomingGroupBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="title">
+           <string>Incoming</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_5">
+           <item row="1" column="1">
+            <widget class="QSlider" name="inZitarevWetnessSlider">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Set the wet/dry mix.</string>
+             </property>
+             <property name="maximum">
+              <number>100</number>
+             </property>
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="tickPosition">
+              <enum>QSlider::TicksBelow</enum>
+             </property>
+             <property name="tickInterval">
+              <number>20</number>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="2">
+            <widget class="QLabel" name="inFreeverbLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Wetness</string>
+             </property>
+            </widget>
+           </item>
+           <item row="4" column="0">
+            <widget class="QCheckBox" name="inLimiterCheckBox">
+             <property name="toolTip">
+              <string>Enable the limiter on incoming audio.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Limiter</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="0">
+            <widget class="QCheckBox" name="inFreeverbCheckBox">
+             <property name="toolTip">
+              <string>Enable the freeverb plugin on incoming audio.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Freeverb</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="2" alignment="Qt::AlignHCenter">
+            <widget class="QLabel" name="inZitarevLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Wetness</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QCheckBox" name="inCompressorCheckBox">
+             <property name="toolTip">
+              <string>Enable the compressor plugin on incoming audio.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Compressor</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QCheckBox" name="inZitarevCheckBox">
+             <property name="toolTip">
+              <string>Enable the zitarev reverb plugin on incoming audio.</string>
+             </property>
+             <property name="text">
+              <string>&amp;Zitarev</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QSlider" name="inFreeverbWetnessSlider">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Set the wet/dry mix.</string>
+             </property>
+             <property name="maximum">
+              <number>100</number>
+             </property>
+             <property name="singleStep">
+              <number>1</number>
+             </property>
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="invertedAppearance">
+              <bool>false</bool>
+             </property>
+             <property name="tickPosition">
+              <enum>QSlider::TicksBelow</enum>
+             </property>
+             <property name="tickInterval">
+              <number>20</number>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item>
+         <widget class="QGroupBox" name="outgoingGroupBox">
+          <property name="enabled">
+           <bool>true</bool>
+          </property>
+          <property name="title">
+           <string>Outgoing</string>
+          </property>
+          <layout class="QGridLayout" name="gridLayout_2">
+           <item row="0" column="0">
+            <widget class="QCheckBox" name="outFreeverbCheckBox">
+             <property name="toolTip">
+              <string>Enable the freeverb plugin on outgoing audio.</string>
+             </property>
+             <property name="text">
+              <string>Free&amp;verb</string>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="1">
+            <widget class="QSlider" name="outFreeverbWetnessSlider">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Set the wet/dry mix.</string>
+             </property>
+             <property name="maximum">
+              <number>100</number>
+             </property>
+             <property name="singleStep">
+              <number>1</number>
+             </property>
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="invertedAppearance">
+              <bool>false</bool>
+             </property>
+             <property name="tickPosition">
+              <enum>QSlider::TicksBelow</enum>
+             </property>
+             <property name="tickInterval">
+              <number>20</number>
+             </property>
+            </widget>
+           </item>
+           <item row="0" column="2">
+            <widget class="QLabel" name="outFreeverbLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Wetness</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="0">
+            <widget class="QCheckBox" name="outZitarevCheckBox">
+             <property name="toolTip">
+              <string>Enable the zitarev reverb plugin on outgoing audio.</string>
+             </property>
+             <property name="text">
+              <string>Zi&amp;tarev</string>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="1">
+            <widget class="QSlider" name="outZitarevWetnessSlider">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Set the wet/dry mix.</string>
+             </property>
+             <property name="maximum">
+              <number>100</number>
+             </property>
+             <property name="orientation">
+              <enum>Qt::Horizontal</enum>
+             </property>
+             <property name="tickPosition">
+              <enum>QSlider::TicksBelow</enum>
+             </property>
+             <property name="tickInterval">
+              <number>20</number>
+             </property>
+            </widget>
+           </item>
+           <item row="1" column="2">
+            <widget class="QLabel" name="outZitarevLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Moisture is the essence of wetness,
+and wetness is the essence of beauty.</string>
+             </property>
+             <property name="text">
+              <string>Wetness</string>
+             </property>
+            </widget>
+           </item>
+           <item row="2" column="0">
+            <widget class="QCheckBox" name="outCompressorCheckBox">
+             <property name="toolTip">
+              <string>Enable the compressor plugin on outgoing audio.</string>
+             </property>
+             <property name="text">
+              <string>Com&amp;pressor</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="0">
+            <widget class="QCheckBox" name="outLimiterCheckBox">
+             <property name="toolTip">
+              <string>Enable the limiter on outgoing audio.</string>
+             </property>
+             <property name="text">
+              <string>Li&amp;miter</string>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="1">
+            <widget class="QSpinBox" name="outClientsSpinBox">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="toolTip">
+              <string>Enter the anticipated number of clients that will be connected to the server.</string>
+             </property>
+             <property name="minimum">
+              <number>1</number>
+             </property>
+             <property name="maximum">
+              <number>100</number>
+             </property>
+             <property name="value">
+              <number>2</number>
+             </property>
+            </widget>
+           </item>
+           <item row="3" column="2">
+            <widget class="QLabel" name="outLimiterLabel">
+             <property name="enabled">
+              <bool>false</bool>
+             </property>
+             <property name="text">
+              <string>Clients</string>
+             </property>
+            </widget>
+           </item>
+          </layout>
+         </widget>
+        </item>
+        <item>
+         <spacer name="pluginsVerticalSpacer">
+          <property name="orientation">
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" stdset="0">
+           <size>
+            <width>20</width>
+            <height>40</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </widget>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menuBar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>409</width>
+     <height>30</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <tabstops>
+  <tabstop>typeComboBox</tabstop>
+  <tabstop>addressComboBox</tabstop>
+  <tabstop>connectButton</tabstop>
+  <tabstop>disconnectButton</tabstop>
+  <tabstop>exitButton</tabstop>
+  <tabstop>optionsTabWidget</tabstop>
+  <tabstop>channelRecvSpinBox</tabstop>
+  <tabstop>channelSendSpinBox</tabstop>
+  <tabstop>autoPatchComboBox</tabstop>
+  <tabstop>zeroCheckBox</tabstop>
+  <tabstop>timeoutCheckBox</tabstop>
+  <tabstop>requireAuthCheckBox</tabstop>
+  <tabstop>certEdit</tabstop>
+  <tabstop>certBrowse</tabstop>
+  <tabstop>keyEdit</tabstop>
+  <tabstop>keyBrowse</tabstop>
+  <tabstop>credsEdit</tabstop>
+  <tabstop>credsBrowse</tabstop>
+  <tabstop>authCheckBox</tabstop>
+  <tabstop>usernameEdit</tabstop>
+  <tabstop>passwordEdit</tabstop>
+  <tabstop>aboutButton</tabstop>
+  <tabstop>clientNameEdit</tabstop>
+  <tabstop>remoteNameEdit</tabstop>
+  <tabstop>localPortSpinBox</tabstop>
+  <tabstop>remotePortSpinBox</tabstop>
+  <tabstop>basePortSpinBox</tabstop>
+  <tabstop>queueLengthSpinBox</tabstop>
+  <tabstop>redundancySpinBox</tabstop>
+  <tabstop>resolutionComboBox</tabstop>
+  <tabstop>connectAudioCheckBox</tabstop>
+  <tabstop>realTimeCheckBox</tabstop>
+  <tabstop>ioStatsCheckBox</tabstop>
+  <tabstop>ioStatsSpinBox</tabstop>
+  <tabstop>verboseCheckBox</tabstop>
+  <tabstop>commandLineButton</tabstop>
+  <tabstop>useDefaultsButton</tabstop>
+  <tabstop>backendComboBox</tabstop>
+  <tabstop>sampleRateComboBox</tabstop>
+  <tabstop>bufferSizeComboBox</tabstop>
+  <tabstop>inputDeviceComboBox</tabstop>
+  <tabstop>outputDeviceComboBox</tabstop>
+  <tabstop>refreshDevicesButton</tabstop>
+  <tabstop>jitterCheckBox</tabstop>
+  <tabstop>bufferStrategyComboBox</tabstop>
+  <tabstop>broadcastCheckBox</tabstop>
+  <tabstop>broadcastQueueSpinBox</tabstop>
+  <tabstop>autoQueueCheckBox</tabstop>
+  <tabstop>autoQueueSpinBox</tabstop>
+  <tabstop>inFreeverbCheckBox</tabstop>
+  <tabstop>inFreeverbWetnessSlider</tabstop>
+  <tabstop>inZitarevCheckBox</tabstop>
+  <tabstop>inZitarevWetnessSlider</tabstop>
+  <tabstop>inCompressorCheckBox</tabstop>
+  <tabstop>inLimiterCheckBox</tabstop>
+  <tabstop>outFreeverbCheckBox</tabstop>
+  <tabstop>outFreeverbWetnessSlider</tabstop>
+  <tabstop>outZitarevCheckBox</tabstop>
+  <tabstop>outZitarevWetnessSlider</tabstop>
+  <tabstop>outCompressorCheckBox</tabstop>
+  <tabstop>outLimiterCheckBox</tabstop>
+  <tabstop>outClientsSpinBox</tabstop>
+ </tabstops>
+ <resources>
+  <include location="qjacktrip.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/gui/textbuf.cpp b/src/gui/textbuf.cpp
new file mode 100644 (file)
index 0000000..0fcf1f4
--- /dev/null
@@ -0,0 +1,68 @@
+//*****************************************************************
+/*
+  QJackTrip: Bringing a graphical user interface to JackTrip, a
+  system for high quality audio network performance over the
+  internet.
+
+  Copyright (c) 2021 Aaron Wyatt.
+
+  This file is part of QJackTrip.
+
+  QJackTrip 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 3 of the License, or
+  (at your option) any later version.
+
+  QJackTrip 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 QJackTrip.  If not, see <https://www.gnu.org/licenses/>.
+*/
+//*****************************************************************
+
+#include "textbuf.h"
+
+void textbuf::setOutStream(std::ostream* output)
+{
+    m_outStream = output;
+}
+
+int textbuf::overflow(int c)
+{
+    //Output our buffer.
+    putChars(pbase(), pptr());
+    
+    if (c != traits_t::eof()) {
+        char out = c;
+        putChars(&out, &out + 1);
+    }
+    
+    //Set buffer to empty again
+    setp(m_buf, m_buf + BUF_SIZE);
+    
+    return c;
+}
+
+int textbuf::sync()
+{
+    //Flush our buffer.
+    putChars(pbase(), pptr());
+    setp(m_buf, m_buf + BUF_SIZE);
+    return 0;
+}
+
+void textbuf::putChars(const char* begin, const char* end)
+{
+    if (m_outStream) {
+        for (const char* c = begin; c < end; c++) {
+            *m_outStream << *c;
+        }
+        m_outStream->flush();
+    }
+    
+    emit outputString(QString(QByteArray(begin, end - begin)));
+}
+
diff --git a/src/gui/textbuf.h b/src/gui/textbuf.h
new file mode 100644 (file)
index 0000000..b0326f6
--- /dev/null
@@ -0,0 +1,61 @@
+//*****************************************************************
+/*
+  QJackTrip: Bringing a graphical user interface to JackTrip, a
+  system for high quality audio network performance over the
+  internet.
+
+  Copyright (c) 2021 Aaron Wyatt.
+
+  This file is part of QJackTrip.
+
+  QJackTrip 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 3 of the License, or
+  (at your option) any later version.
+
+  QJackTrip 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 QJackTrip.  If not, see <https://www.gnu.org/licenses/>.
+*/
+//*****************************************************************
+
+#ifndef TEXTBUF_H
+#define TEXTBUF_H
+
+#include <streambuf>
+#include <iostream>
+#include <QPlainTextEdit>
+
+//Extension of a stream buffer to output to a QTextEdit
+class textbuf : public QObject, public std::basic_streambuf<char, std::char_traits<char>>
+{
+    Q_OBJECT
+    
+   public:
+    textbuf() { setp(m_buf, m_buf + BUF_SIZE); }
+    
+    void setOutStream(std::ostream *output);
+
+   signals:
+    void outputString(const QString& output);
+    
+   protected:
+    virtual int overflow(int c = traits_t::eof());
+    virtual int sync();
+    
+   private:
+    typedef std::char_traits<char> traits_t;
+    
+    static const size_t BUF_SIZE = 64;
+    char m_buf[BUF_SIZE];
+    
+    std::ostream *m_outStream = nullptr;
+    
+    void putChars(const char* begin, const char* end);
+};
+
+#endif  // TEXTBUF_H
index 25580457463cdd5b4c7f94683d7c33fe05b7fd94..6f222f739c46a09f1e6bc6bbb173962fea143bc1 100644 (file)
@@ -44,7 +44,7 @@
 /// \todo Add this namespace
 // namespace JackTrip
 
-constexpr const char* const gVersion = "1.4.1";  ///< JackTrip version
+constexpr const char* const gVersion = "1.4.2";  ///< JackTrip version
 
 //*******************************************************************************
 /// \name Default Values
index 9939ca3eed22f218e068b23b13704a9c412cdaf3..044af97185c6d3d9b00154e64e853cc386052cd2 100644 (file)
@@ -39,6 +39,7 @@
 #include <QApplication>
 
 #include "gui/qjacktrip.h"
+#include <QCommandLineParser>
 #else
 #include <QCoreApplication>
 #endif
 #include "UdpHubListener.h"
 #include "jacktrip_globals.h"
 
+#ifdef __WIN_32__
+#include <windows.h>
+#include <psapi.h>
+#include <tlhelp32.h>
+#endif
+
 QCoreApplication* createApplication(int& argc, char* argv[])
 {
     // Check for some specific, GUI related command line options.
@@ -154,6 +161,49 @@ BOOL WINAPI windowsCtrlHandler(DWORD fdwCtrlType)
         return false;
     }
 }
+
+bool isRunFromCmd() {
+    //Get our parent process pid
+    HANDLE h = NULL;
+    PROCESSENTRY32 pe = {0};
+    DWORD pid = GetCurrentProcessId();
+    DWORD ppid = 0;
+    pe.dwSize = sizeof(PROCESSENTRY32);
+    h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    if (Process32First(h, &pe)) {
+        do {
+            //Loop through the list of processes until we find ours.
+            if (pe.th32ProcessID == pid) {
+                ppid = pe.th32ParentProcessID;
+                break;
+            }
+        } while (Process32Next(h, &pe));
+    }
+    CloseHandle(h);
+    
+    //Get the name of our parent process;
+    char pname[MAX_PATH] = {0};
+    DWORD size = MAX_PATH;
+    h = NULL;
+    h = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, ppid);
+    if (h) {
+        if (QueryFullProcessImageNameA(h, 0, pname, &size)) {
+            CloseHandle(h);
+            
+            //Check if our parent process is a command line.
+            if (size >= 14 && strncmp(pname + size - 14, "powershell.exe", 14) == 0) {
+                return true;
+            }
+            if (size >= 7 && strncmp(pname + size - 7, "cmd.exe", 7) == 0) {
+                return true;
+            }
+        } else {
+            CloseHandle(h);
+        }
+    }
+    
+    return false;
+}
 #endif
 
 int main(int argc, char* argv[])
@@ -166,10 +216,21 @@ int main(int argc, char* argv[])
     if (qobject_cast<QApplication*>(app.data())) {
         // Start the GUI if there are no command line options.
 #ifdef __WIN_32__
-        // Remove the console that appears if we're in windows.
-        FreeConsole();
+        // Remove the console that appears if we're on windows and not running from a command line.
+        if (!isRunFromCmd()) {
+            FreeConsole();
+        }
 #endif  // __WIN_32__
         app->setApplicationName("QJackTrip");
+        
+        QCommandLineParser parser;
+        QCommandLineOption verboseOption(QStringList() << "V" << "verbose");   
+        parser.addOption(verboseOption);
+        parser.parse(app->arguments());
+        if (parser.isSet(verboseOption)) {
+            gVerboseFlag = true;
+        }
+        
         window.reset(new QJackTrip);
         window->setArgc(argc);
         QObject::connect(window.data(), &QJackTrip::signalExit, app.data(),
index cdb4fb23738c8174dcb1d2730b412e52eee9f3f9..5aeba8f89ebb530950f20539503552a530e7e3c8 100644 (file)
@@ -1,6 +1,9 @@
-[wrap-git]
-url=https://github.com/thestk/rtaudio.git
-revision=head
+[wrap-file]
+directory = rtaudio-5.2.0
+source_url = https://github.com/thestk/rtaudio/archive/refs/tags/5.2.0.tar.gz
+source_filename = 5.2.0.tar.gz
+source_hash = a8d9c738addffd485c3f0bab14cbba72600267e3113f274398c67829bbb49332
 
 [provide]
 dependency_names = rtaudio
+