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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1515 - (show annotations) (download)
Fri Nov 23 18:15:33 2007 UTC (16 years, 4 months ago) by capela
File size: 13173 byte(s)
* Fixed sure crash when removing channel strips.
* Force auto-arrange when adding channel strips,
  among other incremental fixes.

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

  ViewVC Help
Powered by ViewVC