Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Plugin Pin Connector #7459

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
93884a2
Add PluginPortConfig class
messmerd May 8, 2024
f1f1010
Avoid misleading types and weird casts
messmerd May 8, 2024
c78c17f
Use PluginPortConfig for mono VSTs
messmerd May 8, 2024
4da60af
Refactor; Fix automation clip tooltip
messmerd Jun 16, 2024
798e088
Begin pin connector implementation (WIP)
messmerd Aug 11, 2024
af4d6b3
Loading/saving (WIP)
messmerd Aug 11, 2024
aafe41c
More efficient loading
messmerd Aug 11, 2024
360eca6
Use new routing methods (WIP)
messmerd Aug 11, 2024
7b7f674
Progress (WIP)
messmerd Aug 12, 2024
1568d3a
Merge branch 'master' into pin-connector
messmerd Aug 12, 2024
5f31c04
Fix up post-merge (WIP)
messmerd Aug 12, 2024
853d80c
Fix crash
messmerd Aug 14, 2024
7935718
Begin implementing PluginPinConnectorView
messmerd Aug 14, 2024
b3ad72a
Progress (WIP)
messmerd Aug 14, 2024
b55bdec
Fix pin icon while dragging
messmerd Aug 14, 2024
bda93bc
More progress
messmerd Aug 15, 2024
15f395e
Draw plugin channel text
messmerd Aug 15, 2024
8d2acad
Fix Linux build
messmerd Aug 15, 2024
a00cdba
Some refactoring
messmerd Aug 16, 2024
c98353f
Fix build
messmerd Aug 16, 2024
774e3b6
Introduce MatrixView class
messmerd Aug 17, 2024
e768a58
Use layouts
messmerd Aug 17, 2024
2ee2c08
Make PluginPinConnector::Matrix a struct; Add tooltips
messmerd Aug 17, 2024
8445f2c
Set model display names
messmerd Aug 17, 2024
ecc6318
Fix a display bug
messmerd Aug 17, 2024
a317e16
Remove some unused code
messmerd Aug 17, 2024
2571547
Fix crash when reloading project with pin connector open
messmerd Aug 17, 2024
ada15d3
Fix miscalculation in mousePressEvent
messmerd Aug 18, 2024
a308725
Better pin connector button text; Better naming and comments
messmerd Aug 25, 2024
09eb59f
Use pointing hand cursor when hovering over cells
messmerd Aug 25, 2024
f6910c6
Make routing methods const
messmerd Sep 14, 2024
ba3ffc6
Improve routing normalization
messmerd Sep 14, 2024
af5c16b
Use bitwise OR
messmerd Sep 14, 2024
32557d4
Move some pin connector methods into Matrix
messmerd Sep 14, 2024
1716186
Use `const float*` for process's in buffer
messmerd Sep 14, 2024
23fd48b
Rename `m_trackChannelsUsed` to `m_trackChannelsUpperBound`
messmerd Sep 21, 2024
089ffb4
Merge branch 'master' into pin-connector
messmerd Sep 21, 2024
62efd0e
Various changes
messmerd Sep 23, 2024
b7883f1
Use `MAXIMUM_BUFFER_SIZE`
messmerd Sep 23, 2024
bd404df
Revert strongly typed sample types
messmerd Oct 16, 2024
dcf1fc9
Minor optimization in `mixInputs` lambda
messmerd Oct 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions include/AudioData.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* AudioData.h - Audio data types
*
* Copyright (c) 2024 Dalton Messmer <messmer.dalton/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/

#ifndef LMMS_AUDIO_DATA_H
#define LMMS_AUDIO_DATA_H

#include <type_traits>

#include "lmms_basics.h"

