/[svn]/qsampler/trunk/src/qsamplerDevice.cpp
ViewVC logotype

Contents of /qsampler/trunk/src/qsamplerDevice.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3788 - (show annotations) (download)
Thu Jun 11 16:59:09 2020 UTC (3 years, 10 months ago) by capela
File size: 34048 byte(s)
- Messages widget micro-refactoring.
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.
41 DeviceParam::DeviceParam ( lscp_param_info_t *pParamInfo,
42 const char *pszValue )
43 {
44 setParam(pParamInfo, pszValue);
45 }
46
47
48 // Initializer.
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.
104 Device::Device ( DeviceType deviceType, int iDeviceID )
105 {
106 // m_ports.setAutoDelete(true);
107
108 setDevice(deviceType, iDeviceID);
109 }
110
111 // Default destructor.
112 Device::~Device (void)
113 {
114 qDeleteAll(m_ports);
115 m_ports.clear();
116 }
117
118 // Copy constructor.
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.
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.
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.
288 int Device::deviceID (void) const
289 {
290 return m_iDeviceID;
291 }
292
293 Device::DeviceType Device::deviceType (void) const
294 {
295 return m_deviceType;
296 }
297
298 const QString& Device::deviceTypeName (void) const
299 {
300 return m_sDeviceType;
301 }
302
303 const QString& Device::driverName (void) const
304 {
305 return m_sDriverName;
306 }
307
308 // Special device name formatter.
309 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.
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.
383 const DeviceParamMap& Device::params (void) const
384 {
385 return m_params;
386 }
387
388
389 // Device port/channel list accessor.
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.
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.
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.
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.
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.
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.
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.
644 void Device::appendMessages( const QString& s ) const
645 {
646 MainForm *pMainForm = MainForm::getInstance();
647 if (pMainForm)
648 pMainForm->appendMessages(deviceName() + ' ' + s);
649 }
650
651 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
658 void Device::appendMessagesText( const QString& s ) const
659 {
660 MainForm *pMainForm = MainForm::getInstance();
661 if (pMainForm)
662 pMainForm->appendMessagesText(deviceName() + ' ' + s);
663 }
664
665 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
672 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.
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
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.
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.
740 DevicePort::DevicePort ( Device& device,
741 int iPortID ) : m_device(device)
742 {
743 setDevicePort(iPortID);
744 }
745
746 // Default destructor.
747 DevicePort::~DevicePort (void)
748 {
749 }
750
751
752 // Initializer.
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.
823 int DevicePort::portID (void) const
824 {
825 return m_iPortID;
826 }
827
828 const QString& DevicePort::portName (void) const
829 {
830 return m_sPortName;
831 }
832
833 // Device port/channel parameter accessor.
834 const DeviceParamMap& DevicePort::params (void) const
835 {
836 return m_params;
837 }
838
839
840 // Set the proper device port/channel parameter value.
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.
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
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.
948 DeviceItem::~DeviceItem ()
949 {
950 }
951
952 // Instance accessors.
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
963 AbstractDeviceParamModel::AbstractDeviceParamModel ( QObject* pParent )
964 : QAbstractTableModel(pParent), m_bEditable(false)
965 {
966 m_pParams = nullptr;
967 }
968
969
970 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
977 int AbstractDeviceParamModel::columnCount ( const QModelIndex& /*parent*/) const
978 {
979 return 3;
980 }
981
982
983 Qt::ItemFlags AbstractDeviceParamModel::flags ( const QModelIndex& /*index*/) const
984 {
985 return Qt::ItemIsEditable | Qt::ItemIsEnabled;
986 }
987
988
989 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
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
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
1040 DeviceParamModel::DeviceParamModel ( QObject *pParent )
1041 : AbstractDeviceParamModel(pParent)
1042 {
1043 m_pDevice = nullptr;
1044 }
1045
1046 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
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
1078 void DeviceParamModel::refresh ( Device* pDevice, bool bEditable )
1079 {
1080 m_pDevice = pDevice;
1081 AbstractDeviceParamModel::refresh(&pDevice->params(), bEditable);
1082 }
1083
1084
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
1096 PortParamModel::PortParamModel ( QObject *pParent)
1097 : AbstractDeviceParamModel(pParent)
1098 {
1099 m_pPort = nullptr;
1100 }
1101
1102 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
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
1133 void PortParamModel::refresh ( DevicePort* pPort, bool bEditable )
1134 {
1135 m_pPort = pPort;
1136 AbstractDeviceParamModel::refresh(&pPort->params(), bEditable);
1137 }
1138
1139
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
1151 DeviceParamDelegate::DeviceParamDelegate ( QObject *pParent)
1152 : QItemDelegate(pParent)
1153 {
1154 }
1155
1156
1157 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
1225 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
1232 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
1257 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

  ViewVC Help
Powered by ViewVC