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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1509 - (show annotations) (download)
Thu Nov 22 11:10:44 2007 UTC (16 years, 4 months ago) by capela
File size: 12786 byte(s)
* Audio routing table is initially hidden in the dialog, when
  creating a new sampler channel.

* README requirements and configuration notes update.

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

  ViewVC Help
Powered by ViewVC