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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2074 - (show annotations) (download)
Mon Mar 29 17:00:30 2010 UTC (14 years ago) by capela
File size: 15627 byte(s)
* General source tree layout and build configuration change.

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

  ViewVC Help
Powered by ViewVC