-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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 automation support for Carla. #4569
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,13 +33,20 @@ | |
#include "InstrumentPlayHandle.h" | ||
#include "InstrumentTrack.h" | ||
#include "Mixer.h" | ||
#include "Knob.h" | ||
#include "EffectControls.h" | ||
|
||
#include <QApplication> | ||
#include <QFileDialog> | ||
#include <QFileInfo> | ||
#include <QPushButton> | ||
#include <QTimerEvent> | ||
#include <QVBoxLayout> | ||
#include <QHBoxLayout> | ||
#include <QSizePolicy> | ||
#include <QScrollArea> | ||
#include <QtDebug> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recommend you including |
||
#include <QString> | ||
|
||
#include <cstring> | ||
|
||
|
@@ -299,14 +306,69 @@ void CarlaInstrument::saveSettings(QDomDocument& doc, QDomElement& parent) | |
return; | ||
|
||
QDomDocument carlaDoc("carla"); | ||
|
||
if (carlaDoc.setContent(QString(state))) | ||
{ | ||
QDomNode n = doc.importNode(carlaDoc.documentElement(), true); | ||
parent.appendChild(n); | ||
} | ||
|
||
std::free(state); | ||
|
||
for (uint32_t i=0; i < floatModels.count(); ++i) | ||
{ | ||
QString idStr = CARLA_SETTING_PREFIX + QString::number(i); | ||
floatModels[i]->saveSettings( doc, parent, idStr ); | ||
} | ||
|
||
} | ||
|
||
void CarlaInstrument::refreshParams() | ||
{ | ||
if (fDescriptor->get_parameter_count != nullptr && | ||
fDescriptor->get_parameter_info != nullptr && | ||
fDescriptor->get_parameter_value != nullptr && | ||
fDescriptor->set_parameter_value != nullptr) | ||
{ | ||
uint32_t param_count = fDescriptor->get_parameter_count(fHandle); | ||
if (param_count > 0) | ||
{ | ||
clearKnobModels(); | ||
floatModels.reserve(param_count); | ||
for (uint32_t i=0; i < param_count; ++i) | ||
{ | ||
// https://github.com/falkTX/Carla/tree/master/source/native-plugins source/native-plugins/resources/carla-plugin | ||
const NativeParameter* paramInfo(fDescriptor->get_parameter_info(fHandle, i)); | ||
float param_value = fDescriptor->get_parameter_value(fHandle, i); | ||
|
||
// Get parameter name | ||
QString name = "_NO_NAME_"; | ||
if (paramInfo->name != nullptr){ | ||
name = paramInfo->name; | ||
} | ||
|
||
// Create new model for the knob. | ||
floatModels.push_back(new FloatModel(param_value,0.0f,1.0f,0.001f,this,name)); | ||
|
||
// Load settings into model. | ||
QString idStr = CARLA_SETTING_PREFIX + QString::number(i); | ||
floatModels[i]->loadSettings( settingsElem, idStr ); | ||
|
||
// Connect to signal dataChanged to knobChanged function. | ||
connect( floatModels[i], &FloatModel::dataChanged, [=]() { knobModelChanged(i); }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Connecting slots to functors is not supported in Qt4. You have two choices:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I also think you should use |
||
|
||
// TODO Signal view to update? | ||
} | ||
} | ||
} | ||
} | ||
|
||
void CarlaInstrument::clearKnobModels(){ floatModels.clear(); } | ||
|
||
void CarlaInstrument::knobModelChanged(uint32_t index) | ||
{ | ||
float value = floatModels[index]->value(); | ||
if (fDescriptor->set_parameter_value != nullptr){ | ||
fDescriptor->set_parameter_value(fHandle, index, value); | ||
} | ||
} | ||
|
||
void CarlaInstrument::loadSettings(const QDomElement& elem) | ||
|
@@ -318,6 +380,10 @@ void CarlaInstrument::loadSettings(const QDomElement& elem) | |
carlaDoc.appendChild(carlaDoc.importNode(elem.firstChildElement(), true )); | ||
|
||
fDescriptor->set_state(fHandle, carlaDoc.toString(0).toUtf8().constData()); | ||
|
||
// Store to load parameter knobs settings when added. | ||
settingsElem = const_cast<QDomElement&>(elem); | ||
refreshParams(); | ||
} | ||
|
||
void CarlaInstrument::play(sampleFrame* workingBuffer) | ||
|
@@ -473,18 +539,27 @@ CarlaInstrumentView::CarlaInstrumentView(CarlaInstrument* const instrument, QWid | |
: InstrumentView(instrument, parent), | ||
fHandle(instrument->fHandle), | ||
fDescriptor(instrument->fDescriptor), | ||
fTimerId(fHandle != NULL && fDescriptor->ui_idle != NULL ? startTimer(30) : 0) | ||
fTimerId(fHandle != NULL && fDescriptor->ui_idle != NULL ? startTimer(30) : 0), | ||
p_instrument(instrument) | ||
{ | ||
lMaxColumns = 4; | ||
lCurColumn = 0; | ||
lCurRow = 0; | ||
setAutoFillBackground(true); | ||
|
||
QPalette pal; | ||
pal.setBrush(backgroundRole(), instrument->kIsPatchbay ? PLUGIN_NAME::getIconPixmap("artwork-patchbay") : PLUGIN_NAME::getIconPixmap("artwork-rack")); | ||
setPalette(pal); | ||
|
||
QVBoxLayout * l = new QVBoxLayout( this ); | ||
l->setContentsMargins( 20, 180, 10, 10 ); | ||
l->setSpacing( 10 ); | ||
l->setContentsMargins( 3, 40, 3, 3 ); | ||
l->setSpacing( 3 ); | ||
l->setAlignment( Qt::AlignTop ); | ||
|
||
// Horizontal layout for the buttons | ||
QHBoxLayout * hl = new QHBoxLayout(this); | ||
|
||
// Show GUI button | ||
m_toggleUIButton = new QPushButton( tr( "Show GUI" ), this ); | ||
m_toggleUIButton->setCheckable( true ); | ||
m_toggleUIButton->setChecked( false ); | ||
|
@@ -495,10 +570,36 @@ CarlaInstrumentView::CarlaInstrumentView(CarlaInstrument* const instrument, QWid | |
m_toggleUIButton->setWhatsThis( | ||
tr( "Click here to show or hide the graphical user interface (GUI) of Carla." ) ); | ||
|
||
l->addWidget( m_toggleUIButton ); | ||
l->addStretch(); | ||
|
||
// Refresh params button | ||
m_refreshParamsButton = new QPushButton( tr( "" ), this ); | ||
m_refreshParamsButton->setIcon( embed::getIconPixmap( "reload" ) ); | ||
m_refreshParamsButton->setWhatsThis( | ||
tr( "Click here to reload the Carla parameter knobs." ) ); | ||
QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); | ||
sizePolicy.setHorizontalStretch(0); | ||
sizePolicy.setVerticalStretch(0); | ||
sizePolicy.setHeightForWidth(m_refreshParamsButton->sizePolicy().hasHeightForWidth()); | ||
m_refreshParamsButton->setSizePolicy(sizePolicy); | ||
m_refreshParamsButton->setCheckable( false ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mixing old and new coding styles doesn't look good. I suggest putting whitespaces either anywhere or nowhere. |
||
|
||
// ScrollArea that will contain the knobs | ||
m_scrollArea = new QScrollArea(this); | ||
QWidget * scrollAreaWidget = new QWidget( this ); | ||
m_scrollAreaLayout = new QGridLayout( scrollAreaWidget ); | ||
scrollAreaWidget->setLayout( m_scrollAreaLayout ); | ||
m_scrollArea->setWidget( scrollAreaWidget ); | ||
m_scrollArea->setWidgetResizable( true ); | ||
|
||
// Add widgets to layout | ||
hl->addWidget( m_toggleUIButton ); | ||
hl->addWidget( m_refreshParamsButton ); | ||
l->addLayout( hl ); | ||
l->addWidget( m_scrollArea ); | ||
|
||
connect( m_refreshParamsButton, SIGNAL( clicked(bool) ), this, SLOT( onRefreshButton() ) ); | ||
connect(instrument, SIGNAL(uiClosed()), this, SLOT(uiClosed())); | ||
|
||
refreshButtons(); | ||
} | ||
|
||
CarlaInstrumentView::~CarlaInstrumentView() | ||
|
@@ -507,6 +608,57 @@ CarlaInstrumentView::~CarlaInstrumentView() | |
toggleUI(false); | ||
} | ||
|
||
void CarlaInstrumentView::addKnob(FloatModel& knobModel){ | ||
Knob* new_knob = new Knob(this); | ||
|
||
QString name = knobModel.displayName(); | ||
new_knob->setHintText(name,""); | ||
new_knob->setLabel(name); | ||
|
||
// Set the newly created model to the knob. | ||
new_knob->setModel(&knobModel); | ||
|
||
// Add the new knob to layout | ||
m_scrollAreaLayout->addWidget(new_knob, lCurRow, lCurColumn); | ||
|
||
if (lCurColumn < lMaxColumns-1){ | ||
lCurColumn++; | ||
} else { | ||
lCurColumn=0; | ||
lCurRow++; | ||
} | ||
} | ||
void CarlaInstrumentView::clearKnobs(){ | ||
QLayoutItem *item; | ||
while((item = m_scrollAreaLayout->takeAt(0))) { | ||
if (item->widget()) { | ||
delete item->widget(); | ||
} | ||
delete item; | ||
} | ||
lCurColumn = 0; | ||
lCurRow = 0; | ||
} | ||
|
||
void CarlaInstrumentView::onRefreshButton(){ | ||
p_instrument->refreshParams(); | ||
refreshButtons(); | ||
} | ||
|
||
void CarlaInstrumentView::refreshButtons() | ||
{ | ||
CarlaInstrument * instrument = castModel<CarlaInstrument>(); | ||
if (instrument->floatModels.count()==0){return;} | ||
if (instrument->floatModels.count() != m_scrollAreaLayout->count()){ | ||
clearKnobs(); | ||
|
||
for (uint32_t i=0; i < instrument->floatModels.count(); ++i) | ||
{ | ||
addKnob(*instrument->floatModels[i]); | ||
} | ||
} | ||
} | ||
|
||
void CarlaInstrumentView::toggleUI(bool visible) | ||
{ | ||
if (fHandle != NULL && fDescriptor->ui_show != NULL) | ||
|
@@ -520,6 +672,7 @@ void CarlaInstrumentView::uiClosed() | |
|
||
void CarlaInstrumentView::modelChanged() | ||
{ | ||
refreshButtons(); | ||
} | ||
|
||
void CarlaInstrumentView::timerEvent(QTimerEvent* event) | ||
|
@@ -529,6 +682,3 @@ void CarlaInstrumentView::timerEvent(QTimerEvent* event) | |
|
||
InstrumentView::timerEvent(event); | ||
} | ||
|
||
// ------------------------------------------------------------------- | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,12 +25,22 @@ | |
#ifndef CARLA_H | ||
#define CARLA_H | ||
|
||
#define CARLA_MAX_KNOBS 32 | ||
#define CARLA_SETTING_PREFIX "PARAM_KNOB_" | ||
|
||
// qt | ||
#include <QtCore/QMutex> | ||
#include <QScrollArea> | ||
#include <QGridLayout> | ||
#include <QList> | ||
|
||
// carla/source/includes | ||
#include "CarlaNative.h" | ||
|
||
// lmms/include/ | ||
#include "Instrument.h" | ||
#include "InstrumentView.h" | ||
#include "EffectControls.h" | ||
|
||
class QPushButton; | ||
|
||
|
@@ -67,6 +77,9 @@ class PLUGIN_EXPORT CarlaInstrument : public Instrument | |
|
||
private slots: | ||
void sampleRateChanged(); | ||
void refreshParams(); | ||
void clearKnobModels(); | ||
void knobModelChanged(uint32_t index); | ||
|
||
private: | ||
const bool kIsPatchbay; | ||
|
@@ -83,8 +96,13 @@ private slots: | |
QMutex fMutex; | ||
|
||
friend class CarlaInstrumentView; | ||
|
||
QList<FloatModel*> floatModels; | ||
QDomElement settingsElem; | ||
}; | ||
|
||
// ------------------------------------------------------------------- | ||
|
||
class CarlaInstrumentView : public InstrumentView | ||
{ | ||
Q_OBJECT | ||
|
@@ -96,16 +114,33 @@ class CarlaInstrumentView : public InstrumentView | |
private slots: | ||
void toggleUI(bool); | ||
void uiClosed(); | ||
void refreshButtons(); | ||
void onRefreshButton(); | ||
|
||
private: | ||
virtual void modelChanged(); | ||
virtual void timerEvent(QTimerEvent*); | ||
|
||
void addKnob(FloatModel& knobModel); | ||
void clearKnobs(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Our coding convention says you should use tabs, but most part of this file uses spaces. I don't know which one will be better, but please don't mix them like this. You can change indentation after some discussions. |
||
|
||
NativePluginHandle fHandle; | ||
const NativePluginDescriptor* fDescriptor; | ||
int fTimerId; | ||
|
||
CarlaInstrument* const p_instrument; | ||
|
||
uint32_t lMaxColumns; | ||
uint32_t lCurColumn; | ||
uint32_t lCurRow; | ||
|
||
QScrollArea * m_scrollArea; | ||
QGridLayout * m_scrollAreaLayout; | ||
|
||
QPushButton * m_toggleUIButton; | ||
QPushButton * m_refreshParamsButton; | ||
}; | ||
|
||
// ------------------------------------------------------------------- | ||
|
||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you will not need to include
EffectControls.h
here as well as incarla.h
.