namespace lmms
{

//! Conventions for passing audio data
enum class AudioDataLayout
{
/*
* Given:
* - N == Frame count
* - C == Number of channels
* - i == Sample index, where 0 <= i < N
* - `samples` has the type sample_t*
* - `samples` size == N * C
*/

/**
* Layout where the samples for each channel are interleaved.
* i.e. "LRLRLRLR"
*
* Samples for individual channels can be accessed like this:
* - Channel #0 samples: samples[C*i]
* - Channel #1 samples: samples[C*i + 1]
* - Channel #2 samples: samples[C*i + 2]
* - Channel #3 samples: samples[C*i + 3]
* - ...
*/
Interleaved,

/**
* Layout where all samples for a particular channel are grouped together.
* i.e. "LLLLRRRR"
*
* Samples for individual channels can be accessed like this:
* - Channel #0 samples: samples[i]
* - Channel #1 samples: samples[1*N + i]
* - Channel #2 samples: samples[2*N + i]
* - Channel #3 samples: samples[3*N + i]
* - ...
*/
Split
};


/**
* An alias for an unbounded floating point array.
*
* Can be used as a replacement for `float*` parameters when you want to document the
* data layout of the audio data.
*/
template<AudioDataLayout layout, typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
using AudioDataPtr = T*;

template<typename T>
using SplitAudioDataPtr = AudioDataPtr<AudioDataLayout::Split, T>;

template<typename T>
using InterleavedAudioDataPtr = AudioDataPtr<AudioDataLayout::Interleaved, T>;


/**
* A simple (samples, size) pair for storing audio data of a particular layout.
* All data is contiguous in memory.
*
* NOTE: More information is still needed to correctly interpret this audio data:
* - For Split layout, the frame count is needed
* - For Interleaved layout, the channel count is needed
*/
template<AudioDataLayout layout, typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
using AudioData = Span<T>;

template<typename T>
using SplitAudioData = AudioData<AudioDataLayout::Split, T>;

template<typename T>
using InterleavedAudioData = AudioData<AudioDataLayout::Interleaved, T>;


} // namespace lmms

#endif // LMMS_AUDIO_DATA_H
156 changes: 156 additions & 0 deletions include/PluginPinConnector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* PluginPinConnector.h - Specifies how to route audio channels
* in and out of a plugin.
*
* Copyright (c) 2024 Dalton Messmer <messmer.dalton/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/

#ifndef LMMS_PLUGIN_PIN_CONNECTOR_H
#define LMMS_PLUGIN_PIN_CONNECTOR_H

#include <vector>

#include "AutomatableModel.h"
#include "lmms_export.h"
#include "SampleFrame.h"
#include "SerializingObject.h"

class QWidget;

