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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3413 - (show annotations) (download)
Fri Jan 26 16:55:50 2018 UTC (4 years ago) by schoenebeck
File size: 33980 byte(s)
* Fixed minor memory leak in device management dialog.

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

  ViewVC Help
Powered by ViewVC