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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2570 - (show annotations) (download)
Wed May 21 16:56:18 2014 UTC (9 years, 10 months ago) by capela
File size: 17547 byte(s)
- Channel-strip instrument name button text color fix.
1 // qsamplerChannelStrip.cpp
2 //
3 /****************************************************************************
4 Copyright (C) 2004-2014, rncbc aka Rui Nuno Capela. All rights reserved.
5 Copyright (C) 2007, 2008, 2014 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 "qsamplerChannelStrip.h"
25
26 #include "qsamplerMainForm.h"
27
28 #include "qsamplerChannelFxForm.h"
29
30 #include <QMessageBox>
31 #include <QDragEnterEvent>
32 #include <QFileInfo>
33 #include <QTimer>
34 #include <QUrl>
35 #include <QMenu>
36
37 #if QT_VERSION >= 0x050000
38 #include <QMimeData>
39 #endif
40
41 // Channel status/usage usage limit control.
42 #define QSAMPLER_ERROR_LIMIT 3
43
44 // Needed for lroundf()
45 #include <math.h>
46
47 #ifndef CONFIG_ROUND
48 static inline long lroundf ( float x )
49 {
50 if (x >= 0.0f)
51 return long(x + 0.5f);
52 else
53 return long(x - 0.5f);
54 }
55 #endif
56
57
58 namespace QSampler {
59
60 //-------------------------------------------------------------------------
61 // QSampler::ChannelStrip -- Channel strip form implementation.
62 //
63
64 // MIDI activity pixmap common resources.
65 int ChannelStrip::g_iMidiActivityRefCount = 0;
66 QPixmap *ChannelStrip::g_pMidiActivityLedOn = NULL;
67 QPixmap *ChannelStrip::g_pMidiActivityLedOff = NULL;
68
69 // Channel strip activation/selection.
70 ChannelStrip *ChannelStrip::g_pSelectedStrip = NULL;
71
72 ChannelStrip::ChannelStrip ( QWidget* pParent, Qt::WindowFlags wflags )
73 : QWidget(pParent, wflags)
74 {
75 m_ui.setupUi(this);
76
77 // Initialize locals.
78 m_pChannel = NULL;
79 m_iDirtyChange = 0;
80 m_iErrorCount = 0;
81 m_instrumentListPopupMenu = NULL;
82
83 if (++g_iMidiActivityRefCount == 1) {
84 g_pMidiActivityLedOn = new QPixmap(":/images/ledon1.png");
85 g_pMidiActivityLedOff = new QPixmap(":/images/ledoff1.png");
86 }
87
88 m_ui.MidiActivityLabel->setPixmap(*g_pMidiActivityLedOff);
89
90 #ifndef CONFIG_EVENT_CHANNEL_MIDI
91 m_ui.MidiActivityLabel->setToolTip("MIDI activity (disabled)");
92 #endif
93
94 m_pMidiActivityTimer = new QTimer(this);
95 m_pMidiActivityTimer->setSingleShot(true);
96
97 QObject::connect(m_pMidiActivityTimer,
98 SIGNAL(timeout()),
99 SLOT(midiActivityLedOff())
100 );
101
102 // Try to restore normal window positioning.
103 adjustSize();
104
105 QObject::connect(m_ui.ChannelSetupPushButton,
106 SIGNAL(clicked()),
107 SLOT(channelSetup()));
108 QObject::connect(m_ui.ChannelMutePushButton,
109 SIGNAL(toggled(bool)),
110 SLOT(channelMute(bool)));
111 QObject::connect(m_ui.ChannelSoloPushButton,
112 SIGNAL(toggled(bool)),
113 SLOT(channelSolo(bool)));
114 QObject::connect(m_ui.VolumeSlider,
115 SIGNAL(valueChanged(int)),
116 SLOT(volumeChanged(int)));
117 QObject::connect(m_ui.VolumeSpinBox,
118 SIGNAL(valueChanged(int)),
119 SLOT(volumeChanged(int)));
120 QObject::connect(m_ui.ChannelEditPushButton,
121 SIGNAL(clicked()),
122 SLOT(channelEdit()));
123 QObject::connect(m_ui.FxPushButton,
124 SIGNAL(clicked()),
125 SLOT(channelFxEdit()));
126
127 setSelected(false);
128 }
129
130
131 ChannelStrip::~ChannelStrip (void)
132 {
133 setSelected(false);
134
135 // Destroy existing channel descriptor.
136 if (m_pChannel)
137 delete m_pChannel;
138 m_pChannel = NULL;
139
140 if (--g_iMidiActivityRefCount == 0) {
141 if (g_pMidiActivityLedOn)
142 delete g_pMidiActivityLedOn;
143 g_pMidiActivityLedOn = NULL;
144 if (g_pMidiActivityLedOff)
145 delete g_pMidiActivityLedOff;
146 g_pMidiActivityLedOff = NULL;
147 }
148 }
149
150
151 // Window drag-n-drop event handlers.
152 void ChannelStrip::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )
153 {
154 if (m_pChannel == NULL)
155 return;
156
157 bool bAccept = false;
158
159 if (pDragEnterEvent->source() == NULL) {
160 const QMimeData *pMimeData = pDragEnterEvent->mimeData();
161 if (pMimeData && pMimeData->hasUrls()) {
162 QListIterator<QUrl> iter(pMimeData->urls());
163 while (iter.hasNext()) {
164 const QString& sFilename = iter.next().toLocalFile();
165 if (!sFilename.isEmpty()) {
166 // bAccept = Channel::isDlsInstrumentFile(sFilename);
167 bAccept = QFileInfo(sFilename).exists();
168 break;
169 }
170 }
171 }
172 }
173
174 if (bAccept)
175 pDragEnterEvent->accept();
176 else
177 pDragEnterEvent->ignore();
178 }
179
180
181 void ChannelStrip::dropEvent ( QDropEvent* pDropEvent )
182 {
183 if (m_pChannel == NULL)
184 return;
185
186 if (pDropEvent->source())
187 return;
188
189 const QMimeData *pMimeData = pDropEvent->mimeData();
190 if (pMimeData && pMimeData->hasUrls()) {
191 QStringList files;
192 QListIterator<QUrl> iter(pMimeData->urls());
193 while (iter.hasNext()) {
194 const QString& sFilename = iter.next().toLocalFile();
195 if (!sFilename.isEmpty()) {
196 // Go and set the dropped instrument filename...
197 m_pChannel->setInstrument(sFilename, 0);
198 // Open up the channel dialog.
199 channelSetup();
200 break;
201 }
202 }
203 }
204 }
205
206
207 // Channel strip setup formal initializer.
208 void ChannelStrip::setup ( Channel *pChannel )
209 {
210 // Destroy any previous channel descriptor;
211 // (remember that once setup we own it!)
212 if (m_pChannel)
213 delete m_pChannel;
214
215 // Set the new one...
216 m_pChannel = pChannel;
217
218 // Stabilize this around.
219 updateChannelInfo();
220
221 // We'll accept drops from now on...
222 if (m_pChannel)
223 setAcceptDrops(true);
224 }
225
226
227 // Channel secriptor accessor.
228 Channel *ChannelStrip::channel (void) const
229 {
230 return m_pChannel;
231 }
232
233
234 // Messages view font accessors.
235 QFont ChannelStrip::displayFont (void) const
236 {
237 return m_ui.EngineNameTextLabel->font();
238 }
239
240 void ChannelStrip::setDisplayFont ( const QFont & font )
241 {
242 m_ui.EngineNameTextLabel->setFont(font);
243 m_ui.MidiPortChannelTextLabel->setFont(font);
244 m_ui.InstrumentNamePushButton->setFont(font);
245 m_ui.InstrumentStatusTextLabel->setFont(font);
246 }
247
248
249 // Channel display background effect.
250 void ChannelStrip::setDisplayEffect ( bool bDisplayEffect )
251 {
252 QPalette pal;
253 pal.setColor(QPalette::Foreground, Qt::yellow);
254 pal.setColor(QPalette::ButtonText, Qt::yellow);
255 m_ui.EngineNameTextLabel->setPalette(pal);
256 m_ui.MidiPortChannelTextLabel->setPalette(pal);
257 pal.setColor(QPalette::Foreground, Qt::green);
258 pal.setColor(QPalette::ButtonText, Qt::green);
259 if (bDisplayEffect) {
260 QPixmap pm(":/images/displaybg1.png");
261 pal.setBrush(QPalette::Background, QBrush(pm));
262 } else {
263 pal.setColor(QPalette::Background, Qt::black);
264 }
265 m_ui.ChannelInfoFrame->setPalette(pal);
266 m_ui.InstrumentNamePushButton->setPalette(pal);
267 m_ui.StreamVoiceCountTextLabel->setPalette(pal);
268 }
269
270
271 // Maximum volume slider accessors.
272 void ChannelStrip::setMaxVolume ( int iMaxVolume )
273 {
274 m_iDirtyChange++;
275 m_ui.VolumeSlider->setRange(0, iMaxVolume);
276 m_ui.VolumeSpinBox->setRange(0, iMaxVolume);
277 m_iDirtyChange--;
278 }
279
280
281 // Channel setup dialog slot.
282 bool ChannelStrip::channelSetup (void)
283 {
284 if (m_pChannel == NULL)
285 return false;
286
287 // Invoke the channel setup dialog.
288 bool bResult = m_pChannel->channelSetup(this);
289 // Notify that this channel has changed.
290 if (bResult)
291 emit channelChanged(this);
292
293 return bResult;
294 }
295
296
297 // Channel mute slot.
298 bool ChannelStrip::channelMute ( bool bMute )
299 {
300 if (m_pChannel == NULL)
301 return false;
302
303 // Invoke the channel mute method.
304 bool bResult = m_pChannel->setChannelMute(bMute);
305 // Notify that this channel has changed.
306 if (bResult)
307 emit channelChanged(this);
308
309 return bResult;
310 }
311
312
313 // Channel solo slot.
314 bool ChannelStrip::channelSolo ( bool bSolo )
315 {
316 if (m_pChannel == NULL)
317 return false;
318
319 // Invoke the channel solo method.
320 bool bResult = m_pChannel->setChannelSolo(bSolo);
321 // Notify that this channel has changed.
322 if (bResult)
323 emit channelChanged(this);
324
325 return bResult;
326 }
327
328
329 // Channel edit slot.
330 void ChannelStrip::channelEdit (void)
331 {
332 if (m_pChannel == NULL)
333 return;
334
335 m_pChannel->editChannel();
336 }
337
338 bool ChannelStrip::channelFxEdit (void)
339 {
340 MainForm *pMainForm = MainForm::getInstance();
341 if (!pMainForm || !channel())
342 return false;
343
344 pMainForm->appendMessages(QObject::tr("channel fx sends..."));
345
346 bool bResult = false;
347
348 #if CONFIG_FXSEND
349 ChannelFxForm *pChannelFxForm =
350 new ChannelFxForm(channel(), parentWidget());
351 if (pChannelFxForm) {
352 //pChannelForm->setup(this);
353 bResult = pChannelFxForm->exec();
354 delete pChannelFxForm;
355 }
356 #else // CONFIG_FXSEND
357 QMessageBox::critical(this,
358 QSAMPLER_TITLE ": " + tr("Unavailable"),
359 tr("Sorry, QSampler was built without FX send support!\n\n"
360 "(Make sure you have a recent liblscp when recompiling QSampler)"));
361 #endif // CONFIG_FXSEND
362
363 return bResult;
364 }
365
366 // Channel reset slot.
367 bool ChannelStrip::channelReset (void)
368 {
369 if (m_pChannel == NULL)
370 return false;
371
372 // Invoke the channel reset method.
373 bool bResult = m_pChannel->channelReset();
374 // Notify that this channel has changed.
375 if (bResult)
376 emit channelChanged(this);
377
378 return bResult;
379 }
380
381
382 // Update the channel instrument name.
383 bool ChannelStrip::updateInstrumentName ( bool bForce )
384 {
385 if (m_pChannel == NULL)
386 return false;
387
388 // Do we refresh the actual name?
389 if (bForce)
390 m_pChannel->updateInstrumentName();
391
392 // Instrument name...
393 if (m_pChannel->instrumentName().isEmpty()) {
394 if (m_pChannel->instrumentStatus() >= 0) {
395 m_ui.InstrumentNamePushButton->setText(
396 ' ' + Channel::loadingInstrument());
397 } else {
398 m_ui.InstrumentNamePushButton->setText(
399 ' ' + Channel::noInstrumentName());
400 }
401 } else {
402 m_ui.InstrumentNamePushButton->setText(
403 ' ' + m_pChannel->instrumentName());
404 }
405
406 bool bShowInstrumentPopup = false;
407
408 // Instrument list popup (for fast switching among sounds of the same file)
409 if (!m_pChannel->instrumentFile().isEmpty()) {
410 const QStringList instruments
411 = Channel::getInstrumentList(m_pChannel->instrumentFile(), true);
412 if (!instruments.isEmpty()) {
413 bShowInstrumentPopup = true;
414 if (!m_instrumentListPopupMenu) {
415 m_instrumentListPopupMenu
416 = new QMenu(m_ui.InstrumentNamePushButton);
417 m_instrumentListPopupMenu->setTitle(tr("Instruments"));
418 // for cosmetical reasons, should have at least
419 // the width of the instrument name label...
420 m_instrumentListPopupMenu->setMinimumWidth(120);
421 m_ui.InstrumentNamePushButton->setMenu(m_instrumentListPopupMenu);
422 QObject::connect(m_instrumentListPopupMenu,
423 SIGNAL(triggered(QAction*)),
424 SLOT(instrumentListPopupItemClicked(QAction *)));
425 } else {
426 m_instrumentListPopupMenu->clear();
427 }
428 QAction *action;
429 for (int i = 0; i < instruments.size(); ++i) {
430 action = m_instrumentListPopupMenu->addAction(instruments.at(i));
431 action->setData(i);
432 action->setCheckable(true);
433 action->setChecked(i == m_pChannel->instrumentNr());
434 }
435 }
436 }
437
438 if (!bShowInstrumentPopup && m_instrumentListPopupMenu) {
439 delete m_instrumentListPopupMenu;
440 m_instrumentListPopupMenu = NULL;
441 }
442
443 return true;
444 }
445
446 void ChannelStrip::instrumentListPopupItemClicked ( QAction *action )
447 {
448 if (!action) return;
449
450 QVariant data = action->data();
451 if (data.isValid() && !m_pChannel->instrumentFile().isEmpty()) {
452 m_pChannel->loadInstrument(m_pChannel->instrumentFile(), data.toInt());
453 emit channelChanged(this);
454 }
455 }
456
457 // Do the dirty volume change.
458 bool ChannelStrip::updateChannelVolume (void)
459 {
460 if (m_pChannel == NULL)
461 return false;
462
463 // Convert...
464 int iVolume = ::lroundf(100.0f * m_pChannel->volume());
465 // And clip...
466 if (iVolume < 0)
467 iVolume = 0;
468
469 // Flag it here, to avoid infinite recursion.
470 m_iDirtyChange++;
471 m_ui.VolumeSlider->setValue(iVolume);
472 m_ui.VolumeSpinBox->setValue(iVolume);
473 m_iDirtyChange--;
474
475 return true;
476 }
477
478
479 // Update whole channel info state.
480 bool ChannelStrip::updateChannelInfo (void)
481 {
482 if (m_pChannel == NULL)
483 return false;
484
485 // Check for error limit/recycle...
486 if (m_iErrorCount > QSAMPLER_ERROR_LIMIT)
487 return true;
488
489 // Update strip caption.
490 QString sText = m_pChannel->channelName();
491 setWindowTitle(sText);
492 m_ui.ChannelSetupPushButton->setText('&' + sText);
493
494 // Check if we're up and connected.
495 MainForm* pMainForm = MainForm::getInstance();
496 if (pMainForm->client() == NULL)
497 return false;
498
499 // Read actual channel information.
500 m_pChannel->updateChannelInfo();
501
502 // Engine name...
503 if (m_pChannel->engineName().isEmpty()) {
504 m_ui.EngineNameTextLabel->setText(
505 ' ' + Channel::noEngineName());
506 } else {
507 m_ui.EngineNameTextLabel->setText(
508 ' ' + m_pChannel->engineName());
509 }
510
511 // Instrument name...
512 updateInstrumentName(false);
513
514 // MIDI Port/Channel...
515 QString sMidiPortChannel = QString::number(m_pChannel->midiPort()) + " / ";
516 if (m_pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
517 sMidiPortChannel += tr("All");
518 else
519 sMidiPortChannel += QString::number(m_pChannel->midiChannel() + 1);
520 m_ui.MidiPortChannelTextLabel->setText(sMidiPortChannel);
521
522 // Common palette...
523 QPalette pal;
524 const QColor& rgbFore = pal.color(QPalette::Foreground);
525
526 // Instrument status...
527 const int iInstrumentStatus = m_pChannel->instrumentStatus();
528 if (iInstrumentStatus < 0) {
529 pal.setColor(QPalette::Foreground, Qt::red);
530 m_ui.InstrumentStatusTextLabel->setPalette(pal);
531 m_ui.InstrumentStatusTextLabel->setText(
532 tr("ERR%1").arg(iInstrumentStatus));
533 m_iErrorCount++;
534 return false;
535 }
536
537 // All seems normal...
538 pal.setColor(QPalette::Foreground,
539 iInstrumentStatus < 100 ? Qt::yellow : Qt::green);
540 m_ui.InstrumentStatusTextLabel->setPalette(pal);
541 m_ui.InstrumentStatusTextLabel->setText(
542 QString::number(iInstrumentStatus) + '%');
543 m_iErrorCount = 0;
544
545 #ifdef CONFIG_MUTE_SOLO
546 // Mute/Solo button state coloring...
547 bool bMute = m_pChannel->channelMute();
548 const QColor& rgbButton = pal.color(QPalette::Button);
549 const QColor& rgbButtonText = pal.color(QPalette::ButtonText);
550 pal.setColor(QPalette::Foreground, rgbFore);
551 pal.setColor(QPalette::Button, bMute ? Qt::yellow : rgbButton);
552 pal.setColor(QPalette::ButtonText, bMute ? Qt::darkYellow : rgbButtonText);
553 m_ui.ChannelMutePushButton->setPalette(pal);
554 m_ui.ChannelMutePushButton->setDown(bMute);
555 bool bSolo = m_pChannel->channelSolo();
556 pal.setColor(QPalette::Button, bSolo ? Qt::cyan : rgbButton);
557 pal.setColor(QPalette::ButtonText, bSolo ? Qt::darkCyan : rgbButtonText);
558 m_ui.ChannelSoloPushButton->setPalette(pal);
559 m_ui.ChannelSoloPushButton->setDown(bSolo);
560 #else
561 m_ui.ChannelMutePushButton->setEnabled(false);
562 m_ui.ChannelSoloPushButton->setEnabled(false);
563 #endif
564
565 // And update the both GUI volume elements;
566 // return success if, and only if, intrument is fully loaded...
567 return updateChannelVolume() && (iInstrumentStatus == 100);
568 }
569
570
571 // Update whole channel usage state.
572 bool ChannelStrip::updateChannelUsage (void)
573 {
574 if (m_pChannel == NULL)
575 return false;
576
577 MainForm *pMainForm = MainForm::getInstance();
578 if (pMainForm->client() == NULL)
579 return false;
580
581 // This only makes sense on fully loaded channels...
582 if (m_pChannel->instrumentStatus() < 100)
583 return false;
584
585 // Get current channel voice count.
586 int iVoiceCount = ::lscp_get_channel_voice_count(
587 pMainForm->client(), m_pChannel->channelID());
588 // Get current stream count.
589 int iStreamCount = ::lscp_get_channel_stream_count(
590 pMainForm->client(), m_pChannel->channelID());
591 // Get current channel buffer fill usage.
592 // As benno has suggested this is the percentage usage
593 // of the least filled buffer stream...
594 int iStreamUsage = ::lscp_get_channel_stream_usage(
595 pMainForm->client(), m_pChannel->channelID());;
596
597 // Update the GUI elements...
598 m_ui.StreamUsageProgressBar->setValue(iStreamUsage);
599 m_ui.StreamVoiceCountTextLabel->setText(
600 QString("%1 / %2").arg(iStreamCount).arg(iVoiceCount));
601
602 // We're clean.
603 return true;
604 }
605
606
607 // Volume change slot.
608 void ChannelStrip::volumeChanged ( int iVolume )
609 {
610 if (m_pChannel == NULL)
611 return;
612
613 // Avoid recursion.
614 if (m_iDirtyChange > 0)
615 return;
616
617 // Convert and clip.
618 float fVolume = (float) iVolume / 100.0f;
619 if (fVolume < 0.001f)
620 fVolume = 0.0f;
621
622 // Update the GUI elements.
623 if (m_pChannel->setVolume(fVolume)) {
624 updateChannelVolume();
625 emit channelChanged(this);
626 }
627 }
628
629
630 // Context menu event handler.
631 void ChannelStrip::contextMenuEvent( QContextMenuEvent *pEvent )
632 {
633 if (m_pChannel == NULL)
634 return;
635
636 // We'll just show up the main form's edit menu (thru qsamplerChannel).
637 m_pChannel->contextMenuEvent(pEvent);
638 }
639
640
641 void ChannelStrip::midiActivityLedOn (void)
642 {
643 m_ui.MidiActivityLabel->setPixmap(*g_pMidiActivityLedOn);
644 m_pMidiActivityTimer->start(100);
645 }
646
647
648 void ChannelStrip::midiActivityLedOff (void)
649 {
650 m_ui.MidiActivityLabel->setPixmap(*g_pMidiActivityLedOff);
651 }
652
653
654 // Error count hackish accessors.
655 void ChannelStrip::resetErrorCount (void)
656 {
657 m_iErrorCount = 0;
658 }
659
660
661 // Channel strip activation/selection.
662 void ChannelStrip::setSelected ( bool bSelected )
663 {
664 if (bSelected) {
665 if (g_pSelectedStrip == this)
666 return;
667 if (g_pSelectedStrip)
668 g_pSelectedStrip->setSelected(false);
669 g_pSelectedStrip = this;
670 } else {
671 if (g_pSelectedStrip == this)
672 g_pSelectedStrip = NULL;
673 }
674
675 QPalette pal;
676 if (bSelected) {
677 const QColor& color = pal.midlight().color();
678 pal.setColor(QPalette::Background, color.dark(150));
679 pal.setColor(QPalette::Foreground, color.light(150));
680 }
681 QWidget::setPalette(pal);
682 }
683
684
685 bool ChannelStrip::isSelected (void) const
686 {
687 return (this == g_pSelectedStrip);
688 }
689
690
691 } // namespace QSampler
692
693
694 // end of qsamplerChannelStrip.cpp

  ViewVC Help
Powered by ViewVC