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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC