|
- /*
- * Simple JACK Audio Meter
- * Copyright (C) 2011-2015 Filipe Coelho <falktx@falktx.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * For a full copy of the GNU General Public License see the COPYING file
- */
-
- #include <QtCore/Qt>
-
- #ifndef Q_COMPILER_LAMBDA
- # define nullptr (0)
- #endif
-
- #define VERSION "0.8.1"
-
- #include "../jack_utils.hpp"
- #include "../widgets/digitalpeakmeter.hpp"
-
- #include <cmath>
- #include <QtGui/QIcon>
- #include <QtWidgets/QApplication>
- #include <QtWidgets/QMessageBox>
-
- // -------------------------------
-
- volatile double x_portValue1 = 0.0;
- volatile double x_portValue2 = 0.0;
- volatile bool x_isOutput = true;
- volatile bool x_needReconnect = false;
- volatile bool x_quitNow = false;
-
- jack_client_t* jClient = nullptr;
- jack_port_t* jPort1 = nullptr;
- jack_port_t* jPort2 = nullptr;
-
- QString gClientName;
-
- // -------------------------------
- // JACK callbacks
-
- int process_callback(const jack_nframes_t nframes, void*)
- {
- float* const jOut1 = (float*)jackbridge_port_get_buffer(jPort1, nframes);
- float* const jOut2 = (float*)jackbridge_port_get_buffer(jPort2, nframes);
-
- for (jack_nframes_t i = 0; i < nframes; i++)
- {
- if (std::abs(jOut1[i]) > x_portValue1)
- x_portValue1 = std::abs(jOut1[i]);
-
- if (std::abs(jOut2[i]) > x_portValue2)
- x_portValue2 = std::abs(jOut2[i]);
- }
-
- return 0;
- }
-
- void port_callback(jack_port_id_t, jack_port_id_t, int, void*)
- {
- if (x_isOutput)
- x_needReconnect = true;
- }
-
- #ifdef HAVE_JACKSESSION
- void session_callback(jack_session_event_t* const event, void* const arg)
- {
- #ifdef Q_OS_LINUX
- QString filepath("cadence-jackmeter");
- Q_UNUSED(arg);
- #else
- QString filepath((char*)arg);
- #endif
-
- event->command_line = strdup(filepath.toUtf8().constData());
-
- jackbridge_session_reply(jClient, event);
-
- if (event->type == JackSessionSaveAndQuit)
- x_quitNow = true;
-
- jackbridge_session_event_free(event);
- }
- #endif
-
- // -------------------------------
- // helpers
-
- void reconnect_ports()
- {
- x_needReconnect = false;
-
- const QString nameIn1(gClientName+":in1");
- const QString nameIn2(gClientName+":in2");
-
- if (x_isOutput)
- {
- jack_port_t* const jPlayPort1 = jackbridge_port_by_name(jClient, x_isOutput ? "system:playback_1" : "system:capture_1");
- jack_port_t* const jPlayPort2 = jackbridge_port_by_name(jClient, x_isOutput ? "system:playback_2" : "system:capture_2");
- std::vector<char*> jPortList1(jackbridge_port_get_all_connections_as_vector(jClient, jPlayPort1));
- std::vector<char*> jPortList2(jackbridge_port_get_all_connections_as_vector(jClient, jPlayPort2));
-
- foreach (char* const& thisPortName, jPortList1)
- {
- jack_port_t* const thisPort = jackbridge_port_by_name(jClient, thisPortName);
-
- if (! (jackbridge_port_is_mine(jClient, thisPort) || jackbridge_port_connected_to(jPort1, thisPortName)))
- jackbridge_connect(jClient, thisPortName, nameIn1.toUtf8().constData());
-
- free(thisPortName);
- }
-
- foreach (char* const& thisPortName, jPortList2)
- {
- jack_port_t* const thisPort = jackbridge_port_by_name(jClient, thisPortName);
-
- if (! (jackbridge_port_is_mine(jClient, thisPort) || jackbridge_port_connected_to(jPort2, thisPortName)))
- jackbridge_connect(jClient, thisPortName, nameIn2.toUtf8().constData());
-
- free(thisPortName);
- }
-
- jPortList1.clear();
- jPortList2.clear();
- }
- else
- {
- if (jackbridge_port_by_name(jClient, "system:capture_1") != nullptr)
- if (! jackbridge_port_connected_to(jPort1, "system:capture_1"))
- jackbridge_connect(jClient, "system:capture_1", nameIn1.toUtf8().constData());
-
- if (jackbridge_port_by_name(jClient, "system:capture_2") != nullptr)
- if (! jackbridge_port_connected_to(jPort2, "system:capture_2"))
- jackbridge_connect(jClient, "system:capture_2", nameIn2.toUtf8().constData());
- }
- }
-
- // -------------------------------
- // Meter class
-
- class MeterW : public DigitalPeakMeter
- {
- public:
- MeterW() : DigitalPeakMeter(nullptr)
- {
- setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
- setWindowTitle(gClientName);
-
- if (x_isOutput)
- setColor(Color::GREEN);
- else
- setColor(Color::BLUE);
-
- setChannels(2);
- setOrientation(VERTICAL);
- setSmoothRelease(1);
-
- displayMeter(1, 0.0f);
- displayMeter(2, 0.0f);
-
- int refresh = float(jackbridge_get_buffer_size(jClient)) / jackbridge_get_sample_rate(jClient) * 1000;
-
- m_peakTimerId = startTimer(refresh > 50 ? refresh : 50);
- }
-
- protected:
- void timerEvent(QTimerEvent* event)
- {
- if (x_quitNow)
- {
- close();
- x_quitNow = false;
- return;
- }
-
- if (event->timerId() == m_peakTimerId)
- {
- displayMeter(1, x_portValue1);
- displayMeter(2, x_portValue2);
- x_portValue1 = 0.0;
- x_portValue2 = 0.0;
-
- if (x_needReconnect)
- reconnect_ports();
- }
-
- QWidget::timerEvent(event);
- }
-
- private:
- int m_peakTimerId;
- };
-
- // -------------------------------
-
- int main(int argc, char* argv[])
- {
- QApplication app(argc, argv);
- app.setApplicationName("JackMeter");
- app.setApplicationVersion(VERSION);
- app.setOrganizationName("Cadence");
- app.setWindowIcon(QIcon(":/scalable/cadence.svg"));
-
- if (app.arguments().contains("-in"))
- x_isOutput = false;
-
- // JACK initialization
- jack_status_t jStatus;
- #ifdef HAVE_JACKSESSION
- jack_options_t jOptions = static_cast<jack_options_t>(JackNoStartServer|JackUseExactName|JackSessionID);
- #else
- jack_options_t jOptions = static_cast<jack_options_t>(JackNoStartServer|JackUseExactName);
- #endif
- jClient = jackbridge_client_open(x_isOutput ? "M" : "Mi", jOptions, &jStatus);
-
- if (! jClient)
- {
- std::string errorString(jackbridge_status_get_error_string(jStatus));
- QMessageBox::critical(nullptr, app.translate("MeterW", "Error"), app.translate("MeterW",
- "Could not connect to JACK, possible reasons:\n"
- "%1").arg(QString::fromStdString(errorString)));
- return 1;
- }
-
- gClientName = jackbridge_get_client_name(jClient);
-
- jPort1 = jackbridge_port_register(jClient, "in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
- jPort2 = jackbridge_port_register(jClient, "in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
-
- jackbridge_set_process_callback(jClient, process_callback, nullptr);
- jackbridge_set_port_connect_callback(jClient, port_callback, nullptr);
- #ifdef HAVE_JACKSESSION
- jackbridge_set_session_callback(jClient, session_callback, argv[0]);
- #endif
- jackbridge_activate(jClient);
-
- reconnect_ports();
-
- // Show GUI
- MeterW gui;
- gui.resize(70, 600);
- gui.show();
- gui.setAttribute(Qt::WA_QuitOnClose);
-
- // App-Loop
- int ret = app.exec();
-
- jackbridge_deactivate(jClient);
- jackbridge_client_close(jClient);
-
- return ret;
- }
|