New upstream version 1.5.0+ds0
authorIOhannes m zmölnig <zmoelnig@umlautS.umlaeute.mur.at>
Mon, 3 Jan 2022 16:13:29 +0000 (17:13 +0100)
committerIOhannes m zmölnig <zmoelnig@umlautS.umlaeute.mur.at>
Mon, 3 Jan 2022 16:13:29 +0000 (17:13 +0100)
docs/changelog.yml
src/Patcher.cpp
src/Patcher.h
src/Settings.cpp
src/Settings.h
src/UdpHubListener.h
src/gui/qjacktrip.cpp
src/gui/qjacktrip.ui
src/gui/qjacktrip_novs.ui
src/jacktrip_globals.h

index ba5cb3f0a0da73819ae686215011b8878ca7b48c..636ad51d690c75392376ad6b40d45b49e62906e5 100644 (file)
@@ -1,3 +1,7 @@
+- Version: "1.5.0"
+  Date: 2022-01-03
+  Description:
+  - (added) option to upmix mono clients to stereo in hub server mode patching
 - Version: "1.4.3"
   Date: 2021-12-18
   Description:
index daa47a779a479d86818ee927411581cc15369ae1..d8083a63261dfdedf36399cd94f1d0ebb1967311 100644 (file)
  */
 
 #include "Patcher.h"
-
-Patcher::Patcher() : m_patchMode(JackTrip::SERVERTOCLIENT), m_jackClient(nullptr) {}
+#include <QVector>
 
 void Patcher::setPatchMode(JackTrip::hubConnectionModeT patchMode)
 {
     m_patchMode = patchMode;
 }
 
