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 L/R channel routing for VST plugins #7247

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
139 changes: 139 additions & 0 deletions include/PluginPortConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* PluginPortConfig.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_PORT_CONFIG_H
#define LMMS_PLUGIN_PORT_CONFIG_H

#include <QObject>

#include "ComboBoxModel.h"
#include "lmms_export.h"
#include "SerializingObject.h"

class QWidget;

namespace lmms
{

namespace gui
{

class ComboBox;

} // namespace gui

//! Configure channel routing for a plugin's mono/stereo in/out ports
class LMMS_EXPORT PluginPortConfig
: public QObject
, public SerializingObject
{
Q_OBJECT

public:
enum class Config
{
None = -1,
MonoMix = 0, // mono ports only
LeftOnly = 1, // mono ports only
RightOnly = 2, // mono ports only
Stereo = 3
};

enum class MonoPluginType
{
None,
Input,
Output,
Both
};

PluginPortConfig(Model* parent = nullptr);
PluginPortConfig(int inCount, int outCount, Model* parent = nullptr);

/**
* Getters
*/
auto portCountIn() const -> int { return m_portCountIn; }
auto portCountOut() const -> int { return m_portCountOut; }

auto portConfigIn() const -> Config
{
switch (m_portCountIn)
{
default: [[fallthrough]];
case 0: return Config::None;
case 1: return static_cast<Config>(m_config.value());
case 2: return Config::Stereo;
}
}

auto portConfigOut() const -> Config
{
switch (m_portCountOut)
{
default: [[fallthrough]];
case 0: return Config::None;
case 1: return static_cast<Config>(m_config.value());
case 2: return Config::Stereo;
}
}

auto hasMonoPort() const -> bool;
auto monoPluginType() const -> MonoPluginType;
auto model() -> ComboBoxModel* { return &m_config; }

/**
* Setters
*/
void setPortCounts(int inCount, int outCount);
void setPortCountIn(int inCount);
void setPortCountOut(int outCount);
auto setPortConfig(Config config) -> bool;

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

auto instantiateView(QWidget* parent = nullptr) -> gui::ComboBox*;

signals:
void portsChanged();

private:
void updateOptions();

int m_portCountIn = DEFAULT_CHANNELS;
int m_portCountOut = DEFAULT_CHANNELS;

//! Value is 0..2, which represents { MonoMix, LeftOnly, RightOnly } for non-Stereo plugins
ComboBoxModel m_config;
};

} // namespace lmms

#endif // LMMS_PLUGIN_PORT_CONFIG_H
14 changes: 10 additions & 4 deletions include/RemotePlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#define LMMS_REMOTE_PLUGIN_H

#include "RemotePluginBase.h"

#include "PluginPortConfig.h"
#include "SharedMemory.h"

