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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1667 - (hide annotations) (download)
Mon Feb 4 23:24:19 2008 UTC (16 years, 2 months ago) by schoenebeck
File size: 14198 byte(s)
* added FX Sends dialog to channel strips
  (still under construction, so far one can only create, destroy and rename
  FX sends, the rest is still to do)
* bumped version to 0.2.1.3

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

  ViewVC Help
Powered by ViewVC