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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1691 - (show annotations) (download)
Thu Feb 14 22:31:26 2008 UTC (16 years, 1 month ago) by schoenebeck
File size: 14903 byte(s)
* implemented MIDI indicator LED on channel strips

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

  ViewVC Help
Powered by ViewVC