#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
Expand All @@ -42,7 +44,7 @@ class ProcessWatcher : public QThread
{
Q_OBJECT
public:
ProcessWatcher( RemotePlugin * );
explicit ProcessWatcher(RemotePlugin* plugin);
~ProcessWatcher() override = default;

void stop()
Expand All @@ -69,7 +71,7 @@ class LMMS_EXPORT RemotePlugin : public QObject, public RemotePluginBase
{
Q_OBJECT
public:
RemotePlugin();
explicit RemotePlugin(Model* parent = nullptr);
~RemotePlugin() override;

inline bool isRunning()
Expand Down Expand Up @@ -140,6 +142,11 @@ class LMMS_EXPORT RemotePlugin : public QObject, public RemotePluginBase
m_commMutex.unlock();
}

PluginPortConfig& portConfig()
{
return m_portConfig;
}

public slots:
virtual void showUI();
virtual void hideUI();
Expand Down Expand Up @@ -172,8 +179,7 @@ public slots:
SharedMemory<float[]> m_audioBuffer;
std::size_t m_audioBufferSize;

int m_inputCount;
int m_outputCount;
PluginPortConfig m_portConfig;

#ifndef SYNC_WITH_SHM_FIFO
int m_server;
Expand Down
8 changes: 3 additions & 5 deletions include/RemotePluginClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ class RemotePluginClient : public RemotePluginBase

bool processMessage( const message & _m ) override;

virtual void process( const sampleFrame * _in_buf,
sampleFrame * _out_buf ) = 0;
virtual void process(float* _in_buf, float* _out_buf) = 0;

virtual void processMidiEvent( const MidiEvent&, const f_cnt_t /* _offset */ )
{
Expand Down Expand Up @@ -342,9 +341,8 @@ void RemotePluginClient::doProcessing()
{
if (m_audioBuffer)
{
process( (sampleFrame *)( m_inputCount > 0 ? m_audioBuffer.get() : nullptr ),
(sampleFrame *)( m_audioBuffer.get() +
( m_inputCount*m_bufferSize ) ) );
process(m_inputCount > 0 ? m_audioBuffer.get() : nullptr,
m_audioBuffer.get() + m_inputCount * m_bufferSize);
}
else
{
Expand Down
35 changes: 21 additions & 14 deletions plugins/Vestige/Vestige.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@


#include "AudioEngine.h"
#include "ComboBox.h"
#include "ConfigManager.h"
#include "CustomTextKnob.h"
#include "Engine.h"
Expand Down Expand Up @@ -363,7 +364,7 @@ void VestigeInstrument::loadFile( const QString & _file )
}

m_pluginMutex.lock();
m_plugin = new VstInstrumentPlugin( m_pluginDLL );
m_plugin = new VstInstrumentPlugin{m_pluginDLL, this};
if( m_plugin->failed() )
{
m_pluginMutex.unlock();
Expand Down Expand Up @@ -482,10 +483,17 @@ gui::PluginView * VestigeInstrument::instantiateView( QWidget * _parent )
}


PluginPortConfig* VestigeInstrument::portConfig()
{
if (!m_plugin) { return nullptr; }
return &m_plugin->portConfig();
}


namespace gui
{

VestigeInstrumentView::VestigeInstrumentView( Instrument * _instrument,
VestigeInstrumentView::VestigeInstrumentView( VestigeInstrument * _instrument,
QWidget * _parent ) :
InstrumentViewFixedSize( _instrument, _parent ),
lastPosInMenu (0)
Expand Down Expand Up @@ -602,15 +610,15 @@ VestigeInstrumentView::VestigeInstrumentView( Instrument * _instrument,
SLOT( noteOffAll() ) );

setAcceptDrops( true );
_instrument2 = _instrument;
m_instrument2 = _instrument;
_parent2 = _parent;
}


void VestigeInstrumentView::managePlugin( void )
{
if ( m_vi->m_plugin != nullptr && m_vi->m_subWindow == nullptr ) {
m_vi->p_subWindow = new ManageVestigeInstrumentView( _instrument2, _parent2, m_vi);
m_vi->p_subWindow = new ManageVestigeInstrumentView( m_instrument2, _parent2, m_vi);
} else if (m_vi->m_subWindow != nullptr) {
if (m_vi->m_subWindow->widget()->isVisible() == false ) {
m_vi->m_scrollArea->show();
Expand Down Expand Up @@ -912,8 +920,8 @@ void VestigeInstrumentView::paintEvent( QPaintEvent * )



ManageVestigeInstrumentView::ManageVestigeInstrumentView( Instrument * _instrument,
QWidget * _parent, VestigeInstrument * m_vi2 ) :
ManageVestigeInstrumentView::ManageVestigeInstrumentView( VestigeInstrument * _instrument,
QWidget * _parent, VestigeInstrument * _vi2 ) :
InstrumentViewFixedSize( _instrument, _parent )
{
#if QT_VERSION < 0x50C00
Expand All @@ -927,7 +935,7 @@ ManageVestigeInstrumentView::ManageVestigeInstrumentView( Instrument * _instrume

#endif

m_vi = m_vi2;
m_vi = _vi2;
m_vi->m_scrollArea = new QScrollArea( this );
widget = new QWidget(this);
l = new QGridLayout( this );
Expand Down Expand Up @@ -960,13 +968,12 @@ ManageVestigeInstrumentView::ManageVestigeInstrumentView( Instrument * _instrume

l->addWidget( m_displayAutomatedOnly, 0, 1, 1, 2, Qt::AlignLeft );


m_closeButton = new QPushButton( tr( " Close " ), widget );
connect( m_closeButton, SIGNAL( clicked() ), this,
SLOT( closeWindow() ) );

l->addWidget( m_closeButton, 0, 2, 1, 7, Qt::AlignLeft );

if (m_vi->portConfig()->hasMonoPort())
{
m_portConfig = m_vi->portConfig()->instantiateView(this);
m_portConfig->setFixedSize(108, gui::ComboBox::DEFAULT_HEIGHT);
l->addWidget(m_portConfig, 0, 2, 1, 3, Qt::AlignLeft);
}

for( int i = 0; i < 10; i++ )
{
Expand Down
12 changes: 8 additions & 4 deletions plugins/Vestige/Vestige.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ class QGridLayout;
namespace lmms
{

class ComboBox;
class FloatModel;
class PluginPortConfig;
class VstPlugin;

namespace gui
Expand Down Expand Up @@ -74,6 +76,8 @@ class VestigeInstrument : public Instrument

virtual gui::PluginView* instantiateView( QWidget * _parent );

PluginPortConfig* portConfig();

protected slots:
void setParameter( lmms::Model * action );
void handleConfigChange( QString cls, QString attr, QString value );
Expand Down Expand Up @@ -107,7 +111,7 @@ class ManageVestigeInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:
ManageVestigeInstrumentView( Instrument * _instrument, QWidget * _parent, VestigeInstrument * m_vi2 );
ManageVestigeInstrumentView( VestigeInstrument * _instrument, QWidget * _parent, VestigeInstrument * _vi2 );
virtual ~ManageVestigeInstrumentView();


Expand All @@ -132,7 +136,7 @@ protected slots:
QGridLayout * l;
QPushButton * m_syncButton;
QPushButton * m_displayAutomatedOnly;
QPushButton * m_closeButton;
ComboBox* m_portConfig;
CustomTextKnob ** vstKnobs;

} ;
Expand All @@ -142,7 +146,7 @@ class VestigeInstrumentView : public InstrumentViewFixedSize
{
Q_OBJECT
public:
VestigeInstrumentView( Instrument * _instrument, QWidget * _parent );
VestigeInstrumentView( VestigeInstrument * _instrument, QWidget * _parent );
virtual ~VestigeInstrumentView() = default;


Expand Down Expand Up @@ -182,7 +186,7 @@ protected slots:
PixmapButton * m_managePluginButton;
PixmapButton * m_savePresetButton;

Instrument * _instrument2;
VestigeInstrument* m_instrument2;
QWidget * _parent2;

} ;
Expand Down
9 changes: 5 additions & 4 deletions plugins/VstBase/RemoteVstPlugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class RemoteVstPlugin : public RemotePluginClient
void hideEditor();
void destroyEditor();

virtual void process( const sampleFrame * _in, sampleFrame * _out );
void process(float* _in, float* _out) override;


virtual void processMidiEvent( const MidiEvent& event, const f_cnt_t offset );
Expand Down Expand Up @@ -1027,7 +1027,7 @@ bool RemoteVstPlugin::load( const std::string & _plugin_file )



void RemoteVstPlugin::process( const sampleFrame * _in, sampleFrame * _out )
void RemoteVstPlugin::process(float* _in, float* _out)
{
// first we gonna post all MIDI-events we enqueued so far
if( m_midiEvents.size() )
Expand Down Expand Up @@ -1076,14 +1076,15 @@ void RemoteVstPlugin::process( const sampleFrame * _in, sampleFrame * _out )
return;
}

// NOTE: VST in/out channels are always provided split: in[0..frames] (left), in[frames..2*frames] (right)
for( int i = 0; i < inputCount(); ++i )
{
m_inputs[i] = &((float *) _in)[i * bufferSize()];
m_inputs[i] = &_in[i * bufferSize()];
}

for( int i = 0; i < outputCount(); ++i )
{
m_outputs[i] = &((float *) _out)[i * bufferSize()];
m_outputs[i] = &_out[i * bufferSize()];
memset( m_outputs[i], 0, bufferSize() * sizeof( float ) );
}

Expand Down
Loading
Loading