namespace lmms
{

namespace gui
{

class PluginPinConnectorView;

} // namespace gui

//! Configuration for audio channel routing in/out of plugin
class LMMS_EXPORT PluginPinConnector
: public Model
, public SerializingObject
{
Q_OBJECT

public:
//! [track channel][plugin channel]
using PinMap = std::vector<std::vector<BoolModel*>>;
JohannesLorenz marked this conversation as resolved.
Show resolved Hide resolved
JohannesLorenz marked this conversation as resolved.
Show resolved Hide resolved

//! A plugin's input or output connections and other info
struct Matrix
{
PinMap pins;
int channelCount = 0;
std::vector<QString> channelNames; //!< optional

// TODO: Channel groupings, port configurations, ...

auto channelName(int channel) const -> QString;

auto enabled(std::uint8_t trackChannel, unsigned pluginChannel) const -> bool
{
return pins[trackChannel][pluginChannel]->value();
}
};

PluginPinConnector(Model* parent = nullptr);
PluginPinConnector(int pluginChannelCountIn, int pluginChannelCountOut, Model* parent = nullptr);

/**
* Getters
*/
auto in() const -> const Matrix& { return m_in; };
messmerd marked this conversation as resolved.
Show resolved Hide resolved
auto out() const -> const Matrix& { return m_out; };
auto trackChannelCount() const -> std::size_t { return s_totalTrackChannels; }
auto trackChannelsUsed() const -> unsigned int { return m_trackChannelsUsed; }
messmerd marked this conversation as resolved.
Show resolved Hide resolved

/**
* Setters
*/
void setPluginChannelCounts(int inCount, int outCount);
void setPluginChannelCountIn(int inCount);
void setPluginChannelCountOut(int outCount);

void setDefaultConnections();

/*
* Routes audio from LMMS track channels to plugin inputs according to the plugin pin connector configuration.
*
* Iterates through each output channel, mixing together all input audio routed to the output channel.
* If no audio is routed to an output channel, the output channel's buffer is zeroed.
*
* `frames` : number of frames in each `in`/`out` audio buffer
* `in` : track channels from LMMS core (currently just the main track channel pair)
* `out` : plugin input channels in Split form
*/
void routeToPlugin(f_cnt_t frames, CoreAudioData in, SplitAudioData<sample_t> out);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might work for VST, which wants split channels, but e.g. the LMMS-native Amplifier wants its audio data interleaved. Are you planning to add routines for that case?


/*
* Routes audio from plugin outputs to LMMS track channels according to the plugin pin connector configuration.
*
* Iterates through each output channel, mixing together all input audio routed to the output channel.
* If no audio is routed to an output channel, `inOut` remains unchanged for audio bypass.
*
* `frames` : number of frames in each `in`/`out` audio buffer
* `in` : plugin output channels in Split form
* `inOut` : track channels from/to LMMS core (inplace processing)
*/
void routeFromPlugin(f_cnt_t frames, SplitAudioData<const sample_t> in, CoreAudioDataMut inOut);


/**
* SerializingObject implementation
*/
void saveSettings(QDomDocument& doc, QDomElement& elem) override;
void loadSettings(const QDomElement& elem) override;
auto nodeName() const -> QString override { return "pins"; }

auto instantiateView(QWidget* parent = nullptr) -> gui::PluginPinConnectorView*;
auto getChannelCountText() const -> QString;

static constexpr std::size_t MaxTrackChannels = 256; // TODO: Move somewhere else

public slots:
void setTrackChannelCount(int count);

private:
static void saveSettings(const Matrix& matrix, QDomDocument& doc, QDomElement& elem);
static void loadSettings(const QDomElement& elem, Matrix& matrix);

void setPluginChannelCount(int newCount, bool isInput, Matrix& matrix);

Matrix m_in; //!< LMMS --> Plugin
Matrix m_out; //!< Plugin --> LMMS

//! TODO: Move this somewhere else; Will be >= 2 once there is support for adding new track channels
static constexpr std::size_t s_totalTrackChannels = DEFAULT_CHANNELS;

//! This value is <= to the total number of track channels (currently always 2)
unsigned int m_trackChannelsUsed = DEFAULT_CHANNELS;

// TODO: When full routing is added, get LMMS channel counts from bus or router class
};

} // namespace lmms

#endif // LMMS_PLUGIN_PIN_CONNECTOR_H
82 changes: 82 additions & 0 deletions include/PluginPinConnectorView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* PluginPinConnectorView.h - Displays pin connectors
*
* Copyright (c) 2024 Dalton Messmer <messmer.dalton/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/

#ifndef LMMS_GUI_PLUGIN_PIN_CONNECTOR_VIEW_H
#define LMMS_GUI_PLUGIN_PIN_CONNECTOR_VIEW_H

#include <QWidget>

#include "embed.h"
#include "lmms_export.h"
#include "ModelView.h"

class QPixmap;
//class QScrollArea;

namespace lmms
{

class BoolModel;
class PluginPinConnector;

namespace gui
{

class SubWindow;

class LMMS_EXPORT PluginPinConnectorView
: public QWidget
, public ModelView
{
Q_OBJECT

public:
PluginPinConnectorView(PluginPinConnector* model, QWidget* parent);

auto sizeHint() const -> QSize override;
auto minimumSizeHint() const -> QSize override;

void toggleVisibility();
void closeWindow();

protected:
void paintEvent(QPaintEvent* pe) override;

private:
class MatrixView;

void updateGeometry();

SubWindow* m_subWindow = nullptr;
//QScrollArea* m_scrollArea = nullptr;

MatrixView* m_inView = nullptr;
MatrixView* m_outView = nullptr;
};

} // namespace gui

} // namespace lmms

#endif // LMMS_GUI_PLUGIN_PIN_CONNECTOR_VIEW_H
Loading
Loading