1 // qsamplerDevice.cpp
2 //
3 /****************************************************************************
4    Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved.
5    Copyright (C) 2007, 2008 Christian Schoenebeck
6 
7    This program is free software; you can redistribute it and/or
8    modify it under the terms of the GNU General Public License
9    as published by the Free Software Foundation; either version 2
10    of the License, or (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License along
18    with this program; if not, write to the Free Software Foundation, Inc.,
19    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 
21 *****************************************************************************/
22 
23 #include "qsamplerAbout.h"
24 #include "qsamplerDevice.h"
25 
26 #include "qsamplerMainForm.h"
27 #include "qsamplerDeviceForm.h"
28 
29 #include <QCheckBox>
30 #include <QSpinBox>
31 #include <QLineEdit>
32 
33 
34 namespace QSampler {
35 
36 //-------------------------------------------------------------------------
37 // QSampler::DeviceParam - MIDI/Audio Device parameter structure.
38 //
39 
40 // Constructors.
DeviceParam(lscp_param_info_t * pParamInfo,const char * pszValue)41 DeviceParam::DeviceParam ( lscp_param_info_t *pParamInfo,
42 	const char *pszValue )
43 {
44 	setParam(pParamInfo, pszValue);
45 }
46 
47 
48 // Initializer.
setParam(lscp_param_info_t * pParamInfo,const char * pszValue)49 void DeviceParam::setParam ( lscp_param_info_t *pParamInfo,
50 	const char *pszValue )
51 {
52 	if (pParamInfo == nullptr)
53 		return;
54 
55 	// Info structure field members.
56 
57 	type = pParamInfo->type;
58 
59 	if (pParamInfo->description)
60 		description = pParamInfo->description;
61 	else
62 		description.clear();
63 
64 	mandatory = bool(pParamInfo->mandatory);
65 	fix = bool(pParamInfo->fix);
66 	multiplicity = bool(pParamInfo->multiplicity);
67 
68 	depends.clear();
69 	for (int i = 0; pParamInfo->depends && pParamInfo->depends[i]; i++)
70 		depends.append(pParamInfo->depends[i]);
71 
72 	if (pParamInfo->defaultv)
73 		defaultv = pParamInfo->defaultv;
74 	else
75 		defaultv.clear();
76 
77 	if (pParamInfo->range_min)
78 		range_min = pParamInfo->range_min;
79 	else
80 		range_min.clear();
81 
82 	if (pParamInfo->range_max)
83 		range_max = pParamInfo->range_max;
84 	else
85 		range_max.clear();
86 
87 	possibilities.clear();
88 	for (int i = 0; pParamInfo->possibilities && pParamInfo->possibilities[i]; i++)
89 		possibilities.append(pParamInfo->possibilities[i]);
90 
91 	// The current parameter value.
92 	if (pszValue)
93 		value = pszValue;
94 	else
95 		value.clear();
96 }
97 
98 
99 //-------------------------------------------------------------------------
100 // QSampler::Device - MIDI/Audio Device structure.
101 //
102 
103 // Constructor.
Device(DeviceType deviceType,int iDeviceID)104 Device::Device ( DeviceType deviceType, int iDeviceID )
105 {
106 //	m_ports.setAutoDelete(true);
107 
108 	setDevice(deviceType, iDeviceID);
109 }
110 
111 // Default destructor.
~Device(void)112 Device::~Device (void)
113 {
114 	qDeleteAll(m_ports);
115 	m_ports.clear();
116 }
117 
118 // Copy constructor.
Device(const Device & device)119 Device::Device ( const Device& device )
120 	: m_params(device.m_params), m_ports(device.m_ports)
121 {
122 	m_iDeviceID   = device.m_iDeviceID;
123 	m_deviceType  = device.m_deviceType;
124 	m_sDeviceType = device.m_sDeviceType;
125 	m_sDriverName = device.m_sDriverName;
126 	m_sDeviceName = device.m_sDeviceName;
127 }
128 
129 
130 // Initializer.
setDevice(DeviceType deviceType,int iDeviceID)131 void Device::setDevice ( DeviceType deviceType, int iDeviceID )
132 {
133 	MainForm *pMainForm = MainForm::getInstance();
134 	if (pMainForm == nullptr)
135 		return;
136 	if (pMainForm->client() == nullptr)
137 		return;
138 
139 	// Device id and type should be always set.
140 	m_iDeviceID  = iDeviceID;
141 	m_deviceType = deviceType;
142 
143 	// Reset device parameters and ports anyway.
144 	m_params.clear();
145 	qDeleteAll(m_ports);
146 	m_ports.clear();
147 
148 	// Retrieve device info, if any.
149 	lscp_device_info_t *pDeviceInfo = nullptr;
150 	switch (deviceType) {
151 	case Device::Audio:
152 		m_sDeviceType = QObject::tr("Audio");
153 		if (m_iDeviceID >= 0 && (pDeviceInfo = ::lscp_get_audio_device_info(
154 				pMainForm->client(), m_iDeviceID)) == nullptr)
155 			appendMessagesClient("lscp_get_audio_device_info");
156 		break;
157 	case Device::Midi:
158 		m_sDeviceType = QObject::tr("MIDI");
159 		if (m_iDeviceID >= 0 && (pDeviceInfo = ::lscp_get_midi_device_info(
160 				pMainForm->client(), m_iDeviceID)) == nullptr)
161 			appendMessagesClient("lscp_get_midi_device_info");
162 		break;
163 	case Device::None:
164 		m_sDeviceType.clear();
165 		break;
166 	}
167 	// If we're bogus, bail out...
168 	if (pDeviceInfo == nullptr) {
169 		m_sDriverName.clear();
170 		m_sDeviceName = QObject::tr("New %1 device").arg(m_sDeviceType);
171 		return;
172 	}
173 
174 	// Other device properties...
175 	m_sDriverName = pDeviceInfo->driver;
176 	m_sDeviceName = m_sDriverName + ' '
177 		+ QObject::tr("Device %1").arg(m_iDeviceID);
178 
179 	// Grab device parameters...
180 	for (int i = 0; pDeviceInfo->params && pDeviceInfo->params[i].key; i++) {
181 		const QString sParam = pDeviceInfo->params[i].key;
182 		lscp_param_info_t *pParamInfo = nullptr;
183 		switch (deviceType) {
184 		case Device::Audio:
185 			if ((pParamInfo = ::lscp_get_audio_driver_param_info(
186 					pMainForm->client(), m_sDriverName.toUtf8().constData(),
187 					sParam.toUtf8().constData(), nullptr)) == nullptr)
188 				appendMessagesClient("lscp_get_audio_driver_param_info");
189 			break;
190 		case Device::Midi:
191 			if ((pParamInfo = ::lscp_get_midi_driver_param_info(
192 					pMainForm->client(), m_sDriverName.toUtf8().constData(),
193 					sParam.toUtf8().constData(), nullptr)) == nullptr)
194 				appendMessagesClient("lscp_get_midi_driver_param_info");
195 			break;
196 		case Device::None:
197 			break;
198 		}
199 		if (pParamInfo) {
200 			m_params[sParam.toUpper()] = DeviceParam(pParamInfo,
201 				pDeviceInfo->params[i].value);
202 		}
203 	}
204 
205 	// Refresh parameter dependencies...
206 	refreshParams();
207 	// Set port/channel list...
208 	refreshPorts();
209 }
210 
211 
212 // Driver name initializer/settler.
setDriver(const QString & sDriverName)213 void Device::setDriver ( const QString& sDriverName )
214 {
215 	MainForm *pMainForm = MainForm::getInstance();
216 	if (pMainForm == nullptr)
217 		return;
218 	if (pMainForm->client() == nullptr)
219 		return;
220 
221 	// Valid only for scratch devices.
222 	if (m_sDriverName == sDriverName)
223 		return;
224 
225 	// Reset device parameters and ports anyway.
226 	m_params.clear();
227 	qDeleteAll(m_ports);
228 	m_ports.clear();
229 
230 	// Retrieve driver info, if any.
231 	lscp_driver_info_t *pDriverInfo = nullptr;
232 	switch (m_deviceType) {
233 	case Device::Audio:
234 		if ((pDriverInfo = ::lscp_get_audio_driver_info(pMainForm->client(),
235 				sDriverName.toUtf8().constData())) == nullptr)
236 			appendMessagesClient("lscp_get_audio_driver_info");
237 		break;
238 	case Device::Midi:
239 		if ((pDriverInfo = ::lscp_get_midi_driver_info(pMainForm->client(),
240 				sDriverName.toUtf8().constData())) == nullptr)
241 			appendMessagesClient("lscp_get_midi_driver_info");
242 		break;
243 	case Device::None:
244 		break;
245 	}
246 
247 	// If we're bogus, bail out...
248 	if (pDriverInfo == nullptr)
249 		return;
250 
251 	// Remember device parameters...
252 	m_sDriverName = sDriverName;
253 
254 	// Grab driver parameters...
255 	for (int i = 0; pDriverInfo->parameters && pDriverInfo->parameters[i]; i++) {
256 		const QString sParam = pDriverInfo->parameters[i];
257 		lscp_param_info_t *pParamInfo = nullptr;
258 		switch (m_deviceType) {
259 		case Device::Audio:
260 			if ((pParamInfo = ::lscp_get_audio_driver_param_info(
261 					pMainForm->client(), sDriverName.toUtf8().constData(),
262 					sParam.toUtf8().constData(), nullptr)) == nullptr)
263 				appendMessagesClient("lscp_get_audio_driver_param_info");
264 			break;
265 		case Device::Midi:
266 			if ((pParamInfo = ::lscp_get_midi_driver_param_info(
267 					pMainForm->client(), sDriverName.toUtf8().constData(),
268 					sParam.toUtf8().constData(), nullptr)) == nullptr)
269 				appendMessagesClient("lscp_get_midi_driver_param_info");
270 			break;
271 		case Device::None:
272 			break;
273 		}
274 		if (pParamInfo) {
275 			m_params[sParam.toUpper()] = DeviceParam(pParamInfo,
276 				pParamInfo->defaultv);
277 		}
278 	}
279 
280 	// Refresh parameter dependencies...
281 	refreshParams();
282 	// Set port/channel list...
283 	refreshPorts();
284 }
285 
286 
287 // Device property accessors.
deviceID(void) const288 int Device::deviceID (void) const
289 {
290 	return m_iDeviceID;
291 }
292 
deviceType(void) const293 Device::DeviceType Device::deviceType (void) const
294 {
295 	return m_deviceType;
296 }
297 
deviceTypeName(void) const298 const QString& Device::deviceTypeName (void) const
299 {
300 	return m_sDeviceType;
301 }
302 
driverName(void) const303 const QString& Device::driverName (void) const
304 {
305 	return m_sDriverName;
306 }
307 
308 // Special device name formatter.
deviceName(void) const309 QString Device::deviceName (void) const
310 {
311 	QString sPrefix;
312 	if (m_iDeviceID >= 0)
313 		sPrefix += m_sDeviceType + ' ';
314 	return sPrefix + m_sDeviceName;
315 }
316 
317 
318 // Set the proper device parameter value.
setParam(const QString & sParam,const QString & sValue)319 bool Device::setParam ( const QString& sParam,
320 	const QString& sValue )
321 {
322 	MainForm *pMainForm = MainForm::getInstance();
323 	if (pMainForm == nullptr)
324 		return false;
325 	if (pMainForm->client() == nullptr)
326 		return false;
327 
328 	// Set proper device parameter.
329 	m_params[sParam.toUpper()].value = sValue;
330 
331 	// If the device already exists, things get immediate...
332 	int iRefresh = 0;
333 	if (m_iDeviceID >= 0 && !sValue.isEmpty()) {
334 
335 		// we need temporary byte arrrays with the final strings, because
336 		// i.e. QString::toUtf8() only returns a temporary object and the
337 		// C-style char* pointers for liblscp would immediately be invalidated
338 		QByteArray finalParamKey = sParam.toUtf8();
339 		QByteArray finalParamVal = sValue.toUtf8();
340 
341 		// Prepare parameter struct.
342 		lscp_param_t param;
343 		param.key   = (char *) finalParamKey.constData();
344 		param.value = (char *) finalParamVal.constData();
345 		// Now it depends on the device type...
346 		lscp_status_t ret = LSCP_FAILED;
347 		switch (m_deviceType) {
348 		case Device::Audio:
349 			if (sParam == "CHANNELS") iRefresh++;
350 			if ((ret = ::lscp_set_audio_device_param(pMainForm->client(),
351 					m_iDeviceID, &param)) != LSCP_OK)
352 				appendMessagesClient("lscp_set_audio_device_param");
353 			break;
354 		case Device::Midi:
355 			if (sParam == "PORTS") iRefresh++;
356 			if ((ret = ::lscp_set_midi_device_param(pMainForm->client(),
357 					m_iDeviceID, &param)) != LSCP_OK)
358 				appendMessagesClient("lscp_set_midi_device_param");
359 			break;
360 		case Device::None:
361 			break;
362 		}
363 		// Show result.
364 		if (ret == LSCP_OK) {
365 			appendMessages(QString("%1: %2.").arg(sParam).arg(sValue));
366 			// Special care for specific parameter changes...
367 			if (iRefresh > 0)
368 				iRefresh += refreshPorts();
369 			iRefresh += refreshDepends(sParam);
370 		} else {
371 			// Oops...
372 			appendMessagesError(
373 				QObject::tr("Could not set device parameter value.\n\nSorry."));
374 		}
375 	}
376 
377 	// Return whether we're need a view refresh.
378 	return (iRefresh > 0);
379 }
380 
381 
382 // Device parameter accessor.
params(void) const383 const DeviceParamMap& Device::params (void) const
384 {
385 	return m_params;
386 }
387 
388 
389 // Device port/channel list accessor.
ports(void)390 DevicePortList& Device::ports (void)
391 {
392 	return m_ports;
393 }
394 
395 
396 // Create a new device, as a copy of this current one.
createDevice(void)397 bool Device::createDevice (void)
398 {
399 	MainForm *pMainForm = MainForm::getInstance();
400 	if (pMainForm == nullptr)
401 		return false;
402 	if (pMainForm->client() == nullptr)
403 		return false;
404 
405 	// we need temporary lists with the final strings, because i.e.
406 	// QString::toUtf8() only returns a temporary object and the
407 	// C-style char* pointers for liblscp would immediately be invalidated
408 	QList<QByteArray> finalKeys;
409 	QList<QByteArray> finalVals;
410 
411 	DeviceParamMap::ConstIterator iter;
412 	for (iter = m_params.begin(); iter != m_params.end(); ++iter) {
413 		if (iter.value().value.isEmpty()) continue;
414 		finalKeys.push_back(iter.key().toUtf8());
415 		finalVals.push_back(iter.value().value.toUtf8());
416 	}
417 
418 	// yeah, we DO HAVE to do the two loops separately !
419 
420 	// Build the parameter list...
421 	lscp_param_t *pParams = new lscp_param_t [finalKeys.count() + 1];
422 	int iParam;
423 	for (iParam = 0; iParam < finalKeys.count(); iParam++) {
424 		pParams[iParam].key   = (char *) finalKeys[iParam].constData();
425 		pParams[iParam].value = (char *) finalVals[iParam].constData();
426 	}
427 	// Null terminated.
428 	pParams[iParam].key   = nullptr;
429 	pParams[iParam].value = nullptr;
430 
431 	// Now it depends on the device type...
432 	switch (m_deviceType) {
433 	case Device::Audio:
434 		if ((m_iDeviceID = ::lscp_create_audio_device(pMainForm->client(),
435 				m_sDriverName.toUtf8().constData(), pParams)) < 0)
436 			appendMessagesClient("lscp_create_audio_device");
437 		break;
438 	case Device::Midi:
439 		if ((m_iDeviceID = ::lscp_create_midi_device(pMainForm->client(),
440 				m_sDriverName.toUtf8().constData(), pParams)) < 0)
441 			appendMessagesClient("lscp_create_midi_device");
442 		break;
443 	case Device::None:
444 		break;
445 	}
446 
447 	// Free used parameter array.
448 	delete[] pParams;
449 
450 	// Show result.
451 	if (m_iDeviceID >= 0) {
452 		// Refresh our own stuff...
453 		setDevice(m_deviceType, m_iDeviceID);
454 		appendMessages(QObject::tr("created."));
455 	} else {
456 		appendMessagesError(QObject::tr("Could not create device.\n\nSorry."));
457 	}
458 
459 	// Return whether we're a valid device...
460 	return (m_iDeviceID >= 0);
461 }
462 
463 
464 // Destroy existing device.
deleteDevice(void)465 bool Device::deleteDevice (void)
466 {
467 	MainForm *pMainForm = MainForm::getInstance();
468 	if (pMainForm == nullptr)
469 		return false;
470 	if (pMainForm->client() == nullptr)
471 		return false;
472 
473 	// Now it depends on the device type...
474 	lscp_status_t ret = LSCP_FAILED;
475 	switch (m_deviceType) {
476 	case Device::Audio:
477 		if ((ret = ::lscp_destroy_audio_device(pMainForm->client(),
478 				m_iDeviceID)) != LSCP_OK)
479 			appendMessagesClient("lscp_destroy_audio_device");
480 		break;
481 	case Device::Midi:
482 		if ((ret = ::lscp_destroy_midi_device(pMainForm->client(),
483 				m_iDeviceID)) != LSCP_OK)
484 			appendMessagesClient("lscp_destroy_midi_device");
485 		break;
486 	case Device::None:
487 		break;
488 	}
489 
490 	// Show result.
491 	if (ret == LSCP_OK) {
492 		appendMessages(QObject::tr("deleted."));
493 		m_iDeviceID = -1;
494 	} else {
495 		appendMessagesError(QObject::tr("Could not delete device.\n\nSorry."));
496 	}
497 
498 	// Return whether we've done it..
499 	return (ret == LSCP_OK);
500 }
501 
502 
503 // Device parameter dependencies refreshner.
refreshParams(void)504 int Device::refreshParams (void)
505 {
506 	// This should only make sense for scratch devices...
507 	if (m_iDeviceID >= 0)
508 		return 0;
509 	// Refresh all parameters that have dependencies...
510 	int iParams = 0;
511 	DeviceParamMap::ConstIterator iter;
512 	for (iter = m_params.begin(); iter != m_params.end(); ++iter)
513 		iParams += refreshParam(iter.key());
514 	// Return how many parameters have been refreshed...
515 	return iParams;
516 }
517 
518 
519 // Device port/channel list refreshner.
refreshPorts(void)520 int Device::refreshPorts (void)
521 {
522 	// This should only make sense for actual devices...
523 	if (m_iDeviceID < 0)
524 		return 0;
525 	// Port/channel count determination...
526 	int iPorts = 0;
527 	switch (m_deviceType) {
528 	case Device::Audio:
529 		iPorts = m_params["CHANNELS"].value.toInt();
530 		break;
531 	case Device::Midi:
532 		iPorts = m_params["PORTS"].value.toInt();
533 		break;
534 	case Device::None:
535 		break;
536 	}
537 	// Retrieve port/channel information...
538 	qDeleteAll(m_ports);
539 	m_ports.clear();
540 	for (int iPort = 0; iPort < iPorts; iPort++)
541 		m_ports.append(new DevicePort(*this, iPort));
542 	// Return how many ports have been refreshed...
543 	return iPorts;
544 }
545 
546 
547 // Refresh/set dependencies given that some parameter has changed.
refreshDepends(const QString & sParam)548 int Device::refreshDepends ( const QString& sParam )
549 {
550 	// This should only make sense for scratch devices...
551 	if (m_iDeviceID >= 0)
552 		return 0;
553 	// Refresh all parameters that depend on this one...
554 	int iDepends = 0;
555 	DeviceParamMap::ConstIterator iter;
556 	for (iter = m_params.begin(); iter != m_params.end(); ++iter) {
557 		const QStringList& depends = iter.value().depends;
558 		if (depends.indexOf(sParam) >= 0)
559 			iDepends += refreshParam(iter.key());
560 	}
561 	// Return how many dependencies have been refreshed...
562 	return iDepends;
563 }
564 
565 
566 // Refresh/set given parameter based on driver supplied dependencies.
refreshParam(const QString & sParam)567 int Device::refreshParam ( const QString& sParam )
568 {
569 	MainForm *pMainForm = MainForm::getInstance();
570 	if (pMainForm == nullptr)
571 		return 0;
572 	if (pMainForm->client() == nullptr)
573 		return 0;
574 
575 	// Check if we have dependencies...
576 	DeviceParam& param = m_params[sParam.toUpper()];
577 	if (param.depends.isEmpty())
578 		return 0;
579 
580 	int iRefresh = 0;
581 
582 	// Build dependency list...
583 	lscp_param_t *pDepends = new lscp_param_t [param.depends.count() + 1];
584 	int iDepend = 0;
585 
586 	// we need temporary lists with the final strings, because i.e.
587 	// QString::toUtf8() only returns a temporary object and the
588 	// C-style char* pointers for liblscp would immediately be invalidated
589 	QList<QByteArray> finalKeys;
590 	QList<QByteArray> finalVals;
591 	for (int i = 0; i < param.depends.count(); i++) {
592 		const QString& sDepend = param.depends[i];
593 		finalKeys.push_back(sDepend.toUtf8());
594 		finalVals.push_back(m_params[sDepend.toUpper()].value.toUtf8());
595 	}
596 	// yeah, we DO HAVE to do those two loops separately !
597 	for (int i = 0; i < param.depends.count(); i++) {
598 		pDepends[iDepend].key   = (char *) finalKeys[i].constData();
599 		pDepends[iDepend].value = (char *) finalVals[i].constData();
600 		++iDepend;
601 	}
602 	// Null terminated.
603 	pDepends[iDepend].key   = nullptr;
604 	pDepends[iDepend].value = nullptr;
605 
606 	// FIXME: Some parameter dependencies (e.g.ALSA CARD)
607 	// are blocking for no reason, causing potential timeout-crashes.
608 	// hopefully this gets mitigated if this dependency hell is only
609 	// carried out for scratch devices...
610 
611 	// Retrieve some modern parameters...
612 	lscp_param_info_t *pParamInfo = nullptr;
613 	switch (m_deviceType) {
614 	case Device::Audio:
615 		if ((pParamInfo = ::lscp_get_audio_driver_param_info(
616 				pMainForm->client(), m_sDriverName.toUtf8().constData(),
617 				sParam.toUtf8().constData(), pDepends)) == nullptr)
618 			appendMessagesClient("lscp_get_audio_driver_param_info");
619 		break;
620 	case Device::Midi:
621 		if ((pParamInfo = ::lscp_get_midi_driver_param_info(
622 				pMainForm->client(), m_sDriverName.toUtf8().constData(),
623 				sParam.toUtf8().constData(), pDepends)) == nullptr)
624 			appendMessagesClient("lscp_get_midi_driver_param_info");
625 		break;
626 	case Device::None:
627 		break;
628 	}
629 	if (pParamInfo) {
630 		param = DeviceParam(pParamInfo,
631 			param.value.isEmpty() ? nullptr : param.value.toUtf8().constData());
632 		iRefresh++;
633 	}
634 
635 	// Free used parameter array.
636 	delete[] pDepends;
637 
638 	// Return whether the parameters has been changed...
639 	return iRefresh;
640 }
641 
642 
643 // Redirected messages output methods.
appendMessages(const QString & s) const644 void Device::appendMessages( const QString& s ) const
645 {
646 	MainForm *pMainForm = MainForm::getInstance();
647 	if (pMainForm)
648 		pMainForm->appendMessages(deviceName() + ' ' + s);
649 }
650 
appendMessagesColor(const QString & s,const QColor & rgb) const651 void Device::appendMessagesColor( const QString& s,	const QColor& rgb ) const
652 {
653 	MainForm *pMainForm = MainForm::getInstance();
654 	if (pMainForm)
655 		pMainForm->appendMessagesColor(deviceName() + ' ' + s, rgb);
656 }
657 
appendMessagesText(const QString & s) const658 void Device::appendMessagesText( const QString& s ) const
659 {
660 	MainForm *pMainForm = MainForm::getInstance();
661 	if (pMainForm)
662 		pMainForm->appendMessagesText(deviceName() + ' ' + s);
663 }
664 
appendMessagesError(const QString & s) const665 void Device::appendMessagesError( const QString& s ) const
666 {
667 	MainForm *pMainForm = MainForm::getInstance();
668 	if (pMainForm)
669 		pMainForm->appendMessagesError(deviceName() + "\n\n" + s);
670 }
671 
appendMessagesClient(const QString & s) const672 void Device::appendMessagesClient( const QString& s ) const
673 {
674 	MainForm *pMainForm = MainForm::getInstance();
675 	if (pMainForm)
676 		pMainForm->appendMessagesClient(deviceName() + ' ' + s);
677 }
678 
679 
680 // Device ids enumerator.
getDevices(lscp_client_t * pClient,DeviceType deviceType)681 int *Device::getDevices ( lscp_client_t *pClient,
682 	DeviceType deviceType )
683 {
684 	int *piDeviceIDs = nullptr;
685 	switch (deviceType) {
686 	case Device::Audio:
687 		piDeviceIDs = ::lscp_list_audio_devices(pClient);
688 		break;
689 	case Device::Midi:
690 		piDeviceIDs = ::lscp_list_midi_devices(pClient);
691 		break;
692 	case Device::None:
693 		break;
694 	}
695 	return piDeviceIDs;
696 }
697 
getDeviceIDs(lscp_client_t * pClient,DeviceType deviceType)698 std::set<int> Device::getDeviceIDs(lscp_client_t *pClient,
699 	DeviceType deviceType)
700 {
701 	std::set<int> result;
702 	int* piDeviceIDs = getDevices(pClient, deviceType);
703 	if (!piDeviceIDs) return result;
704 	for (int i = 0; piDeviceIDs[i] != -1; ++i)
705 		result.insert(piDeviceIDs[i]);
706 	return result;
707 }
708 
709 
710 // Driver names enumerator.
getDrivers(lscp_client_t * pClient,DeviceType deviceType)711 QStringList Device::getDrivers ( lscp_client_t *pClient,
712 	DeviceType deviceType )
713 {
714 	QStringList drivers;
715 
716 	const char **ppszDrivers = nullptr;
717 	switch (deviceType) {
718 	case Device::Audio:
719 		ppszDrivers = ::lscp_list_available_audio_drivers(pClient);
720 		break;
721 	case Device::Midi:
722 		ppszDrivers = ::lscp_list_available_midi_drivers(pClient);
723 		break;
724 	case Device::None:
725 		break;
726 	}
727 
728 	for (int iDriver = 0; ppszDrivers && ppszDrivers[iDriver]; iDriver++)
729 		drivers.append(ppszDrivers[iDriver]);
730 
731 	return drivers;
732 }
733 
734 
735 //-------------------------------------------------------------------------
736 // QSampler::DevicePort - MIDI/Audio Device port/channel structure.
737 //
738 
739 // Constructor.
DevicePort(Device & device,int iPortID)740 DevicePort::DevicePort ( Device& device,
741 	int iPortID ) : m_device(device)
742 {
743 	setDevicePort(iPortID);
744 }
745 
746 // Default destructor.
~DevicePort(void)747 DevicePort::~DevicePort (void)
748 {
749 }
750 
751 
752 // Initializer.
setDevicePort(int iPortID)753 void DevicePort::setDevicePort ( int iPortID )
754 {
755 	MainForm *pMainForm = MainForm::getInstance();
756 	if (pMainForm == nullptr)
757 		return;
758 	if (pMainForm->client() == nullptr)
759 		return;
760 
761 	// Device port id should be always set.
762 	m_iPortID = iPortID;
763 
764 	// Reset port parameters anyway.
765 	m_params.clear();
766 
767 	// Retrieve device port/channel info, if any.
768 	lscp_device_port_info_t *pPortInfo = nullptr;
769 	switch (m_device.deviceType()) {
770 	case Device::Audio:
771 		if ((pPortInfo = ::lscp_get_audio_channel_info(pMainForm->client(),
772 				m_device.deviceID(), m_iPortID)) == nullptr)
773 			m_device.appendMessagesClient("lscp_get_audio_channel_info");
774 		break;
775 	case Device::Midi:
776 		if ((pPortInfo = ::lscp_get_midi_port_info(pMainForm->client(),
777 				m_device.deviceID(), m_iPortID)) == nullptr)
778 			m_device.appendMessagesClient("lscp_get_midi_port_info");
779 		break;
780 	case Device::None:
781 		break;
782 	}
783 
784 	// If we're bogus, bail out...
785 	if (pPortInfo == nullptr) {
786 		m_sPortName.clear();
787 		return;
788 	}
789 
790 	// Set device port/channel properties...
791 	m_sPortName = pPortInfo->name;
792 
793 	// Grab device port/channel parameters...
794 	m_params.clear();
795 	for (int i = 0; pPortInfo->params && pPortInfo->params[i].key; i++) {
796 		const QString sParam = pPortInfo->params[i].key;
797 		lscp_param_info_t *pParamInfo = nullptr;
798 		switch (m_device.deviceType()) {
799 		case Device::Audio:
800 			if ((pParamInfo = ::lscp_get_audio_channel_param_info(
801 					pMainForm->client(), m_device.deviceID(),
802 					m_iPortID, sParam.toUtf8().constData())) == nullptr)
803 				m_device.appendMessagesClient("lscp_get_audio_channel_param_info");
804 			break;
805 		case Device::Midi:
806 			if ((pParamInfo = ::lscp_get_midi_port_param_info(
807 					pMainForm->client(), m_device.deviceID(),
808 					m_iPortID, sParam.toUtf8().constData())) == nullptr)
809 				m_device.appendMessagesClient("lscp_get_midi_port_param_info");
810 			break;
811 		case Device::None:
812 			break;
813 		}
814 		if (pParamInfo) {
815 			m_params[sParam.toUpper()] = DeviceParam(pParamInfo,
816 				pPortInfo->params[i].value);
817 		}
818 	}
819 }
820 
821 
822 // Device port/channel property accessors.
portID(void) const823 int DevicePort::portID (void) const
824 {
825 	return m_iPortID;
826 }
827 
portName(void) const828 const QString& DevicePort::portName (void) const
829 {
830 	return m_sPortName;
831 }
832 
833 // Device port/channel parameter accessor.
params(void) const834 const DeviceParamMap& DevicePort::params (void) const
835 {
836 	return m_params;
837 }
838 
839 
840 // Set the proper device port/channel parameter value.
setParam(const QString & sParam,const QString & sValue)841 bool DevicePort::setParam ( const QString& sParam,
842 	const QString& sValue )
843 {
844 	MainForm *pMainForm = MainForm::getInstance();
845 	if (pMainForm == nullptr)
846 		return false;
847 	if (pMainForm->client() == nullptr)
848 		return false;
849 
850 	// Set proper port/channel parameter.
851 	m_params[sParam.toUpper()].value = sValue;
852 
853 	// If the device already exists, things get immediate...
854 	int iRefresh = 0;
855 	if (m_device.deviceID() >= 0 && m_iPortID >= 0) {
856 
857 		// we need temporary byte arrrays with the final strings, because
858 		// i.e. QString::toUtf8() only returns a temporary object and the
859 		// C-style char* pointers for liblscp would immediately be invalidated
860 		QByteArray finalParamKey = sParam.toUtf8();
861 		QByteArray finalParamVal = sValue.toUtf8();
862 
863 		// Prepare parameter struct.
864 		lscp_param_t param;
865 		param.key   = (char *) finalParamKey.constData();
866 		param.value = (char *) finalParamVal.constData();
867 		// Now it depends on the device type...
868 		lscp_status_t ret = LSCP_FAILED;
869 		switch (m_device.deviceType()) {
870 		case Device::Audio:
871 			if ((ret = ::lscp_set_audio_channel_param(pMainForm->client(),
872 					m_device.deviceID(), m_iPortID, &param)) != LSCP_OK)
873 				m_device.appendMessagesClient("lscp_set_audio_channel_param");
874 			break;
875 		case Device::Midi:
876 			if ((ret = ::lscp_set_midi_port_param(pMainForm->client(),
877 					m_device.deviceID(), m_iPortID, &param)) != LSCP_OK)
878 				m_device.appendMessagesClient("lscp_set_midi_port_param");
879 			break;
880 		case Device::None:
881 			break;
882 		}
883 		// Show result.
884 		if (ret == LSCP_OK) {
885 			m_device.appendMessages(m_sPortName
886 				+ ' ' + QString("%1: %2.").arg(sParam).arg(sValue));
887 			iRefresh++;
888 		} else {
889 			m_device.appendMessagesError(
890 				QObject::tr("Could not set %1 parameter value.\n\n"
891 					"Sorry.").arg(m_sPortName));
892 		}
893 	}
894 
895 	// Return whether we're need a view refresh.
896 	return (iRefresh > 0);
897 }
898 
899 
900 //-------------------------------------------------------------------------
901 // QSampler::DeviceItem - QTreeWidget device item.
902 //
903 
904 // Constructors.
DeviceItem(QTreeWidget * pTreeWidget,Device::DeviceType deviceType)905 DeviceItem::DeviceItem ( QTreeWidget* pTreeWidget,
906 	Device::DeviceType deviceType )
907 	: QTreeWidgetItem(pTreeWidget, QSAMPLER_DEVICE_ITEM),
908 		m_device(deviceType)
909 {
910 	switch(m_device.deviceType()) {
911 	case Device::Audio:
912 		setIcon(0, QPixmap(":/images/audio1.png"));
913 		setText(0, QObject::tr("Audio Devices"));
914 		break;
915 	case Device::Midi:
916 		setIcon(0, QPixmap(":/images/midi1.png"));
917 		setText(0, QObject::tr("MIDI Devices"));
918 		break;
919 	case Device::None:
920 		break;
921 	}
922 
923 	// Root items are not selectable...
924 	setFlags(flags() & ~Qt::ItemIsSelectable);
925 }
926 
DeviceItem(QTreeWidgetItem * pItem,Device::DeviceType deviceType,int iDeviceID)927 DeviceItem::DeviceItem ( QTreeWidgetItem* pItem,
928 	Device::DeviceType deviceType,
929 	int iDeviceID )
930 	: QTreeWidgetItem(pItem, QSAMPLER_DEVICE_ITEM),
931 		m_device(deviceType, iDeviceID)
932 {
933 	switch(m_device.deviceType()) {
934 	case Device::Audio:
935 		setIcon(0, QPixmap(":/images/audio2.png"));
936 		break;
937 	case Device::Midi:
938 		setIcon(0, QPixmap(":/images/midi2.png"));
939 		break;
940 	case Device::None:
941 		break;
942 	}
943 
944 	setText(0, m_device.deviceName());
945 }
946 
947 // Default destructor.
~DeviceItem()948 DeviceItem::~DeviceItem ()
949 {
950 }
951 
952 // Instance accessors.
device()953 Device& DeviceItem::device ()
954 {
955 	return m_device;
956 }
957 
958 
959 //-------------------------------------------------------------------------
960 // QSampler::AbstractDeviceParamModel - data model base class for device parameters
961 //
962 
AbstractDeviceParamModel(QObject * pParent)963 AbstractDeviceParamModel::AbstractDeviceParamModel ( QObject* pParent )
964 	: QAbstractTableModel(pParent), m_bEditable(false)
965 {
966 	m_pParams = nullptr;
967 }
968 
969 
rowCount(const QModelIndex &) const970 int AbstractDeviceParamModel::rowCount ( const QModelIndex& /*parent*/) const
971 {
972 	//std::cout << "model size=" << params.size() << "\n" << std::flush;
973 	return (m_pParams ? m_pParams->size() : 0);
974 }
975 
976 
columnCount(const QModelIndex &) const977 int AbstractDeviceParamModel::columnCount ( const QModelIndex& /*parent*/) const
978 {
979 	return 3;
980 }
981 
982 
flags(const QModelIndex &) const983 Qt::ItemFlags AbstractDeviceParamModel::flags ( const QModelIndex& /*index*/) const
984 {
985 	return Qt::ItemIsEditable | Qt::ItemIsEnabled;
986 }
987 
988 
headerData(int section,Qt::Orientation orientation,int role) const989 QVariant AbstractDeviceParamModel::headerData (
990 	int section, Qt::Orientation orientation, int role) const
991 {
992 	if (role != Qt::DisplayRole)
993 		return QVariant();
994 
995 	if (orientation == Qt::Horizontal) {
996 		switch (section) {
997 			case 0:  return tr("Parameter");
998 			case 1:  return tr("Value");
999 			case 2:  return tr("Description");
1000 			default: return QVariant();
1001 		}
1002 	}
1003 
1004 	return QVariant();
1005 }
1006 
1007 
refresh(const DeviceParamMap * pParams,bool bEditable)1008 void AbstractDeviceParamModel::refresh (
1009 	const DeviceParamMap* pParams, bool bEditable )
1010 {
1011 	m_pParams   = pParams;
1012 	m_bEditable = bEditable;
1013 	// inform the outer world (QTableView) that our data changed
1014 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
1015 	QAbstractTableModel::reset();
1016 #else
1017 	QAbstractTableModel::beginResetModel();
1018 	QAbstractTableModel::endResetModel();
1019 #endif
1020 }
1021 
1022 
clear(void)1023 void AbstractDeviceParamModel::clear (void)
1024 {
1025 	m_pParams = nullptr;
1026 	// inform the outer world (QTableView) that our data changed
1027 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
1028 	QAbstractTableModel::reset();
1029 #else
1030 	QAbstractTableModel::beginResetModel();
1031 	QAbstractTableModel::endResetModel();
1032 #endif
1033 }
1034 
1035 
1036 //-------------------------------------------------------------------------
1037 // QSampler::DeviceParamModel - data model for device parameters
1038 //                              (used for QTableView)
1039 
DeviceParamModel(QObject * pParent)1040 DeviceParamModel::DeviceParamModel ( QObject *pParent )
1041 	: AbstractDeviceParamModel(pParent)
1042 {
1043 	m_pDevice = nullptr;
1044 }
1045 
data(const QModelIndex & index,int role) const1046 QVariant DeviceParamModel::data (
1047 	const QModelIndex &index, int role) const
1048 {
1049 	if (!index.isValid())
1050 		return QVariant();
1051 
1052 	if (role != Qt::DisplayRole)
1053 		return QVariant();
1054 
1055 	DeviceParameterRow item;
1056 	item.name  = m_pParams->keys()[index.row()];
1057 	item.param = (*m_pParams)[item.name];
1058 	item.alive = (m_pDevice && m_pDevice->deviceID() >= 0);
1059 
1060 	return QVariant::fromValue(item);
1061 }
1062 
1063 
setData(const QModelIndex & index,const QVariant & value,int)1064 bool DeviceParamModel::setData (
1065 	const QModelIndex& index, const QVariant& value, int /*role*/)
1066 {
1067 	if (!index.isValid())
1068 		return false;
1069 
1070 	QString key = m_pParams->keys()[index.row()];
1071 	//m_pParams[key].value = value.toString();
1072 	m_pDevice->setParam(key, value.toString());
1073 	emit dataChanged(index, index);
1074 	return true;
1075 }
1076 
1077 
refresh(Device * pDevice,bool bEditable)1078 void DeviceParamModel::refresh ( Device* pDevice, bool bEditable )
1079 {
1080 	m_pDevice = pDevice;
1081 	AbstractDeviceParamModel::refresh(&pDevice->params(), bEditable);
1082 }
1083 
1084 
clear(void)1085 void DeviceParamModel::clear (void)
1086 {
1087 	AbstractDeviceParamModel::clear();
1088 	m_pDevice = nullptr;
1089 }
1090 
1091 
1092 //-------------------------------------------------------------------------
1093 // QSampler::PortParamModel - data model for port parameters
1094 //                            (used for QTableView)
1095 
PortParamModel(QObject * pParent)1096 PortParamModel::PortParamModel ( QObject *pParent)
1097 	: AbstractDeviceParamModel(pParent)
1098 {
1099 	m_pPort = nullptr;
1100 }
1101 
data(const QModelIndex & index,int role) const1102 QVariant PortParamModel::data ( const QModelIndex &index, int role ) const
1103 {
1104 	if (!index.isValid())
1105 		return QVariant();
1106 
1107 	if (role != Qt::DisplayRole)
1108 		return QVariant();
1109 
1110 	DeviceParameterRow item;
1111 	item.name  = m_pParams->keys()[index.row()];
1112 	item.param = (*m_pParams)[item.name];
1113 	item.alive = (m_pPort && m_pPort->portID() >= 0);
1114 
1115 	return QVariant::fromValue(item);
1116 }
1117 
1118 
setData(const QModelIndex & index,const QVariant & value,int)1119 bool PortParamModel::setData (
1120 	const QModelIndex& index, const QVariant& value, int /*role*/)
1121 {
1122 	if (!index.isValid())
1123 		return false;
1124 
1125 	QString key = m_pParams->keys()[index.row()];
1126 	//params[key].value = value.toString();
1127 	m_pPort->setParam(key, value.toString());
1128 	emit dataChanged(index, index);
1129 	return true;
1130 }
1131 
1132 
refresh(DevicePort * pPort,bool bEditable)1133 void PortParamModel::refresh ( DevicePort* pPort, bool bEditable )
1134 {
1135 	m_pPort = pPort;
1136 	AbstractDeviceParamModel::refresh(&pPort->params(), bEditable);
1137 }
1138 
1139 
clear(void)1140 void PortParamModel::clear (void)
1141 {
1142 	AbstractDeviceParamModel::clear();
1143 	m_pPort = nullptr;
1144 }
1145 
1146 
1147 //-------------------------------------------------------------------------
1148 // QSampler::DeviceParamDelegate - table cell renderer for device/port parameters
1149 //
1150 
DeviceParamDelegate(QObject * pParent)1151 DeviceParamDelegate::DeviceParamDelegate ( QObject *pParent)
1152 	: QItemDelegate(pParent)
1153 {
1154 }
1155 
1156 
createEditor(QWidget * pParent,const QStyleOptionViewItem &,const QModelIndex & index) const1157 QWidget* DeviceParamDelegate::createEditor ( QWidget *pParent,
1158 	const QStyleOptionViewItem& /* option */, const QModelIndex& index ) const
1159 {
1160 	if (!index.isValid())
1161 		return nullptr;
1162 
1163 	DeviceParameterRow r = index.model()->data(index,
1164 		Qt::DisplayRole).value<DeviceParameterRow>();
1165 
1166 	const bool bEnabled = (r.alive) ? !r.param.fix : true;
1167 	const bool bFix = r.param.fix;
1168 
1169 	QString val = (r.alive) ? r.param.value : r.param.defaultv;
1170 
1171 	switch (index.column()) {
1172 		case 0:
1173 			return new QLabel(r.name, pParent);
1174 		case 1: {
1175 			if (r.param.type == LSCP_TYPE_BOOL) {
1176 				QCheckBox *pCheckBox = new QCheckBox(pParent);
1177 				if (!val.isEmpty())
1178 					pCheckBox->setChecked(val.toLower() == "true");
1179 				pCheckBox->setEnabled(bEnabled);
1180 				pCheckBox->setCheckable(!bFix);
1181 				return pCheckBox;
1182 			} else if (r.param.possibilities.count() > 0) {
1183 				QStringList opts = r.param.possibilities;
1184 				if (r.param.multiplicity)
1185 					opts.prepend(tr("(none)"));
1186 				QComboBox *pComboBox = new QComboBox(pParent);
1187 				pComboBox->addItems(opts);
1188 				if (r.param.value.isEmpty())
1189 					pComboBox->setCurrentIndex(0);
1190 				else
1191 					pComboBox->setCurrentIndex(pComboBox->findText(val));
1192 				pComboBox->setEnabled(bEnabled);
1193 				pComboBox->setEditable(!bFix);
1194 				return pComboBox;
1195 			} else if (r.param.type == LSCP_TYPE_INT && bEnabled) {
1196 				QSpinBox *pSpinBox = new QSpinBox(pParent);
1197 				pSpinBox->setMinimum(
1198 					(!r.param.range_min.isEmpty()) ?
1199 						r.param.range_min.toInt() : 0 // or better a negative default min value ?
1200 				);
1201 				pSpinBox->setMaximum(
1202 					(!r.param.range_max.isEmpty()) ?
1203 						r.param.range_max.toInt() : (1 << 24) // or better a higher default max value ?
1204 				);
1205 				pSpinBox->setValue(val.toInt());
1206 				pSpinBox->setReadOnly(bFix);
1207 				return pSpinBox;
1208 			} else if (bEnabled) {
1209 				QLineEdit *pLineEdit = new QLineEdit(val, pParent);
1210 				pLineEdit->setReadOnly(bFix);
1211 				return pLineEdit;
1212 			} else {
1213 				QLabel *pLabel = new QLabel(val, pParent);
1214 				return pLabel;
1215 			}
1216 		}
1217 		case 2:
1218 			return new QLabel(r.param.description, pParent);
1219 		default:
1220 			return nullptr;
1221 	}
1222 }
1223 
1224 
setEditorData(QWidget *,const QModelIndex &) const1225 void DeviceParamDelegate::setEditorData (
1226 	QWidget* /*pEditor*/, const QModelIndex& /*index*/) const
1227 {
1228 	// Unused, since we set the editor data already in createEditor()
1229 }
1230 
1231 
setModelData(QWidget * pEditor,QAbstractItemModel * pModel,const QModelIndex & index) const1232 void DeviceParamDelegate::setModelData ( QWidget *pEditor,
1233 	QAbstractItemModel *pModel, const QModelIndex& index ) const
1234 {
1235 	if (index.column() == 1) {
1236 		DeviceParameterRow r = index.model()->data(index,
1237 			Qt::DisplayRole).value<DeviceParameterRow> ();
1238 		if (pEditor->metaObject()->className() == QString("QCheckBox")) {
1239 			QCheckBox *pCheckBox = static_cast<QCheckBox *> (pEditor);
1240 			pModel->setData(index, QVariant(pCheckBox->checkState() == Qt::Checked));
1241 		} else if (pEditor->metaObject()->className() == QString("QComboBox")) {
1242 			QComboBox *pComboBox = static_cast<QComboBox *> (pEditor);
1243 			pModel->setData(index, pComboBox->currentText());
1244 		} else if (pEditor->metaObject()->className() == QString("QSpinBox")) {
1245 			QSpinBox *pSpinBox = static_cast<QSpinBox *> (pEditor);
1246 			pModel->setData(index, pSpinBox->value());
1247 		} else if (pEditor->metaObject()->className() == QString("QLineEdit")) {
1248 			QLineEdit *pLineEdit = static_cast<QLineEdit *> (pEditor);
1249 			pModel->setData(index, pLineEdit->text());
1250 		} else if (pEditor->metaObject()->className() == QString("QLabel")) {
1251 			QLabel *pLabel = static_cast<QLabel *> (pEditor);
1252 			pModel->setData(index, pLabel->text());
1253 		}
1254 	}
1255 }
1256 
updateEditorGeometry(QWidget * pEditor,const QStyleOptionViewItem & option,const QModelIndex &) const1257 void DeviceParamDelegate::updateEditorGeometry ( QWidget *pEditor,
1258 	const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
1259 {
1260 	if (pEditor)
1261 		pEditor->setGeometry(option.rect);
1262 }
1263 
1264 } // namespace QSampler
1265 
1266 // end of qsamplerDevice.cpp
1267