+void Patcher::setStereoUpmix(bool upmix)
+{
+    m_steroUpmix = upmix;
+}
+
 void Patcher::registerClient(const QString& clientName)
 {
     QMutexLocker locker(&m_connectionMutex);
@@ -71,29 +75,52 @@ void Patcher::registerClient(const QString& clientName)
     outPorts = jack_get_ports(m_jackClient, NULL, NULL, JackPortIsOutput);
     inPorts  = jack_get_ports(m_jackClient, NULL, NULL, JackPortIsInput);
 
-    // Start with our receiving ports.
+    // Find the ports belonging to our client.
+    QVector<const char*> clientOutPorts;
+    QVector<const char*> clientInPorts;
+    
     for (int i = 0; outPorts[i]; i++) {
-        QString client = QString(outPorts[i]).section(":", 0, 0);
-        if (client == clientName) {
-            QString channel = QString(outPorts[i]).section("_", -1, -1);
-            for (int j = 0; inPorts[j]; j++) {
-                // First check if this is one of our other clients. (Fan out/in and full
-                // mix.)
-                if (m_patchMode == JackTrip::CLIENTFOFI
-                    || m_patchMode == JackTrip::FULLMIX) {
-                    if (m_clients.contains(QString(inPorts[j]).section(":", 0, 0))
-                        && QString(inPorts[j]).section("_", -1, -1) == channel
-                        && !QString(outPorts[i]).contains("broadcast")) {
-                        jack_connect(m_jackClient, outPorts[i], inPorts[j]);
+        // Exclude broadcast ports.
+        if (QString(outPorts[i]).section(":", 0, 0) == clientName 
+            && !QString(outPorts[i]).contains("broadcast")) {
+            clientOutPorts.append(outPorts[i]);
+        }
+    }
+
+    for (int i = 0; inPorts[i]; i++) {
+        if (QString(inPorts[i]).section(":", 0, 0) == clientName) {
+            clientInPorts.append(inPorts[i]);
+        }
+    }
+
+    bool clientIsMono = (clientOutPorts.count() == 1);
+
+    // Start with our receiving ports.
+    for (int i = 0; i < clientOutPorts.count(); i++) {
+        QString channel = QString(clientOutPorts.at(i)).section("_", -1, -1);
+        for (int j = 0; inPorts[j]; j++) {
+            QString otherClient = QString(inPorts[j]).section(":", 0, 0);
+            QString otherChannel = QString(inPorts[j]).section("_", -1, -1);
+
+            // First check if this is one of our other clients. (Fan out/in and full mix.)
+            if (m_patchMode == JackTrip::CLIENTFOFI || m_patchMode == JackTrip::FULLMIX) {
+                if (m_clients.contains(otherClient) && otherChannel == channel) {
+                    jack_connect(m_jackClient, clientOutPorts.at(i), inPorts[j]);
+                } else if (m_steroUpmix && clientIsMono) {
+                    // Deal with the special case of stereo upmix
+                    if (m_clients.contains(otherClient) && otherChannel == "2") {
+                        jack_connect(m_jackClient, clientOutPorts.at(i), inPorts[j]);
                     }
                 }
-                // Then check if it's our registering client. (Client Echo and full mix.)
-                if (m_patchMode == JackTrip::CLIENTECHO
-                    || m_patchMode == JackTrip::FULLMIX) {
-                    if (QString(inPorts[j]).section(":", 0, 0) == clientName
-                        && QString(inPorts[j]).section("_", -1, -1) == channel
-                        && !QString(outPorts[i]).contains("broadcast")) {
-                        jack_connect(m_jackClient, outPorts[i], inPorts[j]);
+            }
+
+            // Then check if it's our registering client. (Client Echo and full mix.)
+            if (m_patchMode == JackTrip::CLIENTECHO || m_patchMode == JackTrip::FULLMIX) {
+                if (otherClient == clientName && otherChannel == channel) {
+                    jack_connect(m_jackClient, clientOutPorts.at(i), inPorts[j]);
+                } else if (m_steroUpmix && clientIsMono) {
+                    if (otherClient == clientName && otherChannel == "2") {
+                        jack_connect(m_jackClient, clientOutPorts.at(i), inPorts[j]);
                     }
                 }
             }
@@ -101,17 +128,18 @@ void Patcher::registerClient(const QString& clientName)
     }
 
     // Then our sending ports. We only need to check for other clients here.
-    //(Any loopback connections will have been made in the previous loop.)
+    // (Any loopback connections will have been made in the previous loop.)
     if (m_patchMode == JackTrip::CLIENTFOFI || m_patchMode == JackTrip::FULLMIX) {
-        for (int i = 0; inPorts[i]; i++) {
-            QString client = QString(inPorts[i]).section(":", 0, 0);
-            if (client == clientName) {
-                QString channel = QString(inPorts[i]).section("_", -1, -1);
-                for (int j = 0; outPorts[j]; j++) {
-                    if (m_clients.contains(QString(outPorts[j]).section(":", 0, 0))
-                        && QString(outPorts[j]).section("_", -1, -1) == channel
-                        && !QString(outPorts[j]).contains("broadcast")) {
-                        jack_connect(m_jackClient, outPorts[j], inPorts[i]);
+        for (int i = 0; i < clientInPorts.count(); i++) {
+            QString channel = QString(clientInPorts.at(i)).section("_", -1, -1);
+            for (int j = 0; outPorts[j]; j++) {
+                QString otherClient = QString(outPorts[j]).section(":", 0, 0);
+                QString otherChannel = QString(outPorts[j]).section("_", -1, -1);
+                if (m_clients.contains(otherClient)
+                    && !QString(outPorts[j]).contains("broadcast")) {
+                    if (otherChannel == channel || 
+                        (m_steroUpmix && channel == "2" && m_monoClients.contains(otherClient))) {
+                        jack_connect(m_jackClient, outPorts[j], clientInPorts.at(i));
                     }
                 }
             }
@@ -119,6 +147,9 @@ void Patcher::registerClient(const QString& clientName)
     }
 
     m_clients.append(clientName);
+    if (clientIsMono) {
+        m_monoClients.append(clientName);
+    }
     jack_free(outPorts);
     jack_free(inPorts);
 }
@@ -127,6 +158,7 @@ void Patcher::unregisterClient(const QString& clientName)
 {
     QMutexLocker locker(&m_connectionMutex);
     m_clients.removeAll(clientName);
+    m_monoClients.removeAll(clientName);
 }
 
 void Patcher::shutdownCallback(void* arg)
index 52335243bd4321d7bcb5ac10e473814f6e781c7a..276eb59a3075a8e8bc5b084156e0ce989c13e269 100644 (file)
@@ -52,10 +52,11 @@ class Patcher : public QObject
     Q_OBJECT
 
    public:
-    Patcher();
+    Patcher() = default;
     virtual ~Patcher();
 
     void setPatchMode(JackTrip::hubConnectionModeT patchMode);
+    void setStereoUpmix(bool upmix);
 
     void registerClient(const QString& clientName);
     void unregisterClient(const QString& clientName);
@@ -65,9 +66,11 @@ class Patcher : public QObject
 
    private:
     QStringList m_clients;
-    JackTrip::hubConnectionModeT m_patchMode;
+    QStringList m_monoClients;
+    JackTrip::hubConnectionModeT m_patchMode = JackTrip::SERVERTOCLIENT;
+    bool m_steroUpmix = false;
 
-    jack_client_t* m_jackClient;
+    jack_client_t* m_jackClient = nullptr;
     jack_status_t m_status;
 
     QMutex m_connectionMutex;
index d8aa4d98027a906290e5e1f4b9ef10a578ca0fcb..4854d7b3606c2cccbb4de8f8a12dbf47482e8f9f 100644 (file)
@@ -163,6 +163,7 @@ void Settings::parseInput(int argc, char** argv)
         {"verbose", no_argument, NULL, 'V'},  // Verbose mode
         {"hubpatch", required_argument, NULL,
          'p'},  // Set hubConnectionMode for auto patch in Jack
+        {"upmix", no_argument, NULL, 'u'}, // Upmix mono clients when patching
         {"iostat", required_argument, NULL, 'I'},     // Set IO stat timeout
         {"iostatlog", required_argument, NULL, 'G'},  // Set IO stat log file
         {"effects", required_argument, NULL,
@@ -199,7 +200,7 @@ void Settings::parseInput(int argc, char** argv)
     int ch;
     while (
         (ch = getopt_long(argc, argv,
-                          "n:N:H:sc:SC:o:B:P:U:q:r:b:ztlwjeJ:K:RTd:F:p:DvVhI:G:f:O:a:x:A",
+                          "n:N:H:sc:SC:o:B:P:U:q:r:b:ztlwjeJ:K:RTd:F:p:uDvVhI:G:f:O:a:x:A",
                           longopts, NULL))
         != -1)
         switch (ch) {
@@ -450,6 +451,9 @@ void Settings::parseInput(int argc, char** argv)
                 std::exit(1);
             }
             break;
+        case 'u':
+            mStereoUpmix = true;
+            break;
         case 'I':  // IO Stat timeout
             //-------------------------------------------------------
             mIOStatTimeout = atoi(optarg);
@@ -732,6 +736,9 @@ void Settings::printUsage()
             "2=client fan out/in but not loopback, 3=reserved for TUB, 4=full mix, 5=no "
             "auto patching (default: 0)"
          << endl;
+    cout << " -u, --upmix                              Upmix mono clients to stereo when "
+            "patching in HUB SERVER mode"
+         << endl;
     cout << " -z, --zerounderrun                       Set buffer to zeros when underrun "
             "occurs (default: wavetable)"
          << endl;
@@ -869,6 +876,7 @@ UdpHubListener* Settings::getConfiguredHubServer()
     udpHub->setWAIR(mWAIR);
 #endif  // endwhere
     udpHub->setHubPatch(mHubConnectionMode);
+    udpHub->setStereoUpmix(mStereoUpmix);
     // Connect default audio ports must be set after the connection mode.
     udpHub->setConnectDefaultAudioPorts(mConnectDefaultAudioPorts);
     // Set buffers to zero when underrun
index 569ca2717ddb750970a302b6ca587595ac6bb500..88324ffacf37656dd33ef7fbeb2c81b0f49df130 100644 (file)
@@ -123,6 +123,7 @@ class Settings : public QObject
     std::string mInputDeviceName, mOutputDeviceName;
 #endif
     unsigned int mHubConnectionMode = JackTrip::SERVERTOCLIENT;
+    bool mStereoUpmix               = false;
     bool mConnectDefaultAudioPorts  = true;  ///< Connect or not jack audio ports
     int mIOStatTimeout              = 0;
     QSharedPointer<std::ostream> mIOStatStream;
index 07554a8ea6bbf7b716d75d30791cc70231a7485a..a12fcb2c1e2a0717a115907f3b5cb244b7480816 100644 (file)
@@ -184,6 +184,7 @@ class UdpHubListener : public QObject
 #ifndef __NO_JACK__
     Patcher mPatcher;
 #endif
+    bool mStereoUpmix;
 
     int mIOStatTimeout;
     QSharedPointer<std::ostream> mIOStatStream;
@@ -229,6 +230,12 @@ class UdpHubListener : public QObject
         }
     }
     unsigned int getHubPatch() { return mHubPatch; }
+    
+    void setStereoUpmix([[maybe_unused]] bool upmix) {
+#ifndef __NO_JACK__
+        mPatcher.setStereoUpmix(upmix);
+#endif
+    }
 
     void setUnderRunMode(JackTrip::underrunModeT UnderRunMode)
     {
index 0ccb5a3076c77efd4df454ac6efa9c55e81ca720..383b738bfac9da62c7d2919312f4e01ca9dc7fbe 100644 (file)
@@ -224,6 +224,7 @@ QJackTrip::QJackTrip(QWidget* parent)
     //(loadSettings will take care of the UI in all other cases.)
     m_ui->basePortLabel->setVisible(false);
     m_ui->basePortSpinBox->setVisible(false);
+    m_ui->upmixCheckBox->setVisible(false);
     m_ui->requireAuthGroupBox->setVisible(false);
 
 #ifdef __RT_AUDIO__
@@ -473,6 +474,7 @@ void QJackTrip::chooseRunType(int index)
         m_ui->timeoutCheckBox->setVisible(false);
         m_ui->autoPatchComboBox->setVisible(true);
         m_ui->autoPatchLabel->setVisible(true);
+        m_ui->upmixCheckBox->setVisible(true);
         m_ui->requireAuthGroupBox->setVisible(true);
         advancedOptionsForHubServer(true);
         int index = findTab("Plugins");
@@ -489,6 +491,7 @@ void QJackTrip::chooseRunType(int index)
     } else {
         m_ui->autoPatchComboBox->setVisible(false);
         m_ui->autoPatchLabel->setVisible(false);
+        m_ui->upmixCheckBox->setVisible(false);
         m_ui->requireAuthGroupBox->setVisible(false);
         m_ui->channelGroupBox->setVisible(true);
         m_ui->timeoutCheckBox->setVisible(true);
@@ -660,6 +663,7 @@ void QJackTrip::start()
             }
 
             m_udpHub->setHubPatch(hubConnectionMode);
+            m_udpHub->setStereoUpmix(m_ui->upmixCheckBox->isChecked());
 
             if (m_ui->zeroCheckBox->isChecked()) {
                 // Set buffers to zero when underrun
@@ -977,6 +981,7 @@ void QJackTrip::loadSettings()
     }
 
     m_ui->autoPatchComboBox->setCurrentIndex(settings.value("AutoPatchMode", 0).toInt());
+    m_ui->upmixCheckBox->setChecked(settings.value("StereoUpmix", false).toBool());
     m_ui->zeroCheckBox->setChecked(settings.value("ZeroUnderrun", false).toBool());
     m_ui->timeoutCheckBox->setChecked(settings.value("Timeout", false).toBool());
     m_ui->clientNameEdit->setText(settings.value("ClientName", "").toString());
@@ -1102,6 +1107,7 @@ void QJackTrip::saveSettings()
     settings.setValue("ChannelsSend", m_ui->channelSendSpinBox->value());
     settings.setValue("ChannelsRecv", m_ui->channelRecvSpinBox->value());
     settings.setValue("AutoPatchMode", m_ui->autoPatchComboBox->currentIndex());
+    settings.setValue("StereoUpmix", m_ui->upmixCheckBox->isChecked());
     settings.setValue("ZeroUnderrun", m_ui->zeroCheckBox->isChecked());
     settings.setValue("Timeout", m_ui->timeoutCheckBox->isChecked());
     settings.setValue("ClientName", m_ui->clientNameEdit->text());
@@ -1254,6 +1260,9 @@ QString QJackTrip::commandLineFromCurrentOptions()
         if (hubConnectionMode > 0) {
             commandLine.append(QString(" -p %1").arg(hubConnectionMode));
         }
+        if (m_ui->upmixCheckBox->isChecked()) {
+            commandLine.append(" -u");
+        }
     } else {
         if (m_ui->channelSendSpinBox->value() != gDefaultNumInChannels
             || m_ui->channelRecvSpinBox->value() != gDefaultNumOutChannels) {
index 3529a1a4ae4b611a0904423c5f6195f59723b8f9..77d7f315b989795bdae6ebd9859c3e7725ec8b92 100644 (file)
@@ -484,6 +484,13 @@ To connect to a hub server you need to run as a hub client.</string>
           </property>
          </widget>
         </item>
+        <item row="4" column="0" colspan="3">
+         <widget class="QCheckBox" name="upmixCheckBox">
+          <property name="text">
+           <string>&amp;Upmix mono clients to stereo</string>
+          </property>
+         </widget>
+        </item>
        </layout>
       </widget>
       <widget class="QWidget" name="advancedTab">
@@ -1754,6 +1761,7 @@ and wetness is the essence of beauty.</string>
   <tabstop>channelRecvSpinBox</tabstop>
   <tabstop>channelSendSpinBox</tabstop>
   <tabstop>autoPatchComboBox</tabstop>
+  <tabstop>upmixCheckBox</tabstop>
   <tabstop>zeroCheckBox</tabstop>
   <tabstop>timeoutCheckBox</tabstop>
   <tabstop>requireAuthCheckBox</tabstop>
@@ -1806,6 +1814,7 @@ and wetness is the essence of beauty.</string>
   <tabstop>outCompressorCheckBox</tabstop>
   <tabstop>outLimiterCheckBox</tabstop>
   <tabstop>outClientsSpinBox</tabstop>
+  <tabstop>verboseCheckBox</tabstop>
  </tabstops>
  <resources>
   <include location="qjacktrip.qrc"/>
index 9d67bd11dde09217c44697248b980bda72880fe7..7e6b95a5b8f3646143cc39a656e8921bfdf1eb1c 100644 (file)
@@ -558,6 +558,13 @@ To connect to a hub server you need to run as a hub client.</string>
           </property>
          </widget>
         </item>
+        <item row="4" column="0" colspan="3">
+         <widget class="QCheckBox" name="upmixCheckBox">
+          <property name="text">
+           <string>&amp;Upmix mono clients to stereo</string>
+          </property>
+         </widget>
+        </item>
        </layout>
       </widget>
       <widget class="QWidget" name="advancedTab">
@@ -1754,6 +1761,7 @@ and wetness is the essence of beauty.</string>
   <tabstop>channelRecvSpinBox</tabstop>
   <tabstop>channelSendSpinBox</tabstop>
   <tabstop>autoPatchComboBox</tabstop>
+  <tabstop>upmixCheckBox</tabstop>
   <tabstop>zeroCheckBox</tabstop>
   <tabstop>timeoutCheckBox</tabstop>
   <tabstop>requireAuthCheckBox</tabstop>
index 43c03c95f5f17498b044afddfc9abd32f1410f79..7a6a32cf2a38fa284ff24d65d3db4783152b6587 100644 (file)
@@ -40,7 +40,7 @@
 
 #include "AudioInterface.h"
 
-constexpr const char* const gVersion = "1.4.3";  ///< JackTrip version
+constexpr const char* const gVersion = "1.5.0";  ///< JackTrip version
 
 //*******************************************************************************
 /// \name Default Values