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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3555 - (show annotations) (download)
Tue Aug 13 10:19:32 2019 UTC (3 months, 1 week ago) by capela
File size: 34046 byte(s)
- In late compliance to C++11, all NULL constants replaced for nullptr.
1 // qsamplerDevice.cpp
2 //
3 /****************************************************************************
4 Copyright (C) 2004-2019, 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,
652 const QString& c ) const
653 {
654 MainForm *pMainForm = MainForm::getInstance();
655 if (pMainForm)
656 pMainForm->appendMessagesColor(deviceName() + ' ' + s, c);
657 }
658
659 void Device::appendMessagesText( const QString& s ) const
660 {
661 MainForm *pMainForm = MainForm::getInstance();
662 if (pMainForm)
663 pMainForm->appendMessagesText(deviceName() + ' ' + s);
664 }
665
666 void Device::appendMessagesError( const QString& s ) const
667 {
668 MainForm *pMainForm = MainForm::getInstance();
669 if (pMainForm)
670 pMainForm->appendMessagesError(deviceName() + "\n\n" + s);
671 }
672
673 void Device::appendMessagesClient( const QString& s ) const
674 {
675 MainForm *pMainForm = MainForm::getInstance();
676 if (pMainForm)
677 pMainForm->appendMessagesClient(deviceName() + ' ' + s);
678 }
679
680
681 // Device ids enumerator.
682 int *Device::getDevices ( lscp_client_t *pClient,
683 DeviceType deviceType )
684 {
685 int *piDeviceIDs = nullptr;
686 switch (deviceType) {
687 case Device::Audio:
688 piDeviceIDs = ::lscp_list_audio_devices(pClient);
689 break;
690 case Device::Midi:
691 piDeviceIDs = ::lscp_list_midi_devices(pClient);
692 break;
693 case Device::None:
694 break;
695 }
696 return piDeviceIDs;
697 }
698
699 std::set<int> Device::getDeviceIDs(lscp_client_t *pClient,
700 DeviceType deviceType)
701 {
702 std::set<int> result;
703 int* piDeviceIDs = getDevices(pClient, deviceType);
704 if (!piDeviceIDs) return result;
705 for (int i = 0; piDeviceIDs[i] != -1; ++i)
706 result.insert(piDeviceIDs[i]);
707 return result;
708 }
709
710
711 // Driver names enumerator.
712 QStringList Device::getDrivers ( lscp_client_t *pClient,
713 DeviceType deviceType )
714 {
715 QStringList drivers;
716
717 const char **ppszDrivers = nullptr;
718 switch (deviceType) {
719 case Device::Audio:
720 ppszDrivers = ::lscp_list_available_audio_drivers(pClient);
721 break;
722 case Device::Midi:
723 ppszDrivers = ::lscp_list_available_midi_drivers(pClient);
724 break;
725 case Device::None:
726 break;
727 }
728
729 for (int iDriver = 0; ppszDrivers && ppszDrivers[iDriver]; iDriver++)
730 drivers.append(ppszDrivers[iDriver]);
731
732 return drivers;
733 }
734
735
736 //-------------------------------------------------------------------------
737 // QSampler::DevicePort - MIDI/Audio Device port/channel structure.
738 //
739
740 // Constructor.
741 DevicePort::DevicePort ( Device& device,
742 int iPortID ) : m_device(device)
743 {
744 setDevicePort(iPortID);
745 }
746
747 // Default destructor.
748 DevicePort::~DevicePort (void)
749 {
750 }
751
752
753 // Initializer.
754 void DevicePort::setDevicePort ( int iPortID )
755 {
756 MainForm *pMainForm = MainForm::getInstance();
757 if (pMainForm == nullptr)
758 return;
759 if (pMainForm->client() == nullptr)
760 return;
761
762 // Device port id should be always set.
763 m_iPortID = iPortID;
764
765 // Reset port parameters anyway.
766 m_params.clear();
767
768 // Retrieve device port/channel info, if any.
769 lscp_device_port_info_t *pPortInfo = nullptr;
770 switch (m_device.deviceType()) {
771 case Device::Audio:
772 if ((pPortInfo = ::lscp_get_audio_channel_info(pMainForm->client(),
773 m_device.deviceID(), m_iPortID)) == nullptr)
774 m_device.appendMessagesClient("lscp_get_audio_channel_info");
775 break;
776 case Device::Midi:
777 if ((pPortInfo = ::lscp_get_midi_port_info(pMainForm->client(),
778 m_device.deviceID(), m_iPortID)) == nullptr)
779 m_device.appendMessagesClient("lscp_get_midi_port_info");
780 break;
781 case Device::None:
782 break;
783 }
784
785 // If we're bogus, bail out...
786 if (pPortInfo == nullptr) {
787 m_sPortName.clear();
788 return;
789 }
790
791 // Set device port/channel properties...
792 m_sPortName = pPortInfo->name;
793
794 // Grab device port/channel parameters...
795 m_params.clear();
796 for (int i = 0; pPortInfo->params && pPortInfo->params[i].key; i++) {
797 const QString sParam = pPortInfo->params[i].key;
798 lscp_param_info_t *pParamInfo = nullptr;
799 switch (m_device.deviceType()) {
800 case Device::Audio:
801 if ((pParamInfo = ::lscp_get_audio_channel_param_info(
802 pMainForm->client(), m_device.deviceID(),
803 m_iPortID, sParam.toUtf8().constData())) == nullptr)
804 m_device.appendMessagesClient("lscp_get_audio_channel_param_info");
805 break;
806 case Device::Midi:
807 if ((pParamInfo = ::lscp_get_midi_port_param_info(
808 pMainForm->client(), m_device.deviceID(),
809 m_iPortID, sParam.toUtf8().constData())) == nullptr)
810 m_device.appendMessagesClient("lscp_get_midi_port_param_info");
811 break;
812 case Device::None:
813 break;
814 }
815 if (pParamInfo) {
816 m_params[sParam.toUpper()] = DeviceParam(pParamInfo,
817 pPortInfo->params[i].value);
818 }
819 }
820 }
821
822
823 // Device port/channel property accessors.
824 int DevicePort::portID (void) const
825 {
826 return m_iPortID;
827 }
828
829 const QString& DevicePort::portName (void) const
830 {
831 return m_sPortName;
832 }
833
834 // Device port/channel parameter accessor.
835 const DeviceParamMap& DevicePort::params (void) const
836 {
837 return m_params;
838 }
839
840
841 // Set the proper device port/channel parameter value.
842 bool DevicePort::setParam ( const QString& sParam,
843 const QString& sValue )
844 {
845 MainForm *pMainForm = MainForm::getInstance();
846 if (pMainForm == nullptr)
847 return false;
848 if (pMainForm->client() == nullptr)
849 return false;
850
851 // Set proper port/channel parameter.
852 m_params[sParam.toUpper()].value = sValue;
853
854 // If the device already exists, things get immediate...
855 int iRefresh = 0;
856 if (m_device.deviceID() >= 0 && m_iPortID >= 0) {
857
858 // we need temporary byte arrrays with the final strings, because
859 // i.e. QString::toUtf8() only returns a temporary object and the
860 // C-style char* pointers for liblscp would immediately be invalidated
861 QByteArray finalParamKey = sParam.toUtf8();
862 QByteArray finalParamVal = sValue.toUtf8();
863
864 // Prepare parameter struct.
865 lscp_param_t param;
866 param.key = (char *) finalParamKey.constData();
867 param.value = (char *) finalParamVal.constData();
868 // Now it depends on the device type...
869 lscp_status_t ret = LSCP_FAILED;
870 switch (m_device.deviceType()) {
871 case Device::Audio:
872 if ((ret = ::lscp_set_audio_channel_param(pMainForm->client(),
873 m_device.deviceID(), m_iPortID, &param)) != LSCP_OK)
874 m_device.appendMessagesClient("lscp_set_audio_channel_param");
875 break;
876 case Device::Midi:
877 if ((ret = ::lscp_set_midi_port_param(pMainForm->client(),
878 m_device.deviceID(), m_iPortID, &param)) != LSCP_OK)
879 m_device.appendMessagesClient("lscp_set_midi_port_param");
880 break;
881 case Device::None:
882 break;
883 }
884 // Show result.
885 if (ret == LSCP_OK) {
886 m_device.appendMessages(m_sPortName
887 + ' ' + QString("%1: %2.").arg(sParam).arg(sValue));
888 iRefresh++;
889 } else {
890 m_device.appendMessagesError(
891 QObject::tr("Could not set %1 parameter value.\n\n"
892 "Sorry.").arg(m_sPortName));
893 }
894 }
895
896 // Return whether we're need a view refresh.
897 return (iRefresh > 0);
898 }
899
900
901 //-------------------------------------------------------------------------
902 // QSampler::DeviceItem - QTreeWidget device item.
903 //
904
905 // Constructors.
906 DeviceItem::DeviceItem ( QTreeWidget* pTreeWidget,
907 Device::DeviceType deviceType )
908 : QTreeWidgetItem(pTreeWidget, QSAMPLER_DEVICE_ITEM),
909 m_device(deviceType)
910 {
911 switch(m_device.deviceType()) {
912 case Device::Audio:
913 setIcon(0, QPixmap(":/images/audio1.png"));
914 setText(0, QObject::tr("Audio Devices"));
915 break;
916 case Device::Midi:
917 setIcon(0, QPixmap(":/images/midi1.png"));
918 setText(0, QObject::tr("MIDI Devices"));
919 break;
920 case Device::None:
921 break;
922 }
923
924 // Root items are not selectable...
925 setFlags(flags() & ~Qt::ItemIsSelectable);
926 }
927
928 DeviceItem::DeviceItem ( QTreeWidgetItem* pItem,
929 Device::DeviceType deviceType,
930 int iDeviceID )
931 : QTreeWidgetItem(pItem, QSAMPLER_DEVICE_ITEM),
932 m_device(deviceType, iDeviceID)
933 {
934 switch(m_device.deviceType()) {
935 case Device::Audio:
936 setIcon(0, QPixmap(":/images/audio2.png"));
937 break;
938 case Device::Midi:
939 setIcon(0, QPixmap(":/images/midi2.png"));
940 break;
941 case Device::None:
942 break;
943 }
944
945 setText(0, m_device.deviceName());
946 }
947
948 // Default destructor.
949 DeviceItem::~DeviceItem ()
950 {
951 }
952
953 // Instance accessors.
954 Device& DeviceItem::device ()
955 {
956 return m_device;
957 }
958
959
960 //-------------------------------------------------------------------------
961 // QSampler::AbstractDeviceParamModel - data model base class for device parameters
962 //
963
964 AbstractDeviceParamModel::AbstractDeviceParamModel ( QObject* pParent )
965 : QAbstractTableModel(pParent), m_bEditable(false)
966 {
967 m_pParams = nullptr;
968 }
969
970
971 int AbstractDeviceParamModel::rowCount ( const QModelIndex& /*parent*/) const
972 {
973 //std::cout << "model size=" << params.size() << "\n" << std::flush;
974 return (m_pParams ? m_pParams->size() : 0);
975 }
976
977
978 int AbstractDeviceParamModel::columnCount ( const QModelIndex& /*parent*/) const
979 {
980 return 3;
981 }
982
983
984 Qt::ItemFlags AbstractDeviceParamModel::flags ( const QModelIndex& /*index*/) const
985 {
986 return Qt::ItemIsEditable | Qt::ItemIsEnabled;
987 }
988
989
990 QVariant AbstractDeviceParamModel::headerData (
991 int section, Qt::Orientation orientation, int role) const
992 {
993 if (role != Qt::DisplayRole)
994 return QVariant();
995
996 if (orientation == Qt::Horizontal) {
997 switch (section) {
998 case 0: return tr("Parameter");
999 case 1: return tr("Value");
1000 case 2: return tr("Description");
1001 default: return QVariant();
1002 }
1003 }
1004
1005 return QVariant();
1006 }
1007
1008
1009 void AbstractDeviceParamModel::refresh (
1010 const DeviceParamMap* pParams, bool bEditable )
1011 {
1012 m_pParams = pParams;
1013 m_bEditable = bEditable;
1014 // inform the outer world (QTableView) that our data changed
1015 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
1016 QAbstractTableModel::reset();
1017 #else
1018 QAbstractTableModel::beginResetModel();
1019 QAbstractTableModel::endResetModel();
1020 #endif
1021 }
1022
1023
1024 void AbstractDeviceParamModel::clear (void)
1025 {
1026 m_pParams = nullptr;
1027 // inform the outer world (QTableView) that our data changed
1028 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
1029 QAbstractTableModel::reset();
1030 #else
1031 QAbstractTableModel::beginResetModel();
1032 QAbstractTableModel::endResetModel();
1033 #endif
1034 }
1035
1036
1037 //-------------------------------------------------------------------------
1038 // QSampler::DeviceParamModel - data model for device parameters
1039 // (used for QTableView)
1040
1041 DeviceParamModel::DeviceParamModel ( QObject *pParent )
1042 : AbstractDeviceParamModel(pParent)
1043 {
1044 m_pDevice = nullptr;
1045 }
1046
1047 QVariant DeviceParamModel::data (
1048 const QModelIndex &index, int role) const
1049 {
1050 if (!index.isValid())
1051 return QVariant();
1052
1053 if (role != Qt::DisplayRole)
1054 return QVariant();
1055
1056 DeviceParameterRow item;
1057 item.name = m_pParams->keys()[index.row()];
1058 item.param = (*m_pParams)[item.name];
1059 item.alive = (m_pDevice && m_pDevice->deviceID() >= 0);
1060
1061 return QVariant::fromValue(item);
1062 }
1063
1064
1065 bool DeviceParamModel::setData (
1066 const QModelIndex& index, const QVariant& value, int /*role*/)
1067 {
1068 if (!index.isValid())
1069 return false;
1070
1071 QString key = m_pParams->keys()[index.row()];
1072 //m_pParams[key].value = value.toString();
1073 m_pDevice->setParam(key, value.toString());
1074 emit dataChanged(index, index);
1075 return true;
1076 }
1077
1078
1079 void DeviceParamModel::refresh ( Device* pDevice, bool bEditable )
1080 {
1081 m_pDevice = pDevice;
1082 AbstractDeviceParamModel::refresh(&pDevice->params(), bEditable);
1083 }
1084
1085
1086 void DeviceParamModel::clear (void)
1087 {
1088 AbstractDeviceParamModel::clear();
1089 m_pDevice = nullptr;
1090 }
1091
1092
1093 //-------------------------------------------------------------------------
1094 // QSampler::PortParamModel - data model for port parameters
1095 // (used for QTableView)
1096
1097 PortParamModel::PortParamModel ( QObject *pParent)
1098 : AbstractDeviceParamModel(pParent)
1099 {
1100 m_pPort = nullptr;
1101 }
1102
1103 QVariant PortParamModel::data ( const QModelIndex &index, int role ) const
1104 {
1105 if (!index.isValid())
1106 return QVariant();
1107
1108 if (role != Qt::DisplayRole)
1109 return QVariant();
1110
1111 DeviceParameterRow item;
1112 item.name = m_pParams->keys()[index.row()];
1113 item.param = (*m_pParams)[item.name];
1114 item.alive = (m_pPort && m_pPort->portID() >= 0);
1115
1116 return QVariant::fromValue(item);
1117 }
1118
1119
1120 bool PortParamModel::setData (
1121 const QModelIndex& index, const QVariant& value, int /*role*/)
1122 {
1123 if (!index.isValid())
1124 return false;
1125
1126 QString key = m_pParams->keys()[index.row()];
1127 //params[key].value = value.toString();
1128 m_pPort->setParam(key, value.toString());
1129 emit dataChanged(index, index);
1130 return true;
1131 }
1132
1133
1134 void PortParamModel::refresh ( DevicePort* pPort, bool bEditable )
1135 {
1136 m_pPort = pPort;
1137 AbstractDeviceParamModel::refresh(&pPort->params(), bEditable);
1138 }
1139
1140
1141 void PortParamModel::clear (void)
1142 {
1143 AbstractDeviceParamModel::clear();
1144 m_pPort = nullptr;
1145 }
1146
1147
1148 //-------------------------------------------------------------------------
1149 // QSampler::DeviceParamDelegate - table cell renderer for device/port parameters
1150 //
1151
1152 DeviceParamDelegate::DeviceParamDelegate ( QObject *pParent)
1153 : QItemDelegate(pParent)
1154 {
1155 }
1156
1157
1158 QWidget* DeviceParamDelegate::createEditor ( QWidget *pParent,
1159 const QStyleOptionViewItem& /* option */, const QModelIndex& index ) const
1160 {
1161 if (!index.isValid())
1162 return nullptr;
1163
1164 DeviceParameterRow r = index.model()->data(index,
1165 Qt::DisplayRole).value<DeviceParameterRow>();
1166
1167 const bool bEnabled = (r.alive) ? !r.param.fix : true;
1168 const bool bFix = r.param.fix;
1169
1170 QString val = (r.alive) ? r.param.value : r.param.defaultv;
1171
1172 switch (index.column()) {
1173 case 0:
1174 return new QLabel(r.name, pParent);
1175 case 1: {
1176 if (r.param.type == LSCP_TYPE_BOOL) {
1177 QCheckBox *pCheckBox = new QCheckBox(pParent);
1178 if (!val.isEmpty())
1179 pCheckBox->setChecked(val.toLower() == "true");
1180 pCheckBox->setEnabled(bEnabled);
1181 pCheckBox->setCheckable(!bFix);
1182 return pCheckBox;
1183 } else if (r.param.possibilities.count() > 0) {
1184 QStringList opts = r.param.possibilities;
1185 if (r.param.multiplicity)
1186 opts.prepend(tr("(none)"));
1187 QComboBox *pComboBox = new QComboBox(pParent);
1188 pComboBox->addItems(opts);
1189 if (r.param.value.isEmpty())
1190 pComboBox->setCurrentIndex(0);
1191 else
1192 pComboBox->setCurrentIndex(pComboBox->findText(val));
1193 pComboBox->setEnabled(bEnabled);
1194 pComboBox->setEditable(!bFix);
1195 return pComboBox;
1196 } else if (r.param.type == LSCP_TYPE_INT && bEnabled) {
1197 QSpinBox *pSpinBox = new QSpinBox(pParent);
1198 pSpinBox->setMinimum(
1199 (!r.param.range_min.isEmpty()) ?
1200 r.param.range_min.toInt() : 0 // or better a negative default min value ?
1201 );
1202 pSpinBox->setMaximum(
1203 (!r.param.range_max.isEmpty()) ?
1204 r.param.range_max.toInt() : (1 << 24) // or better a higher default max value ?
1205 );
1206 pSpinBox->setValue(val.toInt());
1207 pSpinBox->setReadOnly(bFix);
1208 return pSpinBox;
1209 } else if (bEnabled) {
1210 QLineEdit *pLineEdit = new QLineEdit(val, pParent);
1211 pLineEdit->setReadOnly(bFix);
1212 return pLineEdit;
1213 } else {
1214 QLabel *pLabel = new QLabel(val, pParent);
1215 return pLabel;
1216 }
1217 }
1218 case 2:
1219 return new QLabel(r.param.description, pParent);
1220 default:
1221 return nullptr;
1222 }
1223 }
1224
1225
1226 void DeviceParamDelegate::setEditorData (
1227 QWidget* /*pEditor*/, const QModelIndex& /*index*/) const
1228 {
1229 // Unused, since we set the editor data already in createEditor()
1230 }
1231
1232
1233 void DeviceParamDelegate::setModelData ( QWidget *pEditor,
1234 QAbstractItemModel *pModel, const QModelIndex& index ) const
1235 {
1236 if (index.column() == 1) {
1237 DeviceParameterRow r = index.model()->data(index,
1238 Qt::DisplayRole).value<DeviceParameterRow> ();
1239 if (pEditor->metaObject()->className() == QString("QCheckBox")) {
1240 QCheckBox *pCheckBox = static_cast<QCheckBox *> (pEditor);
1241 pModel->setData(index, QVariant(pCheckBox->checkState() == Qt::Checked));
1242 } else if (pEditor->metaObject()->className() == QString("QComboBox")) {
1243 QComboBox *pComboBox = static_cast<QComboBox *> (pEditor);
1244 pModel->setData(index, pComboBox->currentText());
1245 } else if (pEditor->metaObject()->className() == QString("QSpinBox")) {
1246 QSpinBox *pSpinBox = static_cast<QSpinBox *> (pEditor);
1247 pModel->setData(index, pSpinBox->value());
1248 } else if (pEditor->metaObject()->className() == QString("QLineEdit")) {
1249 QLineEdit *pLineEdit = static_cast<QLineEdit *> (pEditor);
1250 pModel->setData(index, pLineEdit->text());
1251 } else if (pEditor->metaObject()->className() == QString("QLabel")) {
1252 QLabel *pLabel = static_cast<QLabel *> (pEditor);
1253 pModel->setData(index, pLabel->text());
1254 }
1255 }
1256 }
1257
1258 void DeviceParamDelegate::updateEditorGeometry ( QWidget *pEditor,
1259 const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
1260 {
1261 if (pEditor)
1262 pEditor->setGeometry(option.rect);
1263 }
1264
1265 } // namespace QSampler
1266
1267 // end of qsamplerDevice.cpp

  ViewVC Help
Powered by ViewVC