jackspa: accept a plugin UID or a plugin Label on the command line
[ng-jackspa.git] / qjackspa.cpp
blobc6469b617f93d8b184df46121409de0ba6fadb8d
1 // qjackspa.cpp - simple Qt4 LADSPA host for the Jack Audio Connection Kit
2 // Copyright © 2013 Géraud Meyer <graud@gmx.com>
3 //
4 // This file is part of ng-jackspa.
5 //
6 // ng-jackspa is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License version 2 as published by the
8 // Free Software Foundation.
9 //
10 // This program is distributed in the hope that it will be useful, but WITHOUT
11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 // more details.
15 // You should have received a copy of the GNU General Public License along
16 // with ng-jackspa. If not, see <http://www.gnu.org/licenses/>.
18 #include <iostream>
19 #include <exception>
20 #include "qjackspa.h"
22 #define PROGRAM_NAME "qjackspa"
23 #include "interface.c"
24 #define PROGRAM_DESCRIPTION_EXTRA PROGRAM_NAME " also accepts standard Qt options.\n\n"
26 int main(int argc, char *argv[])
28 QApplication app(argc, argv);
30 /* Command line options */
31 GError *error = NULL;
32 GOptionContext *context = interface_context();
33 g_option_context_set_description( context, g_strconcat
34 ( PROGRAM_DESCRIPTION_EXTRA,
35 g_option_context_get_description(context), NULL ) );
36 if (!g_option_context_parse(context, &argc, &argv, &error)) {
37 QMessageBox::critical
38 ( 0, QString(PACKAGE_NAME " error"),
39 QString("Option parsing failed"), QMessageBox::Ok );
40 std::cerr << "option parsing failed: " << error->message << std::endl;
41 return -1;
44 /* Main window */
45 QScrollArea window;
47 /* Initialise jackspa */
48 state_t state;
49 if (!jackspa_init(&state, argc, argv)) {
50 QMessageBox::critical
51 ( 0, QString(PACKAGE_NAME " error"),
52 QString("Cannot initialise jackspa"), QMessageBox::Ok );
53 return 1;
56 try
59 /* Main layout */
60 window.setWidget(new QWidget);
61 QVBoxLayout *slider_box = new QVBoxLayout(window.widget());
63 /* Title bar */
64 QPushButton *button;
65 QPushButton *toggle;
67 QGridLayout *title = 0;
68 slider_box->addLayout(title = new QGridLayout);
69 title->addWidget(button = new QPushButton("&Def"), 0, 0);
70 title->addWidget(toggle = new QPushButton("&Xch"), 1, 0);
71 QLabel *label = 0;
72 title->addWidget(label = new QLabel(state.descriptor->Name), 0, 1, 2, 1);
74 button->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
75 toggle->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
76 label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
77 title->setHorizontalSpacing(4);
78 title->setVerticalSpacing(2);
80 /* Initialise the controls */
81 for (unsigned long p = 0, c = 0; p < state.descriptor->PortCount; p++)
82 if ( LADSPA_IS_PORT_INPUT(state.descriptor->PortDescriptors[p]) &&
83 LADSPA_IS_PORT_CONTROL(state.descriptor->PortDescriptors[p]) )
85 ControlLayout *control = 0;
86 slider_box->addLayout(control = new ControlLayout(&state, p, c++));
87 QObject::connect( button, SIGNAL(clicked()),
88 control, SLOT(on_button_pressed()) );
89 QObject::connect( toggle, SIGNAL(clicked()),
90 control, SLOT(exchange_control()) );
93 /* Main layout */
94 slider_box->setContentsMargins(1, 1, 1, 1);
95 slider_box->setSpacing(8);
96 window.setWidgetResizable(true);
97 window.frameSize().setWidth(400);
98 window.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
99 window.setWindowTitle
100 ((*new QString(PROGRAM_NAME "_")).append(state.descriptor->Label));
101 window.show();
104 catch(std::exception const &e)
106 QMessageBox::critical
107 ( 0, QString(PROGRAM_NAME),
108 QString("Exception failure while initialising the Qt interface:\n").
109 append(e.what()),
110 QMessageBox::Ok );
111 throw(e);
114 return app.exec();
117 ControlLayout::ControlLayout(state_t *state, unsigned long port,
118 unsigned long ctrl, QWidget *parent) :
119 QGridLayout(parent),
120 button("Def"),
121 slider(Qt::Horizontal)
123 control_init(&control, state, port, ctrl);
124 label.setText(control.name);
125 number.setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
126 number.setAccelerated(true);
127 number.setDecimals(4);
128 number.setRange( static_cast<double>(control.min),
129 static_cast<double>(control.max) );
130 number.setSingleStep(static_cast<double>(control.inc.fine));
131 slider.setTracking(false);
132 slider.setRange(0, 5000);
133 slider.setSingleStep
134 (5000 / nearbyintf((control.max - control.min) / control.inc.fine));
135 slider.setPageStep
136 (5000 / nearbyintf((control.max - control.min) / control.inc.coarse));
137 if (control.type == JACKSPA_INT || control.type == JACKSPA_TOGGLE) {
138 number.setDecimals(0);
139 slider.setRange(0, nearbyintf(control.max - control.min));
140 slider.setSingleStep(1);
141 slider.setPageStep(2);
142 slider.setTickInterval(1);
143 slider.setTickPosition(QSlider::TicksLeft);
146 /* Setup the widgets' state */
147 number.setValue(static_cast<double>(*control.val));
148 on_number_changed();
150 /* Layout the widgets */
151 setHorizontalSpacing(4);
152 setVerticalSpacing(2);
153 addWidget(&button, 0, 0);
154 addWidget(&number, 1, 0);
155 addWidget(&label, 0, 2);
156 addWidget(&slider, 1, 2);
157 button.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
158 label.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
159 slider.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
161 /* Signal connections */
162 QObject::connect( &number, SIGNAL(valueChanged(double)),
163 this, SLOT(on_number_changed()) );
164 QObject::connect( &slider, SIGNAL(valueChanged(int)),
165 this, SLOT(on_slider_changed()) );
166 QObject::connect( &button, SIGNAL(clicked()),
167 this, SLOT(on_button_pressed()) );
170 void ControlLayout::on_number_changed()
172 *control.val = static_cast<LADSPA_Data>(number.value());
173 set_slider(static_cast<LADSPA_Data>(number.value()));
176 void ControlLayout::on_slider_changed()
178 int num_pos = slider.maximum() - slider.minimum();
179 LADSPA_Data val = control.min +
180 static_cast<LADSPA_Data>(slider.value()) /
181 static_cast<LADSPA_Data>(num_pos) *
182 (control.max - control.min);
184 *control.val = val;
185 number.setValue(static_cast<double>(val));
188 void ControlLayout::on_button_pressed()
190 if (control.def) {
191 *control.val = *control.def;
192 number.setValue(static_cast<double>(*control.def));
193 set_slider(*control.def);
197 void ControlLayout::exchange_control()
199 control_exchange(&control);
200 set_slider(*control.val);
203 void ControlLayout::set_slider(LADSPA_Data val)
205 int num_pos = slider.maximum() - slider.minimum();
207 slider.setValue( static_cast<int>( lrintf
208 ( ((val - control.min) * static_cast<LADSPA_Data>(num_pos)) /
209 (control.max - control.min) ) ) );
210 // setValue() will not emit valueChanged() if it is being set to its
211 // current value