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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1668 - (show annotations) (download)
Tue Feb 5 15:42:33 2008 UTC (16 years, 1 month ago) by schoenebeck
File size: 14185 byte(s)
* finished FX Sends dialog implementation
* bumped version to 0.2.1.4

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 // Channel status/usage usage limit control.
35 #define QSAMPLER_ERROR_LIMIT 3
36
37 // 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
51 namespace QSampler {
52
53 //-------------------------------------------------------------------------
54 // QSampler::ChannelStrip -- Channel strip form implementation.
55 //
56
57 // Channel strip activation/selection.
58 ChannelStrip *ChannelStrip::g_pSelectedStrip = NULL;
59
60 ChannelStrip::ChannelStrip ( QWidget* pParent, Qt::WindowFlags wflags )
61 : QWidget(pParent, wflags)
62 {
63 m_ui.setupUi(this);
64
65 // Initialize locals.
66 m_pChannel = NULL;
67 m_iDirtyChange = 0;
68 m_iErrorCount = 0;
69
70 // Try to restore normal window positioning.
71 adjustSize();
72
73 QObject::connect(m_ui.ChannelSetupPushButton,
74 SIGNAL(clicked()),
75 SLOT(channelSetup()));
76 QObject::connect(m_ui.ChannelMutePushButton,
77 SIGNAL(toggled(bool)),
78 SLOT(channelMute(bool)));
79 QObject::connect(m_ui.ChannelSoloPushButton,
80 SIGNAL(toggled(bool)),
81 SLOT(channelSolo(bool)));
82 QObject::connect(m_ui.VolumeSlider,
83 SIGNAL(valueChanged(int)),
84 SLOT(volumeChanged(int)));
85 QObject::connect(m_ui.VolumeSpinBox,
86 SIGNAL(valueChanged(int)),
87 SLOT(volumeChanged(int)));
88 QObject::connect(m_ui.ChannelEditPushButton,
89 SIGNAL(clicked()),
90 SLOT(channelEdit()));
91 QObject::connect(m_ui.FxPushButton,
92 SIGNAL(clicked()),
93 SLOT(channelFxEdit()));
94
95 setSelected(false);
96 }
97
98
99 ChannelStrip::~ChannelStrip (void)
100 {
101 setSelected(false);
102
103 // Destroy existing channel descriptor.
104 if (m_pChannel)
105 delete m_pChannel;
106 m_pChannel = NULL;
107 }
108
109
110 // Window drag-n-drop event handlers.
111 void ChannelStrip::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )
112 {
113 if (m_pChannel == NULL)
114 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 bAccept = Channel::isInstrumentFile(sFilename);
126 break;
127 }
128 }
129 }
130 }
131
132 if (bAccept)
133 pDragEnterEvent->accept();
134 else
135 pDragEnterEvent->ignore();
136 }
137
138
139 void ChannelStrip::dropEvent ( QDropEvent* pDropEvent )
140 {
141 if (m_pChannel == NULL)
142 return;
143
144 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 }
162 }
163
164
165 // Channel strip setup formal initializer.
166 void ChannelStrip::setup ( Channel *pChannel )
167 {
168 // Destroy any previous channel descriptor;
169 // (remember that once setup we own it!)
170 if (m_pChannel)
171 delete m_pChannel;
172
173 // Set the new one...
174 m_pChannel = pChannel;
175
176 // Stabilize this around.
177 updateChannelInfo();
178
179 // We'll accept drops from now on...
180 if (m_pChannel)
181 setAcceptDrops(true);
182 }
183
184
185 // Channel secriptor accessor.
186 Channel *ChannelStrip::channel (void) const
187 {
188 return m_pChannel;
189 }
190
191
192 // Messages view font accessors.
193 QFont ChannelStrip::displayFont (void) const
194 {
195 return m_ui.EngineNameTextLabel->font();
196 }
197
198 void ChannelStrip::setDisplayFont ( const QFont & font )
199 {
200 m_ui.EngineNameTextLabel->setFont(font);
201 m_ui.MidiPortChannelTextLabel->setFont(font);
202 m_ui.InstrumentNameTextLabel->setFont(font);
203 m_ui.InstrumentStatusTextLabel->setFont(font);
204 }
205
206
207 // Channel display background effect.
208 void ChannelStrip::setDisplayEffect ( bool bDisplayEffect )
209 {
210 QPalette pal;
211 pal.setColor(QPalette::Foreground, Qt::yellow);
212 m_ui.EngineNameTextLabel->setPalette(pal);
213 m_ui.MidiPortChannelTextLabel->setPalette(pal);
214 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 m_ui.ChannelInfoFrame->setPalette(pal);
222 m_ui.InstrumentNameTextLabel->setPalette(pal);
223 m_ui.StreamVoiceCountTextLabel->setPalette(pal);
224 }
225
226
227 // Maximum volume slider accessors.
228 void ChannelStrip::setMaxVolume ( int iMaxVolume )
229 {
230 m_iDirtyChange++;
231 m_ui.VolumeSlider->setRange(0, iMaxVolume);
232 m_ui.VolumeSpinBox->setRange(0, iMaxVolume);
233 m_iDirtyChange--;
234 }
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 bool ChannelStrip::channelFxEdit (void)
295 {
296 MainForm *pMainForm = MainForm::getInstance();
297 if (!pMainForm || !channel())
298 return false;
299
300 pMainForm->appendMessages(QObject::tr("channel fx sends..."));
301
302 bool bResult = false;
303
304 #if CONFIG_FXSEND
305 ChannelFxForm *pChannelFxForm =
306 new ChannelFxForm(channel(), 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 // 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 if (m_pChannel->instrumentStatus() >= 0) {
351 m_ui.InstrumentNameTextLabel->setText(
352 ' ' + Channel::loadingInstrument());
353 } else {
354 m_ui.InstrumentNameTextLabel->setText(
355 ' ' + Channel::noInstrumentName());
356 }
357 } else {
358 m_ui.InstrumentNameTextLabel->setText(
359 ' ' + m_pChannel->instrumentName());
360 }
361
362 return true;
363 }
364
365
366 // Do the dirty volume change.
367 bool ChannelStrip::updateChannelVolume (void)
368 {
369 if (m_pChannel == NULL)
370 return false;
371
372 // Convert...
373 int iVolume = ::lroundf(100.0f * m_pChannel->volume());
374 // And clip...
375 if (iVolume < 0)
376 iVolume = 0;
377
378 // 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
384 return true;
385 }
386
387
388 // Update whole channel info state.
389 bool ChannelStrip::updateChannelInfo (void)
390 {
391 if (m_pChannel == NULL)
392 return false;
393
394 // Check for error limit/recycle...
395 if (m_iErrorCount > QSAMPLER_ERROR_LIMIT)
396 return true;
397
398 // Update strip caption.
399 QString sText = m_pChannel->channelName();
400 setWindowTitle(sText);
401 m_ui.ChannelSetupPushButton->setText('&' + sText);
402
403 // Check if we're up and connected.
404 MainForm* pMainForm = MainForm::getInstance();
405 if (pMainForm->client() == NULL)
406 return false;
407
408 // Read actual channel information.
409 m_pChannel->updateChannelInfo();
410
411 // Engine name...
412 if (m_pChannel->engineName().isEmpty()) {
413 m_ui.EngineNameTextLabel->setText(
414 ' ' + Channel::noEngineName());
415 } else {
416 m_ui.EngineNameTextLabel->setText(
417 ' ' + m_pChannel->engineName());
418 }
419
420 // Instrument name...
421 updateInstrumentName(false);
422
423 // MIDI Port/Channel...
424 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 m_ui.MidiPortChannelTextLabel->setText(sMidiPortChannel);
430
431 // Common palette...
432 QPalette pal;
433 const QColor& rgbFore = pal.color(QPalette::Foreground);
434
435 // Instrument status...
436 int iInstrumentStatus = m_pChannel->instrumentStatus();
437 if (iInstrumentStatus < 0) {
438 pal.setColor(QPalette::Foreground, Qt::red);
439 m_ui.InstrumentStatusTextLabel->setPalette(pal);
440 m_ui.InstrumentStatusTextLabel->setText(
441 tr("ERR%1").arg(iInstrumentStatus));
442 m_iErrorCount++;
443 return false;
444 }
445 // All seems normal...
446 pal.setColor(QPalette::Foreground,
447 iInstrumentStatus < 100 ? Qt::yellow : Qt::green);
448 m_ui.InstrumentStatusTextLabel->setPalette(pal);
449 m_ui.InstrumentStatusTextLabel->setText(
450 QString::number(iInstrumentStatus) + '%');
451 m_iErrorCount = 0;
452
453 #ifdef CONFIG_MUTE_SOLO
454 // Mute/Solo button state coloring...
455 bool bMute = m_pChannel->channelMute();
456 const QColor& rgbButton = pal.color(QPalette::Button);
457 pal.setColor(QPalette::Foreground, rgbFore);
458 pal.setColor(QPalette::Button, bMute ? Qt::yellow : rgbButton);
459 m_ui.ChannelMutePushButton->setPalette(pal);
460 m_ui.ChannelMutePushButton->setDown(bMute);
461 bool bSolo = m_pChannel->channelSolo();
462 pal.setColor(QPalette::Button, bSolo ? Qt::cyan : rgbButton);
463 m_ui.ChannelSoloPushButton->setPalette(pal);
464 m_ui.ChannelSoloPushButton->setDown(bSolo);
465 #else
466 m_ui.ChannelMutePushButton->setEnabled(false);
467 m_ui.ChannelSoloPushButton->setEnabled(false);
468 #endif
469
470 // And update the both GUI volume elements;
471 // return success if, and only if, intrument is fully loaded...
472 return updateChannelVolume() && (iInstrumentStatus == 100);
473 }
474
475
476 // Update whole channel usage state.
477 bool ChannelStrip::updateChannelUsage (void)
478 {
479 if (m_pChannel == NULL)
480 return false;
481
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 return false;
489
490 // Get current channel voice count.
491 int iVoiceCount = ::lscp_get_channel_voice_count(
492 pMainForm->client(), m_pChannel->channelID());
493 // Get current stream count.
494 int iStreamCount = ::lscp_get_channel_stream_count(
495 pMainForm->client(), m_pChannel->channelID());
496 // Get current channel buffer fill usage.
497 // As benno has suggested this is the percentage usage
498 // of the least filled buffer stream...
499 int iStreamUsage = ::lscp_get_channel_stream_usage(
500 pMainForm->client(), m_pChannel->channelID());;
501
502 // Update the GUI elements...
503 m_ui.StreamUsageProgressBar->setValue(iStreamUsage);
504 m_ui.StreamVoiceCountTextLabel->setText(
505 QString("%1 / %2").arg(iStreamCount).arg(iVoiceCount));
506
507 // We're clean.
508 return true;
509 }
510
511
512 // Volume change slot.
513 void ChannelStrip::volumeChanged ( int iVolume )
514 {
515 if (m_pChannel == NULL)
516 return;
517
518 // Avoid recursion.
519 if (m_iDirtyChange > 0)
520 return;
521
522 // Convert and clip.
523 float fVolume = (float) iVolume / 100.0f;
524 if (fVolume < 0.001f)
525 fVolume = 0.0f;
526
527 // Update the GUI elements.
528 if (m_pChannel->setVolume(fVolume)) {
529 updateChannelVolume();
530 emit channelChanged(this);
531 }
532 }
533
534
535 // Context menu event handler.
536 void ChannelStrip::contextMenuEvent( QContextMenuEvent *pEvent )
537 {
538 if (m_pChannel == NULL)
539 return;
540
541 // We'll just show up the main form's edit menu (thru qsamplerChannel).
542 m_pChannel->contextMenuEvent(pEvent);
543 }
544
545
546 // Error count hackish accessors.
547 void ChannelStrip::resetErrorCount (void)
548 {
549 m_iErrorCount = 0;
550 }
551
552
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 } // namespace QSampler
584
585
586 // end of qsamplerChannelStrip.cpp

  ViewVC Help
Powered by ViewVC