* [gentoo-commits] repo/proj/guru:master commit in: media-sound/opensoundmeter/files/, media-sound/opensoundmeter/
@ 2023-01-06 8:51 Florian Schmaus
0 siblings, 0 replies; only message in thread
From: Florian Schmaus @ 2023-01-06 8:51 UTC (permalink / raw
To: gentoo-commits
commit: 06c2a1810f75a013607a1c71083922144c7f7ed5
Author: Adrian Schollmeyer <nex+b-g-o <AT> nexadn <DOT> de>
AuthorDate: Wed Jan 4 21:30:13 2023 +0000
Commit: Florian Schmaus <flow <AT> gentoo <DOT> org>
CommitDate: Wed Jan 4 21:30:13 2023 +0000
URL: https://gitweb.gentoo.org/repo/proj/guru.git/commit/?id=06c2a181
media-sound/opensoundmeter: add 1.2.2, 1.2.2_p20220104
Signed-off-by: Adrian Schollmeyer <nex+b-g-o <AT> nexadn.de>
media-sound/opensoundmeter/Manifest | 1 +
.../files/opensoundmeter-deadlock-fix.patch | 64 ++
.../files/opensoundmeter-jack-support.patch | 668 +++++++++++++++++++++
.../opensoundmeter/opensoundmeter-1.2.2.ebuild | 60 ++
.../opensoundmeter-1.2.2_p20220104.ebuild | 76 +++
5 files changed, 869 insertions(+)
diff --git a/media-sound/opensoundmeter/Manifest b/media-sound/opensoundmeter/Manifest
index 3d1338830..1cbf64c3a 100644
--- a/media-sound/opensoundmeter/Manifest
+++ b/media-sound/opensoundmeter/Manifest
@@ -1 +1,2 @@
DIST opensoundmeter-1.2.1.gh.tar.gz 41006647 BLAKE2B a3ab132f8a90497132dae3144dd91d162111754e79056bb95ae2f638f65dc6074d2dbc1739c07897f6b2771edfe82c284aea1a48cc9af9454a91698c6915fb5b SHA512 41701377b5df85e08664b68fe102cb6da5d57e70c0366bb5aafc681c926ba7da0622cceb218998bd677e3313f2727b7ecfcb4fcfb5f80fa1fd87334e2a27c377
+DIST opensoundmeter-1.2.2.gh.tar.gz 41041122 BLAKE2B f04441b5d672bb3f2dfcafcd0a69a272f2196972eff5ec99f3990c822edb35513bc9c27e07adeb58711a5355c1de280433f39baf0002ce3a9424c507988f758e SHA512 3cc848133b51a0409401347bdfccfe12b82b7fb07b8925593ee5b14053ac51ccb84c71960fc0d6e888f7a31baa78dba970588150a41a5f5d13fa54792806edc9
diff --git a/media-sound/opensoundmeter/files/opensoundmeter-deadlock-fix.patch b/media-sound/opensoundmeter/files/opensoundmeter-deadlock-fix.patch
new file mode 100644
index 000000000..4719fd788
--- /dev/null
+++ b/media-sound/opensoundmeter/files/opensoundmeter-deadlock-fix.patch
@@ -0,0 +1,64 @@
+diff --git a/src/audio/plugins/alsa.cpp b/src/audio/plugins/alsa.cpp
+index 9987ba3..61537f2 100644
+--- a/src/audio/plugins/alsa.cpp
++++ b/src/audio/plugins/alsa.cpp
+@@ -16,6 +16,7 @@
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+ #include "alsa.h"
++#include <cassert>
+ #include <cstring>
+ #include <QCoreApplication>
+ #define ALSA_BUFFER_SIZE 1024
+@@ -175,23 +176,26 @@ Format AlsaPlugin::deviceFormat(const DeviceInfo::Id &id, const Plugin::Directio
+ Stream *AlsaPlugin::open(const DeviceInfo::Id &id, const Plugin::Direction &mode, const Format &format,
+ QIODevice *endpoint)
+ {
+- std::lock_guard<std::mutex> lock(m_deviceListMutex);
++ std::unique_lock<std::mutex> lock(m_deviceListMutex, std::defer_lock);
+ if (id.isNull()) {
+ return nullptr;
+ }
+
++ assert(!lock.owns_lock());
++ lock.lock();
+ AlsaPCMDevice *device = m_devices[ {mode, id}];
+ if (!device) {
+ device = new AlsaPCMDevice(id, mode, format, m_deviceListMutex);
+ connect (device, &AlsaPCMDevice::closed, this, [this, mode, id, device]() {
+- //mutex is locked here by device
++ std::lock_guard<std::mutex> lock{m_deviceListMutex};
+ m_devices[ {mode, id}] = nullptr;
+ device->deleteLater();
+- m_deviceListMutex.unlock();
+ });
+
+ m_devices[ {mode, id}] = device;
+ }
++ assert(lock.owns_lock());
++ lock.unlock();
+ if (!device->start()) {
+ return nullptr;
+ }
+@@ -326,14 +330,18 @@ bool AlsaPCMDevice::start()
+ }
+ QCoreApplication::processEvents();
+ if (m_callbacks.empty()) {
+- m_mutex.lock();
++ std::unique_lock<std::mutex> lock{m_mutex};
+ if (m_keepAlive) {
++ lock.unlock();
+ QCoreApplication::processEvents();
++ lock.lock();
+ } else {
+- m_threadActive = false;
++ assert(lock.owns_lock());
++ lock.unlock();
+ break;
+ }
+- m_mutex.unlock();
++ assert(lock.owns_lock());
++ lock.unlock();
+ }
+ m_threadActive = true;
+ m_keepAlive = false;
diff --git a/media-sound/opensoundmeter/files/opensoundmeter-jack-support.patch b/media-sound/opensoundmeter/files/opensoundmeter-jack-support.patch
new file mode 100644
index 000000000..b5c7ad9c9
--- /dev/null
+++ b/media-sound/opensoundmeter/files/opensoundmeter-jack-support.patch
@@ -0,0 +1,668 @@
+diff --git a/.travis.yml b/.travis.yml
+index ce9e997..2b6fbe4 100644
+--- a/.travis.yml
++++ b/.travis.yml
+@@ -10,11 +10,12 @@ before_install:
+ install:
+ - sudo apt-get install build-essential libgl1-mesa-dev
+ - sudo apt-get install qt514base qt514multimedia qt514quickcontrols2
++ - sudo apt-get install libjack-dev
+ - source /opt/qt514/bin/qt514-env.sh
+
+
+ script:
+- - /opt/qt514/bin/qmake PREFIX=/usr
++ - /opt/qt514/bin/qmake PREFIX=/usr CONFIG+=jack
+ - make
+ - # Generate AppImage
+ # - sudo apt-get -y install checkinstall
+diff --git a/OpenSoundMeter.pro b/OpenSoundMeter.pro
+index a52b502..f9cef4a 100644
+--- a/OpenSoundMeter.pro
++++ b/OpenSoundMeter.pro
+@@ -300,6 +300,18 @@ unix:!macx:!ios {
+ src/audio/plugins/alsa.cpp
+
+ LIBS += -lasound
++
++ CONFIG(jack) {
++ HEADERS += \
++ src/audio/plugins/jack.h
++
++ SOURCES += \
++ src/audio/plugins/jack.cpp
++
++ LIBS += -ljack
++
++ DEFINES += USE_JACK
++ }
+ }
+
+ GRAPH = $$(GRAPH_BACKEND)
+diff --git a/src/audio/client.cpp b/src/audio/client.cpp
+index d319c72..db7c377 100644
+--- a/src/audio/client.cpp
++++ b/src/audio/client.cpp
+@@ -35,6 +35,10 @@
+ #include "plugins/alsa.h"
+ #endif
+
++#ifdef USE_JACK
++#include "plugins/jack.h"
++#endif
++
+ #ifdef USE_ASIO
+ #include "plugins/asioplugin.h"
+ #endif
+@@ -89,6 +93,10 @@ void Client::initPlugins()
+ m_plugins.push_back(QSharedPointer<Plugin>(new AlsaPlugin()));
+ #endif
+
++#ifdef USE_JACK
++ m_plugins.push_back(QSharedPointer<Plugin>(new JackPlugin()));
++#endif
++
+ for (auto &&plugin : m_plugins) {
+ connect(plugin.data(), &Plugin::deviceListChanged, this, [this]() {
+ refreshDeviceList();
+diff --git a/src/audio/plugins/jack.cpp b/src/audio/plugins/jack.cpp
+new file mode 100644
+index 0000000..3a87edf
+--- /dev/null
++++ b/src/audio/plugins/jack.cpp
+@@ -0,0 +1,462 @@
++/**
++ * OSM
++ * Copyright (C) 2022 Adrian Schollmeyer
++
++ * 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 3 of the License, or
++ * (at your option) any later version.
++
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++#include "jack.h"
++#include <algorithm>
++#include <cassert>
++
++namespace {
++constexpr unsigned int DEFAULT_SAMPLE_RATE{48000};
++constexpr unsigned int DEFAULT_CHANNEL_COUNT_INPUT{2};
++constexpr unsigned int DEFAULT_CHANNEL_COUNT_OUTPUT{1};
++
++constexpr const char* PLUGIN_NAME{"JACK"};
++constexpr const char* JACK_CLIENT_NAME{"OpenSoundMeter"};
++constexpr const char* DEFAULT_MEASUREMENT_CHANNEL{"measurement"};
++constexpr const char* DEFAULT_REFERENCE_CHANNEL{"reference"};
++constexpr const char* DEFAULT_OUTPUT_CHANNEL{"out"};
++}
++
++namespace audio {
++JackClient::JackClient(const Plugin::Direction &direction, QIODevice& endpoint)
++ : m_client(nullptr, jackClientDeleter()), m_direction(direction), m_endpoint(endpoint)
++{
++ initJackClient();
++ initPorts();
++ initSampleRate();
++ initBufferSize();
++ initProcessing();
++}
++
++JackClient::~JackClient()
++{
++ // Explicitly stop processing first, to prevent us still running the JACK
++ // processor while the rest of the object is being cleaned up
++ if (m_client)
++ close();
++}
++
++jack_nframes_t JackClient::currentSampleRate() const
++{
++ return m_sampleRate;
++}
++
++std::size_t JackClient::currentChannelCount() const
++{
++ return m_ports.size();
++}
++
++Plugin::Direction JackClient::direction() const
++{
++ return m_direction;
++}
++
++void JackClient::close()
++{
++ deactivate();
++ m_client.reset(nullptr);
++}
++
++void JackClient::initJackClient()
++{
++ jack_status_t jackStatus;
++ jack_client_t* jackClient = jack_client_open(
++ JACK_CLIENT_NAME,
++ JackOptions::JackNoStartServer,
++ &jackStatus
++ );
++
++ if (!jackClient)
++ throw JackPluginException{"Failed to open JACK client"};
++
++ m_client.reset(jackClient);
++}
++
++void JackClient::initSampleRate()
++{
++ assert(m_client);
++ m_sampleRate = jack_get_sample_rate(m_client.get());
++ qDebug() << "[JACK] Sample rate set: " << m_sampleRate;
++
++ int res = jack_set_sample_rate_callback(
++ m_client.get(),
++ jackSampleRateCallback,
++ this
++ );
++ if (res != 0)
++ throw JackPluginException{"Failed to register sample rate callback"};
++}
++
++void JackClient::initBufferSize()
++{
++ assert(m_client);
++ assert(!m_ports.empty());
++ m_bufferSize = jack_get_buffer_size(m_client.get());
++ m_sampleBuffer.resize(m_bufferSize * m_ports.size());
++ qDebug() << "[JACK] Buffer size set: " << m_bufferSize;
++
++ int res = jack_set_buffer_size_callback(
++ m_client.get(),
++ jackBufferSizeCallback,
++ this
++ );
++ if (res != 0)
++ throw JackPluginException{"Failed to register buffer size callback"};
++}
++
++void JackClient::initPorts()
++{
++ assert(m_client);
++ switch (m_direction) {
++ case Plugin::Direction::Input:
++ registerInputs();
++ break;
++
++ case Plugin::Direction::Output:
++ registerOutputs();
++ break;
++
++ default:
++ throw JackPluginException{"Unsupported signal direction"};
++ }
++}
++
++void JackClient::initProcessing()
++{
++ assert(m_client);
++ int res = jack_set_process_callback(
++ m_client.get(),
++ jackProcessCallback,
++ this
++ );
++ if (res != 0)
++ throw JackPluginException{"Failed to register process callback"};
++}
++
++void JackClient::activate()
++{
++ assert(m_client);
++ if (m_active)
++ return;
++
++ qDebug() << "[JACK] Activating";
++ int res = jack_activate(m_client.get());
++ if (res != 0)
++ throw JackPluginException{"Failed to activate client"};
++
++ m_active = true;
++}
++
++void JackClient::deactivate()
++{
++ if (!m_active)
++ return;
++
++ m_active = false;
++
++ assert(m_client);
++ int res = jack_deactivate(m_client.get());
++ if (res != 0)
++ throw JackPluginException{"Failed to deactivate client"};
++}
++
++void JackClient::registerInputs()
++{
++ qDebug() << "[JACK] Registering Inputs";
++ jack_port_t *measurementPort = jack_port_register(
++ m_client.get(),
++ DEFAULT_MEASUREMENT_CHANNEL,
++ JACK_DEFAULT_AUDIO_TYPE,
++ JackPortFlags::JackPortIsInput,
++ 0
++ );
++ if (!measurementPort)
++ throw JackPluginException{"Failed to register measurement port"};
++ m_ports.emplace_back(measurementPort, jackPortDeleter(m_client.get()));
++ m_portBuffers.push_back(nullptr);
++
++ jack_port_t *referencePort = jack_port_register(
++ m_client.get(),
++ DEFAULT_REFERENCE_CHANNEL,
++ JACK_DEFAULT_AUDIO_TYPE,
++ JackPortFlags::JackPortIsInput,
++ 0
++ );
++ if (!referencePort)
++ throw JackPluginException{"Failed to register reference port"};
++ m_ports.emplace_back(referencePort, jackPortDeleter(m_client.get()));
++ m_portBuffers.push_back(nullptr);
++}
++
++void JackClient::registerOutputs()
++{
++ qDebug() << "[JACK] Registering Outputs";
++ jack_port_t *outputPort = jack_port_register(
++ m_client.get(),
++ DEFAULT_OUTPUT_CHANNEL,
++ JACK_DEFAULT_AUDIO_TYPE,
++ JackPortFlags::JackPortIsOutput,
++ 0
++ );
++ if (!outputPort)
++ throw JackPluginException{"Failed to register output port"};
++ m_ports.emplace_back(outputPort, jackPortDeleter(m_client.get()));
++ m_portBuffers.push_back(nullptr);
++}
++
++std::function<void(jack_client_t *)> JackClient::jackClientDeleter()
++{
++ return [this](jack_client_t *client) -> void {
++ m_ports.resize(0);
++ jack_client_close(client);
++ };
++}
++
++std::function<void(jack_port_t *)> JackClient::jackPortDeleter(jack_client_t *client)
++{
++ // We can't use the object's client member here as it might already have
++ // changed if this deleter is called in the client object's deleter,
++ // resulting in an assertion failure or segfault.
++ assert(client);
++ return [client](jack_port_t *port) -> void {
++ jack_port_unregister(client, port);
++ };
++}
++
++int JackClient::jackSampleRateCallback(jack_nframes_t newSampleRate, void* obj)
++{
++ assert(obj);
++ return reinterpret_cast<JackClient*>(obj)->jackSampleRateCallbackInt(newSampleRate);
++}
++
++int JackClient::jackSampleRateCallbackInt(jack_nframes_t newSampleRate)
++{
++ m_sampleRate = newSampleRate;
++ qInfo() << "[JACK] Sample rate updated: " << m_sampleRate;
++ emit sampleRateChanged(m_sampleRate);
++ return 0;
++}
++
++int JackClient::jackBufferSizeCallback(jack_nframes_t newBufferSize, void* obj)
++{
++ assert(obj);
++ return reinterpret_cast<JackClient*>(obj)->jackBufferSizeCallbackInt(newBufferSize);
++}
++
++int JackClient::jackBufferSizeCallbackInt(jack_nframes_t newBufferSize)
++{
++ m_bufferSize = newBufferSize;
++ qInfo() << "[JACK] Buffer size updated: " << m_bufferSize;
++ if (newBufferSize > 0)
++ m_sampleBuffer.resize(newBufferSize * m_ports.size());
++
++ return 0;
++}
++
++int JackClient::jackProcessCallback(jack_nframes_t nframes, void* obj)
++{
++ assert(obj);
++ return reinterpret_cast<JackClient*>(obj)->jackProcessCallbackInt(nframes);
++}
++
++int JackClient::jackProcessCallbackInt(jack_nframes_t nframes)
++{
++ // Yes, this can actually happen
++ if (m_bufferSize == 0)
++ return 1;
++
++ if (!m_active)
++ return 0;
++
++ assert(m_ports.size() == m_portBuffers.size());
++ assert(nframes == m_bufferSize);
++ assert(m_endpoint.isOpen());
++
++ if (m_direction == Plugin::Direction::Input) {
++ processInputPorts(nframes);
++ } else {
++ processOutputPorts(nframes);
++ }
++ return 0;
++}
++
++void JackClient::processInputPorts(jack_nframes_t nframes)
++{
++ if (!m_endpoint.isWritable())
++ return;
++
++ for (std::size_t i = 0; i < m_ports.size(); ++i) {
++ m_portBuffers[i] = reinterpret_cast<float*>(
++ jack_port_get_buffer(m_ports[i].get(), nframes));
++ }
++
++ std::size_t sampleBufferPos{0};
++ for (jack_nframes_t i = 0; i < nframes; ++i) {
++ for (const float* portBuf : m_portBuffers) {
++ assert(sampleBufferPos < m_sampleBuffer.size());
++ m_sampleBuffer[sampleBufferPos] = portBuf[i];
++ sampleBufferPos++;
++ }
++ }
++ assert(sampleBufferPos == nframes * m_portBuffers.size());
++ m_endpoint.write(
++ reinterpret_cast<char*>(m_sampleBuffer.data()),
++ sampleBufferPos * sizeof(float)
++ );
++}
++
++void JackClient::processOutputPorts(jack_nframes_t nframes)
++{
++ if (!m_endpoint.isReadable())
++ return;
++
++ for (std::size_t i = 0; i < m_ports.size(); ++i) {
++ m_portBuffers[i] = reinterpret_cast<float*>(
++ jack_port_get_buffer(m_ports[i].get(), nframes));
++ }
++
++ const std::size_t samplesToWrite = std::max(
++ static_cast<std::size_t>(nframes),
++ static_cast<std::size_t>(m_endpoint.bytesAvailable() / sizeof(float))
++ );
++ assert(samplesToWrite % m_ports.size() == 0);
++
++ std::size_t portIdx{0};
++ std::size_t portBufferPos{0};
++ for (std::size_t i = 0; i < samplesToWrite; ++i) {
++ assert(portIdx < m_portBuffers.size());
++ assert(portBufferPos < m_bufferSize);
++ const std::size_t bytesRead = m_endpoint.read(
++ reinterpret_cast<char*>(m_portBuffers[portIdx] + portBufferPos),
++ sizeof(float)
++ );
++ assert(bytesRead == sizeof(float));
++
++ portIdx = (portIdx + 1) % m_portBuffers.size();
++ if (portIdx == 0)
++ portBufferPos++;
++ }
++}
++
++JackPlugin::JackPlugin()
++{
++ DeviceInfo m_defaultDeviceInfo{PLUGIN_NAME, PLUGIN_NAME};
++ m_defaultDeviceInfo.setName(PLUGIN_NAME);
++ m_defaultDeviceInfo.setInputChannels({
++ DEFAULT_MEASUREMENT_CHANNEL,
++ DEFAULT_REFERENCE_CHANNEL
++ });
++ m_defaultDeviceInfo.setOutputChannels({DEFAULT_OUTPUT_CHANNEL});
++ m_defaultDeviceInfo.setDefaultSampleRate(DEFAULT_SAMPLE_RATE);
++ m_list.push_back(m_defaultDeviceInfo);
++}
++
++QString JackPlugin::name() const
++{
++ return PLUGIN_NAME;
++}
++
++DeviceInfo::List JackPlugin::getDeviceInfoList() const
++{
++ return m_list;
++}
++
++DeviceInfo::Id JackPlugin::defaultDeviceId(
++ [[maybe_unused]] const Plugin::Direction &mode) const
++{
++ return DeviceInfo::Id();
++}
++
++Format JackPlugin::deviceFormat(
++ [[maybe_unused]] const DeviceInfo::Id &id,
++ const Plugin::Direction &mode) const
++{
++ const auto client_it = std::find_if(
++ m_clients.begin(),
++ m_clients.end(),
++ [mode](const auto& client) {
++
++ return client.second->direction() == mode;
++ });
++
++ if (client_it == m_clients.end()) {
++ if (mode == Plugin::Direction::Input)
++ return {DEFAULT_SAMPLE_RATE, DEFAULT_CHANNEL_COUNT_INPUT};
++ else
++ return {DEFAULT_SAMPLE_RATE, DEFAULT_CHANNEL_COUNT_OUTPUT};
++ } else {
++ return {
++ static_cast<unsigned int>(client_it->second->currentSampleRate()),
++ static_cast<unsigned int>(client_it->second->currentChannelCount())
++ };
++ }
++}
++
++Stream *JackPlugin::open(
++ [[maybe_unused]] const DeviceInfo::Id &id,
++ const Plugin::Direction &mode,
++ [[maybe_unused]] const Format &format,
++ QIODevice *endpoint)
++{
++ // The sample rate is set by JACK, so we don't mess with it.
++ // The channel count is fixed to the minimum amount of channels necessary
++ // for OSM to work as we can freely patch the cannels in JACK.
++ //
++ // The ID can be ignored as we create individual JACK clients
++ // for each requested Stream.
++ try {
++ std::unique_ptr<JackClient> jack = std::make_unique<JackClient>(mode, *endpoint);
++
++ Format f{
++ jack->currentSampleRate(),
++ static_cast<unsigned int>(jack->currentChannelCount())
++ };
++ Stream *stream = new Stream(f);
++
++ m_clients.emplace(stream, std::move(jack));
++ JackClient& jackClient = *m_clients.at(stream).get();
++
++ connect(stream, &Stream::closeMe, this, [this, stream, endpoint]() {
++ // Order is important here to prevent JACK still writing data to
++ // the endpoint after it has been closed.
++ m_clients.erase(stream);
++
++ if (endpoint->isOpen())
++ endpoint->close();
++
++ stream->deleteLater();
++ });
++
++ connect(
++ &jackClient,
++ &JackClient::sampleRateChanged,
++ this,
++ [stream](jack_nframes_t newRate) {
++ assert(stream);
++ stream->setSampleRate(static_cast<unsigned int>(newRate));
++ });
++
++ endpoint->open(mode == Input ? QIODevice::WriteOnly : QIODevice::ReadOnly);
++ jackClient.activate();
++
++ return stream;
++ } catch (JackPluginException& e) {
++ return nullptr;
++ }
++}
++
++}
+diff --git a/src/audio/plugins/jack.h b/src/audio/plugins/jack.h
+new file mode 100644
+index 0000000..9685f65
+--- /dev/null
++++ b/src/audio/plugins/jack.h
+@@ -0,0 +1,127 @@
++/**
++ * OSM
++ * Copyright (C) 2022 Adrian Schollmeyer
++
++ * 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 3 of the License, or
++ * (at your option) any later version.
++
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++
++ * You should have received a copy of the GNU General Public License
++ * along with this program. If not, see <http://www.gnu.org/licenses/>.
++ */
++#ifndef AUDIO_JACKPLUGIN_H
++#define AUDIO_JACKPLUGIN_H
++
++#include "../plugin.h"
++#include <QObject>
++#include <functional>
++#include <jack/jack.h>
++#include <jack/types.h>
++#include <map>
++#include <memory>
++#include <stdexcept>
++#include <vector>
++
++namespace audio {
++class JackClient : public QObject
++{
++ Q_OBJECT
++
++public:
++ constexpr static std::size_t BUFFER_SIZE_MULTIPLIER{4};
++
++ JackClient(const Plugin::Direction &direction, QIODevice& endpoint);
++ JackClient(JackClient&&) = default;
++ JackClient(const JackClient &) = delete;
++ ~JackClient();
++
++ void activate();
++ void deactivate();
++
++ jack_nframes_t currentSampleRate() const;
++ std::size_t currentChannelCount() const;
++
++ Plugin::Direction direction() const;
++
++signals:
++ void sampleRateChanged(jack_nframes_t newSampleRate);
++
++public slots:
++ void close();
++
++private:
++ void initJackClient();
++ void initPorts();
++ void initSampleRate();
++ void initBufferSize();
++ void initProcessing();
++
++ void registerInputs();
++ void registerOutputs();
++
++ std::function<void(jack_client_t *)> jackClientDeleter();
++ static std::function<void(jack_port_t *)> jackPortDeleter(jack_client_t *client);
++
++ static int jackSampleRateCallback(jack_nframes_t newSampleRate, void* obj);
++ int jackSampleRateCallbackInt(jack_nframes_t newSampleRate);
++
++ static int jackBufferSizeCallback(jack_nframes_t newBufferSize, void* obj);
++ int jackBufferSizeCallbackInt(jack_nframes_t newBufferSize);
++
++ static int jackProcessCallback(jack_nframes_t nframes, void* obj);
++ int jackProcessCallbackInt(jack_nframes_t nframes);
++
++ void processInputPorts(jack_nframes_t nframes);
++ void processOutputPorts(jack_nframes_t nframes);
++
++ std::unique_ptr<jack_client_t, std::function<void(jack_client_t *)>> m_client;
++ std::vector<std::unique_ptr<jack_port_t, std::function<void(jack_port_t *)>>> m_ports;
++ std::vector<float*> m_portBuffers;
++ jack_nframes_t m_sampleRate;
++ jack_nframes_t m_bufferSize;
++ const Plugin::Direction m_direction;
++ QIODevice& m_endpoint;
++ std::vector<float> m_sampleBuffer;
++ bool m_active{false};
++};
++
++class JackPlugin : public Plugin
++{
++ Q_OBJECT
++
++public:
++ JackPlugin();
++ JackPlugin(const JackPlugin &) = delete;
++ virtual ~JackPlugin() = default;
++
++ QString name() const override;
++ DeviceInfo::List getDeviceInfoList() const override;
++ DeviceInfo::Id defaultDeviceId(const Direction &mode) const override;
++
++ Format deviceFormat(const DeviceInfo::Id &id, const Direction &mode) const override;
++ Stream *open(const DeviceInfo::Id &id, const Direction &mode, const Format &format, QIODevice *endpoint) override;
++
++private:
++ DeviceInfo::List m_list{};
++ DeviceInfo m_defaultDeviceInfoInput;
++ DeviceInfo m_defaultDeviceInfoOutput;
++ std::map<Stream *, std::unique_ptr<JackClient>> m_clients{};
++};
++
++class JackPluginException : public std::runtime_error
++{
++public:
++ template<typename T>
++ JackPluginException(const T& arg)
++ : std::runtime_error(arg)
++ {}
++};
++}
++
++#endif // AUDIO_JACKPLUGIN_H
diff --git a/media-sound/opensoundmeter/opensoundmeter-1.2.2.ebuild b/media-sound/opensoundmeter/opensoundmeter-1.2.2.ebuild
new file mode 100644
index 000000000..372bb74c4
--- /dev/null
+++ b/media-sound/opensoundmeter/opensoundmeter-1.2.2.ebuild
@@ -0,0 +1,60 @@
+# Copyright 2022 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+inherit qmake-utils desktop
+
+DESCRIPTION="FFT based application for tuning sound systems"
+HOMEPAGE="https://opensoundmeter.com/en/ https://github.com/psmokotnin/osm"
+SRC_URI="
+ https://github.com/psmokotnin/osm/archive/refs/tags/v${PV}.tar.gz -> ${P}.gh.tar.gz
+"
+
+# GPL-3 for the codebase
+# N-Noise-EULA for the M-Noise noise generator
+LICENSE="GPL-3 M-Noise-EULA"
+SLOT="0"
+KEYWORDS="~amd64"
+
+DEPEND="
+ dev-qt/qtcore:5=
+ dev-qt/qtnetwork:5=
+ dev-qt/qtopengl:5=
+ dev-qt/qtquickcontrols2:5=
+ dev-qt/qtwidgets:5=
+ media-libs/alsa-lib
+"
+RDEPEND="${DEPEND}"
+# qtcore for qmake5
+BDEPEND="
+ dev-qt/qtcore:5
+"
+
+S="${WORKDIR}/osm-${PV}"
+DOCS=( "README.md" )
+
+src_prepare() {
+ default
+ mkdir -p build || die
+}
+
+src_configure() {
+ cd build || die
+ eqmake5 ../OpenSoundMeter.pro
+}
+
+src_compile() {
+ cd build || die
+ emake
+}
+
+src_install() {
+ # The default OpenSoundMeter doesn't respect standard dirs, so we install
+ # manually
+ dobin build/OpenSoundMeter
+
+ sed "s/Icon=white/Icon=${PN}/g" "OpenSoundMeter.desktop" || die
+ domenu "OpenSoundMeter.desktop"
+ newicon icons/white.png "${PN}.png"
+}
diff --git a/media-sound/opensoundmeter/opensoundmeter-1.2.2_p20220104.ebuild b/media-sound/opensoundmeter/opensoundmeter-1.2.2_p20220104.ebuild
new file mode 100644
index 000000000..a35275cec
--- /dev/null
+++ b/media-sound/opensoundmeter/opensoundmeter-1.2.2_p20220104.ebuild
@@ -0,0 +1,76 @@
+# Copyright 2022 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+inherit qmake-utils desktop
+
+MY_PV="$(ver_cut 1-3)"
+
+DESCRIPTION="FFT based application for tuning sound systems"
+HOMEPAGE="https://opensoundmeter.com/en/ https://github.com/psmokotnin/osm"
+SRC_URI="
+ https://github.com/psmokotnin/osm/archive/refs/tags/v${MY_PV}.tar.gz -> opensoundmeter-${MY_PV}.gh.tar.gz
+"
+
+# GPL-3 for the codebase
+# N-Noise-EULA for the M-Noise noise generator
+LICENSE="GPL-3 M-Noise-EULA"
+SLOT="0"
+KEYWORDS="~amd64"
+IUSE="jack"
+
+DEPEND="
+ dev-qt/qtcore:5=
+ dev-qt/qtnetwork:5=
+ dev-qt/qtopengl:5=
+ dev-qt/qtquickcontrols2:5=
+ dev-qt/qtwidgets:5=
+ media-libs/alsa-lib
+
+ jack? (
+ virtual/jack
+ )
+"
+RDEPEND="${DEPEND}"
+# qtcore for qmake5
+BDEPEND="
+ dev-qt/qtcore:5
+"
+
+PATCHES=(
+ # Two patches that just take far too long upstream
+ "${FILESDIR}/${PN}-jack-support.patch"
+ "${FILESDIR}/${PN}-deadlock-fix.patch"
+)
+
+S="${WORKDIR}/osm-${MY_PV}"
+DOCS=( "README.md" )
+
+src_prepare() {
+ default
+ mkdir -p build || die
+}
+
+src_configure() {
+ cd build || die
+ local myeqmakeargs=()
+ use jack && myeqmakeargs+=( "CONFIG+=jack" )
+
+ eqmake5 "${myeqmakeargs[@]}" ../OpenSoundMeter.pro
+}
+
+src_compile() {
+ cd build || die
+ emake
+}
+
+src_install() {
+ # The default OpenSoundMeter doesn't respect standard dirs, so we install
+ # manually
+ dobin build/OpenSoundMeter
+
+ sed "s/Icon=white/Icon=${PN}/g" "OpenSoundMeter.desktop" || die
+ domenu "OpenSoundMeter.desktop"
+ newicon icons/white.png "${PN}.png"
+}
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2023-01-06 8:51 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-01-06 8:51 [gentoo-commits] repo/proj/guru:master commit in: media-sound/opensoundmeter/files/, media-sound/opensoundmeter/ Florian Schmaus
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox