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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 426 by capela, Mon Mar 7 11:09:32 2005 UTC revision 3555 by capela, Tue Aug 13 10:19:32 2019 UTC
# Line 1  Line 1 
1  // qsamplerDevice.cpp  // qsamplerDevice.cpp
2  //  //
3  /****************************************************************************  /****************************************************************************
4     Copyright (C) 2003-2005, rncbc aka Rui Nuno Capela. All rights reserved.     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     This program is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License     modify it under the terms of the GNU General Public License
# Line 13  Line 14 
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License along
18     along with this program; if not, write to the Free Software     with this program; if not, write to the Free Software Foundation, Inc.,
19     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20    
21  *****************************************************************************/  *****************************************************************************/
22    
23    #include "qsamplerAbout.h"
24  #include "qsamplerDevice.h"  #include "qsamplerDevice.h"
25    
26  #include "qsamplerMainForm.h"  #include "qsamplerMainForm.h"
27  #include "qsamplerDeviceForm.h"  #include "qsamplerDeviceForm.h"
28    
29  #include "config.h"  #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  // qsamplerDeviceParameterTable - Device parameter view table.  // QSampler::Device - MIDI/Audio Device structure.
101  //  //
102    
103  // Constructor.  // Constructor.
104  qsamplerDeviceParameterTable::qsamplerDeviceParameterTable ( QWidget *pParent, const char *pszName )  Device::Device ( DeviceType deviceType, int iDeviceID )
         : QTable(pParent, pszName)  
105  {  {
106          m_pClient = NULL;  //      m_ports.setAutoDelete(true);
107    
108            setDevice(deviceType, iDeviceID);
109  }  }
110    
111  // Default destructor.  // Default destructor.
112  qsamplerDeviceParameterTable::~qsamplerDeviceParameterTable (void)  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  // The client descriptor property accessors.  void DeviceParamDelegate::setModelData ( QWidget *pEditor,
1234  void qsamplerDeviceParameterTable::setClient ( lscp_client_t *pClient )          QAbstractItemModel *pModel, const QModelIndex& index ) const
1235  {  {
1236      m_pClient = pClient;          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  lscp_client_t *qsamplerDeviceParameterTable::client (void)  void DeviceParamDelegate::updateEditorGeometry ( QWidget *pEditor,
1259            const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
1260  {  {
1261      return m_pClient;          if (pEditor)
1262                    pEditor->setGeometry(option.rect);
1263  }  }
1264    
1265    } // namespace QSampler
1266    
1267  // end of qsamplerDevice.cpp  // end of qsamplerDevice.cpp

Legend:
Removed from v.426  
changed lines
  Added in v.3555

  ViewVC Help
Powered by ViewVC