1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 // $Id: astrip.cpp,v 1.23.2.17 2009/11/16 01:55:55 terminator356 Exp $
5 //
6 // (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
7 // (C) Copyright 2011-2016 Tim E. Real (terminator356 on sourceforge)
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; version 2 of
12 // the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=========================================================
24
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include <QLayout>
29 #include <QVBoxLayout>
30 #include <QApplication>
31 #include <QToolButton>
32 #include <QComboBox>
33 #include <QToolTip>
34 #include <QTimer>
35 #include <QCursor>
36 #include <QPainter>
37 #include <QString>
38 #include <QPoint>
39 #include <QEvent>
40 #include <QWidget>
41 #include <QVariant>
42 #include <QAction>
43 #include <QGridLayout>
44 #include <QPushButton>
45
46 #include "app.h"
47 #include "globals.h"
48 #include "audio.h"
49 #include "midi_consts.h"
50 #include "song.h"
51 #include "slider.h"
52 #include "compact_knob.h"
53 #include "combobox.h"
54 #include "astrip.h"
55 #include "synth.h"
56 #include "audio_fifo.h"
57 #include "amixer.h"
58 #include "icons.h"
59 #include "gconfig.h"
60 #include "menutitleitem.h"
61 #include "routepopup.h"
62 #include "ctrl.h"
63 #include "utils.h"
64 #include "muse_math.h"
65 #include "operations.h"
66
67 // Forwards from header:
68 #include <QHBoxLayout>
69 #include "track.h"
70 #include "doublelabel.h"
71 #include "rack.h"
72 #include "slider.h"
73 #include "compact_slider.h"
74 #include "pixmap_button.h"
75 #include "clipper_label.h"
76
77 // For debugging output: Uncomment the fprintf section.
78 #define DEBUG_AUDIO_STRIP(dev, format, args...) //fprintf(dev, format, ##args);
79
80
81 namespace MusEGui {
82
83 const double AudioStrip::volSliderStep = 0.5;
84 const double AudioStrip::volSliderMax = 10.0;
85 const int AudioStrip::volSliderPrec = 1;
86
87 const double AudioStrip::auxSliderStep = 1.0;
88 const double AudioStrip::auxSliderMax = 10.0;
89 const int AudioStrip::auxSliderPrec = 0;
90
91 const double AudioStrip::gainSliderStep = 0.1;
92 const double AudioStrip::gainSliderMin = 0.5;
93 const double AudioStrip::gainSliderMax = 20.0;
94 const int AudioStrip::gainSliderPrec = 1;
95
96 const int AudioStrip::xMarginHorSlider = 1;
97 const int AudioStrip::yMarginHorSlider = 1;
98 const int AudioStrip::upperRackSpacerHeight = 2;
99 const int AudioStrip::rackFrameWidth = 1;
100
101 //---------------------------------------------------------
102 // AudioComponentRack
103 //---------------------------------------------------------
104
AudioComponentRack(MusECore::AudioTrack * track,int id,bool manageAuxs,QWidget * parent,Qt::WindowFlags f)105 AudioComponentRack::AudioComponentRack(MusECore::AudioTrack* track, int id, bool manageAuxs, QWidget* parent, Qt::WindowFlags f)
106 : ComponentRack(id, parent, f), _track(track), _manageAuxs(manageAuxs)
107 {
108
109 }
110
newComponent(ComponentDescriptor * desc,const ComponentWidget & before)111 void AudioComponentRack::newComponent( ComponentDescriptor* desc, const ComponentWidget& before )
112 {
113 double min = 0.0;
114 double max = 0.0;
115 double val = 0.0;
116 int prec = 0.0;
117 double step = 0.0;
118 bool showval = MusEGlobal::config.showControlValues;
119
120 switch(desc->_componentType)
121 {
122 case aStripAuxComponent:
123 {
124 val = _track->auxSend(desc->_index);
125 //if(val == 0.0)
126 if(val < MusEGlobal::config.minSlider)
127 val = MusEGlobal::config.minSlider;
128 else
129 {
130 val = muse_val2dbr(val);
131 if(val < MusEGlobal::config.minSlider)
132 val = MusEGlobal::config.minSlider;
133 }
134 min = MusEGlobal::config.minSlider;
135 max = AudioStrip::auxSliderMax;
136 prec = AudioStrip::auxSliderPrec;
137 step = AudioStrip::auxSliderStep;
138
139 // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track!
140 // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels.
141 desc->_enabled = _track->auxRefCount() == 0;
142
143 if(!desc->_color.isValid())
144 desc->_color = MusEGlobal::config.auxSliderColor;
145
146 if(desc->_label.isEmpty())
147 {
148 desc->_label = ((MusECore::AudioAux*)(MusEGlobal::song->auxs()->at(desc->_index)))->name();
149 }
150 if(desc->_toolTipText.isEmpty())
151 desc->_toolTipText = tr("Aux send level (dB)");
152 }
153 break;
154
155 case controllerComponent:
156 {
157 MusECore::iCtrlList ic = _track->controller()->find(desc->_index);
158 if(ic == _track->controller()->end())
159 return;
160 MusECore::CtrlList* cl = ic->second;
161 val = _track->pluginCtrlVal(desc->_index);
162 cl->range(&min, &max);
163 prec = 2;
164 step = 0.01;
165
166 if(desc->_label.isEmpty())
167 {
168 switch(desc->_index)
169 {
170 case MusECore::AC_VOLUME:
171 desc->_label = tr("Vol");
172 break;
173
174 case MusECore::AC_PAN:
175 desc->_label = tr("Pan");
176 break;
177
178 case MusECore::AC_MUTE:
179 desc->_label = tr("Mute");
180 break;
181
182 default:
183 desc->_label = cl->name();
184 break;
185 }
186 }
187
188 if(desc->_toolTipText.isEmpty())
189 {
190 switch(desc->_index)
191 {
192 case MusECore::AC_VOLUME:
193 desc->_toolTipText = tr("Volume/gain");
194 break;
195
196 case MusECore::AC_PAN:
197 desc->_toolTipText = tr("Panorama/Balance");
198 break;
199
200 case MusECore::AC_MUTE:
201 desc->_toolTipText = tr("Mute");
202 break;
203
204 default:
205 desc->_toolTipText = cl->name();
206 break;
207 }
208 }
209
210 if(!desc->_color.isValid())
211 {
212 switch(desc->_index)
213 {
214 case MusECore::AC_PAN:
215 desc->_color = MusEGlobal::config.panSliderColor;
216 break;
217
218 default:
219 desc->_color = MusEGlobal::config.audioControllerSliderColor;
220 break;
221 }
222 }
223 }
224 break;
225
226 case propertyComponent:
227 {
228 switch(desc->_index)
229 {
230 case aStripGainProperty:
231 {
232 val = _track->gain();
233 min = AudioStrip::gainSliderMin;
234 max = AudioStrip::gainSliderMax;
235 prec = AudioStrip::gainSliderPrec;
236 step = AudioStrip::gainSliderStep;
237 if(desc->_label.isEmpty())
238 desc->_label = tr("Gain");
239 if(desc->_toolTipText.isEmpty())
240 desc->_toolTipText = tr("Calibration gain");
241 if(!desc->_color.isValid())
242 desc->_color = MusEGlobal::config.gainSliderColor;
243 }
244 break;
245
246 default:
247 if(!desc->_color.isValid())
248 desc->_color = MusEGlobal::config.audioPropertySliderColor;
249 break;
250 }
251 }
252 break;
253 }
254
255 switch(desc->_widgetType)
256 {
257 case CompactKnobComponentWidget:
258 {
259 CompactKnobComponentDescriptor* d = static_cast<CompactKnobComponentDescriptor*>(desc);
260 d->_min = min;
261 d->_max = max;
262 d->_precision = prec;
263 d->_step = step;
264 d->_initVal = val;
265 d->_showValue = showval;
266 if(!d->_color.isValid())
267 d->_color = MusEGlobal::config.sliderBackgroundColor;
268 // test kybos
269 // if(!d->_faceColor.isValid())
270 // d->_faceColor = MusEGlobal::config.sliderBackgroundColor;
271 // if(!d->_shinyColor.isValid())
272 // d->_shinyColor = MusEGlobal::config.sliderBackgroundColor;
273 // if(!d->_rimColor.isValid())
274 // d->_rimColor = MusEGlobal::config.sliderBackgroundColor;
275
276 // Adds a component. Creates a new component using the given desc values if the desc widget is not given.
277 // Connects known widget types' signals to slots.
278 newComponentWidget(d, before);
279
280 // Handle special slots for audio strip.
281 switch(desc->_componentType)
282 {
283 case aStripAuxComponent:
284 {
285 if(d->_compactKnob->specialValueText().isEmpty())
286 {
287 d->_compactKnob->setSpecialValueText(QString('-') + QString(QChar(0x221e))); // The infinity character
288 }
289
290 connect(d->_compactKnob, SIGNAL(valueStateChanged(double,bool,int,int)), SLOT(auxChanged(double,bool,int,int)));
291 connect(d->_compactKnob, SIGNAL(sliderMoved(double,int,bool)), SLOT(auxMoved(double,int,bool)));
292 connect(d->_compactKnob, SIGNAL(sliderPressed(double, int)), SLOT(auxPressed(double, int)));
293 connect(d->_compactKnob, SIGNAL(sliderReleased(double, int)), SLOT(auxReleased(double, int)));
294 connect(d->_compactKnob, SIGNAL(sliderRightClicked(QPoint,int)), SLOT(auxRightClicked(QPoint,int)));
295 }
296 break;
297 }
298 }
299 break;
300
301 case CompactSliderComponentWidget:
302 {
303 CompactSliderComponentDescriptor* d = static_cast<CompactSliderComponentDescriptor*>(desc);
304 d->_min = min;
305 d->_max = max;
306 d->_precision = prec;
307 d->_step = step;
308 d->_initVal = val;
309 d->_showValue = showval;
310
311 if(!d->_color.isValid()) // wrong color, but hopefully set before...
312 d->_color = MusEGlobal::config.sliderBackgroundColor;
313 if(!d->_barColor.isValid())
314 d->_barColor = MusEGlobal::config.sliderBarColor;
315 if(!d->_slotColor.isValid())
316 d->_slotColor = MusEGlobal::config.sliderBackgroundColor;
317
318 // if(!d->_color.isValid())
319 // d->_color = MusEGlobal::config.sliderBackgroundColor;
320 // // Set the bar color the same.
321 // if(!d->_barColor.isValid())
322 // //d->_barColor = d->_color;
323 // d->_barColor = MusEGlobal::config.sliderBarColor;
324
325 // Adds a component. Creates a new component using the given desc values if the desc widget is not given.
326 // Connects known widget types' signals to slots.
327 newComponentWidget(d, before);
328
329 // Handle special slots for audio strip.
330 switch(desc->_componentType)
331 {
332 case aStripAuxComponent:
333 {
334 if(d->_compactSlider->specialValueText().isEmpty())
335 {
336 d->_compactSlider->setSpecialValueText(QString('-') + QString(QChar(0x221e))); // The infinity character
337 }
338
339 connect(d->_compactSlider, SIGNAL(valueStateChanged(double,bool,int,int)), SLOT(auxChanged(double,bool,int,int)));
340 connect(d->_compactSlider, SIGNAL(sliderMoved(double,int,bool)), SLOT(auxMoved(double,int,bool)));
341 connect(d->_compactSlider, SIGNAL(sliderPressed(double, int)), SLOT(auxPressed(double, int)));
342 connect(d->_compactSlider, SIGNAL(sliderReleased(double, int)), SLOT(auxReleased(double, int)));
343 connect(d->_compactSlider, SIGNAL(sliderRightClicked(QPoint,int)), SLOT(auxRightClicked(QPoint,int)));
344 }
345 break;
346 }
347 }
348 break;
349 }
350 }
351
scanControllerComponents()352 void AudioComponentRack::scanControllerComponents()
353 {
354 std::vector<iComponentWidget> to_be_erased;
355 for(iComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
356 {
357 ComponentWidget& cw = *ic;
358 if(!cw._widget)
359 continue;
360
361 switch(cw._componentType)
362 {
363 case controllerComponent:
364 {
365 MusECore::iCtrlList ictrl = _track->controller()->find(cw._index);
366 if(ictrl == _track->controller()->end())
367 to_be_erased.push_back(ic);
368 }
369 break;
370 }
371 }
372 for(std::vector<iComponentWidget>::iterator i = to_be_erased.begin(); i != to_be_erased.end(); ++i)
373 {
374 iComponentWidget icw = *i;
375 ComponentWidget& cw = *icw;
376 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::scanControllerComponents: deleting controller component index:%d\n", cw._index);
377 if(cw._widget)
378 cw._widget->deleteLater();
379 _components.erase(icw);
380 }
381 }
382
scanAuxComponents()383 void AudioComponentRack::scanAuxComponents()
384 {
385 std::vector<iComponentWidget> to_be_erased;
386 for(iComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
387 {
388 ComponentWidget& cw = *ic;
389 if(!cw._widget)
390 continue;
391
392 switch(cw._componentType)
393 {
394 case aStripAuxComponent:
395 {
396 // TODO: This is just brute-force deletion and recreation of all the auxs.
397 // Make this more efficient by only removing what's necessary and updating/re-using the rest.
398 to_be_erased.push_back(ic);
399 }
400 break;
401 }
402 }
403 for(std::vector<iComponentWidget>::iterator i = to_be_erased.begin(); i != to_be_erased.end(); ++i)
404 {
405 iComponentWidget icw = *i;
406 ComponentWidget& cw = *icw;
407 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::scanAuxComponents: deleting aux component index:%d\n", cw._index);
408 if(cw._widget)
409 cw._widget->deleteLater();
410 _components.erase(icw);
411 }
412
413 // Add auxs, only if we want this rack to manage auxs.
414 if(_manageAuxs)
415 {
416 int auxsSize = MusEGlobal::song->auxs()->size();
417 if(_track->hasAuxSend())
418 {
419 for (int idx = 0; idx < auxsSize; ++idx)
420 {
421 // the thought was to acquire the correct Aux name for each Aux
422 // now they are only called Aux1, Aux2, which isn't too usable.
423 // QString title = ((MusECore::AudioAux*)(MusEGlobal::song->auxs()->at(idx)))->auxName();
424 // if (title.length() > 8) { // shorten name
425 // title = title.mid(0,8) + ".";
426 // }
427
428 // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track!
429 // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels.
430 // const bool enable = _track->auxRefCount() == 0;
431
432 if(MusEGlobal::config.preferKnobsVsSliders)
433 {
434 CompactKnobComponentDescriptor aux_desc
435 (
436 aStripAuxComponent,
437 "MixerStripAudioAux",
438 idx
439 );
440 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::scanAuxComponents: adding aux component index:%d\n", idx);
441 newComponent(&aux_desc);
442 }
443 else
444 {
445 CompactSliderComponentDescriptor aux_desc
446 (
447 aStripAuxComponent,
448 "MixerStripAudioAux",
449 idx
450 );
451 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::scanAuxComponents: adding aux component index:%d\n", idx);
452 newComponent(&aux_desc);
453 }
454 }
455 }
456 }
457 }
458
updateComponents()459 void AudioComponentRack::updateComponents()
460 {
461 for(iComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
462 {
463 ComponentWidget& cw = *ic;
464 if(!cw._widget)
465 continue;
466
467 switch(cw._componentType)
468 {
469 case controllerComponent:
470 {
471 // Inhibit the controller stream if control is currently pressed.
472 // Note _pressed operates differently than simply checking if the control is pressed!
473 if(cw._pressed)
474 continue;
475 const double val = _track->pluginCtrlVal(cw._index);
476 setComponentValue(cw, val); // Signals blocked. Redundant ignored.
477 }
478 break;
479
480 case propertyComponent:
481 {
482 switch(cw._index)
483 {
484 case aStripGainProperty:
485 {
486 const double val = _track->gain();
487 setComponentValue(cw, val); // Signals blocked. Redundant ignored.
488 }
489 break;
490 }
491 }
492 break;
493
494 case aStripAuxComponent:
495 {
496 double val = _track->auxSend(cw._index);
497 if(val == 0.0)
498 val = MusEGlobal::config.minSlider;
499 else
500 {
501 val = muse_val2dbr(val);
502 if(val < MusEGlobal::config.minSlider)
503 val = MusEGlobal::config.minSlider;
504 }
505 setComponentValue(cw, val); // Signals blocked. Redundant ignored.
506 }
507 break;
508 }
509 }
510 }
511
setAuxEnabled(bool enable)512 void AudioComponentRack::setAuxEnabled(bool enable)
513 {
514 for(iComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
515 {
516 ComponentWidget& cw = *ic;
517 switch(cw._componentType)
518 {
519 case aStripAuxComponent:
520 setComponentEnabled(cw, enable);
521 break;
522 }
523 }
524 }
525
526
controllerChanged(double val,bool off,int id,int scrollMode)527 void AudioComponentRack::controllerChanged(double val, bool off, int id, int scrollMode)
528 {
529 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::controllerChanged id:%d val:%.20f scrollMode:%d\n", id, val, scrollMode);
530 // Hack: Be sure to ignore in ScrDirect mode since we get both pressed AND changed signals.
531 // ScrDirect mode is one-time only on press with modifier.
532 if(scrollMode != SliderBase::ScrDirect)
533 _track->recordAutomation(id, val);
534 _track->setParam(id, val); // Schedules a timed control change.
535 //_track->setPluginCtrlVal(id, val); // TODO Try this instead. setParam gives a slight jump at release, in tracking off temp mode.
536 _track->enableController(id, false);
537
538 emit componentChanged(controllerComponent, val, off, id, scrollMode);
539 }
540
controllerMoved(double val,int id,bool shift_pressed)541 void AudioComponentRack::controllerMoved(double val, int id, bool shift_pressed)
542 {
543 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::controllerMoved id:%d val:%.20f\n", id, val);
544 emit componentMoved(controllerComponent, val, id, shift_pressed);
545 }
546
controllerPressed(double v,int id)547 void AudioComponentRack::controllerPressed(double v, int id)
548 {
549 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::controllerPressed id:%d\n", id);
550 double val = 0.0;
551 iComponentWidget ic = _components.find(controllerComponent, -1, id);
552 if(ic != _components.end())
553 {
554 ComponentWidget& cw = *ic;
555 cw._pressed = true;
556 val = componentValue(cw);
557 DEBUG_AUDIO_STRIP(stderr, " val:%.20f\n", val);
558 }
559 _track->startAutoRecord(id, val);
560 _track->setPluginCtrlVal(id, val);
561 //_track->setParam(id, val); // Schedules a timed control change. // TODO Try this instead
562 DEBUG_AUDIO_STRIP(stderr, " calling enableController(false)\n");
563 _track->enableController(id, false);
564
565 emit componentPressed(controllerComponent, v, id);
566 }
567
controllerReleased(double v,int id)568 void AudioComponentRack::controllerReleased(double v, int id)
569 {
570 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::controllerReleased id:%d\n", id);
571 MusECore::AutomationType at = _track->automationType();
572 double val = 0.0;
573 iComponentWidget ic = _components.find(controllerComponent, -1, id);
574 if(ic != _components.end())
575 {
576 ComponentWidget& cw = *ic;
577 val = componentValue(cw);
578 DEBUG_AUDIO_STRIP(stderr, " val:%.20f\n", val);
579 cw._pressed = false;
580 }
581 _track->stopAutoRecord(id, val);
582 if(at == MusECore::AUTO_OFF || at == MusECore::AUTO_TOUCH)
583 {
584 DEBUG_AUDIO_STRIP(stderr, " calling enableController(true)\n");
585 _track->enableController(id, true);
586 }
587
588 emit componentReleased(controllerComponent, v, id);
589 }
590
controllerRightClicked(QPoint p,int id)591 void AudioComponentRack::controllerRightClicked(QPoint p, int id)
592 {
593 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::controllerRightClicked id:%d\n", id);
594 MusEGlobal::song->execAutomationCtlPopup(_track, p, id);
595 }
596
597
propertyChanged(double val,bool off,int id,int scrollMode)598 void AudioComponentRack::propertyChanged(double val, bool off, int id, int scrollMode)
599 {
600 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::propertyChanged id:%d val:%.20f\n", id, val);
601 switch(id)
602 {
603 case aStripGainProperty:
604 if(_track->gain() != val)
605 _track->setGain(val); // FIXME: Realtime safe?
606 break;
607 }
608
609 emit componentChanged(propertyComponent, val, off, id, scrollMode);
610 }
611
propertyMoved(double val,int id,bool shift_pressed)612 void AudioComponentRack::propertyMoved(double val, int id, bool shift_pressed)
613 {
614 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::propertyMoved id:%d val:%.20f\n", id, val);
615 emit componentMoved(propertyComponent, val, id, shift_pressed);
616 }
617
propertyPressed(double val,int id)618 void AudioComponentRack::propertyPressed(double val, int id)
619 {
620 emit componentPressed(propertyComponent, val, id);
621 }
622
propertyReleased(double val,int id)623 void AudioComponentRack::propertyReleased(double val, int id)
624 {
625 emit componentReleased(propertyComponent, val, id);
626 }
627
propertyRightClicked(QPoint,int)628 void AudioComponentRack::propertyRightClicked(QPoint, int)
629 {
630
631 }
632
auxChanged(double val,bool off,int id,int scrollMode)633 void AudioComponentRack::auxChanged(double val, bool off, int id, int scrollMode)
634 {
635 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::auxChanged id:%d val:%.20f\n", id, val);
636 double vol;
637 if (val <= MusEGlobal::config.minSlider)
638 vol = 0.0;
639 else
640 vol = muse_db2val(val);
641 MusEGlobal::audio->msgSetAux(_track, id, vol);
642
643 emit componentChanged(aStripAuxComponent, val, off, id, scrollMode);
644 }
645
auxMoved(double val,int id,bool shift_pressed)646 void AudioComponentRack::auxMoved(double val, int id, bool shift_pressed)
647 {
648 DEBUG_AUDIO_STRIP(stderr, "AudioComponentRack::auxMoved id:%d val:%.20f\n", id, val);
649 emit componentMoved(aStripAuxComponent, val, id, shift_pressed);
650 }
651
auxPressed(double val,int id)652 void AudioComponentRack::auxPressed(double val, int id)
653 {
654 emit componentPressed(aStripAuxComponent, val, id);
655 }
656
auxReleased(double val,int id)657 void AudioComponentRack::auxReleased(double val, int id)
658 {
659 emit componentReleased(aStripAuxComponent, val, id);
660 }
661
auxRightClicked(QPoint,int)662 void AudioComponentRack::auxRightClicked(QPoint, int)
663 {
664
665 }
666
667 //---------------------------------------------------------
668 // songChanged
669 //---------------------------------------------------------
670
songChanged(MusECore::SongChangedStruct_t flags)671 void AudioComponentRack::songChanged(MusECore::SongChangedStruct_t flags)
672 {
673 // Scan controllers.
674 if(flags & (SC_RACK | SC_AUDIO_CONTROLLER_LIST))
675 {
676 scanControllerComponents();
677 }
678
679 // Take care of scanning aux before setting aux enabled below.
680 if(flags & SC_AUX)
681 {
682 scanAuxComponents();
683 }
684
685 if(flags & SC_ROUTE) {
686 // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track!
687 // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels.
688 setAuxEnabled(_track->auxRefCount() == 0);
689 }
690 }
691
692 //---------------------------------------------------------
693 // configChanged
694 // Catch when label font, or configuration min slider and meter values change, or viewable tracks etc.
695 //---------------------------------------------------------
696
configChanged()697 void AudioComponentRack::configChanged()
698 {
699 // Handle font changes etc.
700 ComponentRack::configChanged();
701
702 for(iComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
703 {
704 ComponentWidget& cw = *ic;
705
706 // Whether to show values along with labels for certain controls.
707 setComponentShowValue(cw, MusEGlobal::config.showControlValues);
708
709 switch(cw._componentType)
710 {
711 // Special for Aux controls.
712 case aStripAuxComponent:
713 // Adjust aux minimum value.
714 setComponentRange(cw, MusEGlobal::config.minSlider, AudioStrip::auxSliderMax, true, AudioStrip::auxSliderStep);
715 break;
716 }
717 }
718 setComponentColors();
719 }
720
721 //---------------------------------------------------------
722 // setComponentColors
723 //---------------------------------------------------------
724
setComponentColors()725 void AudioComponentRack::setComponentColors()
726 {
727 for(ciComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
728 {
729 const ComponentWidget& cw = *ic;
730 if(!cw._widget)
731 continue;
732
733 QColor color = MusEGlobal::config.sliderBackgroundColor;
734 switch(cw._componentType)
735 {
736 case aStripAuxComponent:
737 color = MusEGlobal::config.auxSliderColor;
738 break;
739
740 case controllerComponent:
741 {
742 switch(cw._index)
743 {
744 case MusECore::AC_PAN:
745 color = MusEGlobal::config.panSliderColor;
746 break;
747
748 default:
749 color = MusEGlobal::config.audioControllerSliderColor;
750 break;
751 }
752 }
753 break;
754
755 case propertyComponent:
756 {
757 switch(cw._index)
758 {
759 case aStripGainProperty:
760 color = MusEGlobal::config.gainSliderColor;
761 break;
762
763 default:
764 color = MusEGlobal::config.audioPropertySliderColor;
765 break;
766 }
767 }
768 break;
769 }
770
771 switch(cw._widgetType)
772 {
773 case CompactKnobComponentWidget:
774 {
775 CompactKnob* w = static_cast<CompactKnob*>(cw._widget);
776 w->setFaceColor(color);
777 }
778 break;
779
780 case CompactSliderComponentWidget:
781 {
782 CompactSlider* w = static_cast<CompactSlider*>(cw._widget);
783 w->setBorderColor(color);
784 w->setThumbColor(color);
785 w->setBarColor(MusEGlobal::config.sliderBarColor);
786 w->setSlotColor(MusEGlobal::config.sliderBackgroundColor);
787 }
788 break;
789 }
790 }
791 }
792
793
794 //---------------------------------------------------------
795 // AudioStripProperties
796 //---------------------------------------------------------
797
AudioStripProperties()798 AudioStripProperties::AudioStripProperties()
799 {
800 _sliderRadius = 4;
801 _sliderRadiusHandle = 2;
802 _sliderHandleHeight = 16;
803 _sliderHandleWidth = 16;
804 _sliderFillOver = true;
805 _sliderUseGradient = true;
806 _sliderBackbone = false;
807 _sliderFillHandle = true;
808 _sliderGrooveWidth = 14;
809 _sliderScalePos = Slider::InsideVertical;
810 _sliderFrame = false;
811 _sliderFrameColor = Qt::darkGray;
812 _meterWidth = Strip::FIXED_METER_WIDTH;
813 _meterWidthPerChannel = false;
814 _meterSpacing = 4;
815 _meterFrame = false;
816 _meterFrameColor = Qt::darkGray;
817 ensurePolished();
818 }
819
820 //---------------------------------------------------------
821 // AudioStrip
822 //---------------------------------------------------------
823
824 //---------------------------------------------------------
825 // heartBeat
826 //---------------------------------------------------------
827
heartBeat()828 void AudioStrip::heartBeat()
829 {
830 const int tch = track->channels();
831 for (int ch = 0; ch < tch; ++ch) {
832 if (meter[ch]) {
833 meter[ch]->setVal(track->meter(ch), track->peak(ch), false);
834 }
835 if(_clipperLabel[ch])
836 {
837 _clipperLabel[ch]->setVal(track->peak(ch));
838 _clipperLabel[ch]->setClipped(track->isClipped(ch));
839 }
840 }
841 updateVolume();
842 _upperRack->updateComponents();
843 // _infoRack->updateComponents();
844 _lowerRack->updateComponents();
845
846 // if(_recMonitor && _recMonitor->isChecked() && MusEGlobal::blinkTimerPhase != _recMonitor->blinkPhase())
847 // _recMonitor->setBlinkPhase(MusEGlobal::blinkTimerPhase);
848
849 Strip::heartBeat();
850 }
851
updateRackSizes(bool upper,bool lower)852 void AudioStrip::updateRackSizes(bool upper, bool lower)
853 {
854 // const QFontMetrics fm = fontMetrics();
855 if(upper)
856 {
857 // Make room for 3 CompactSliders and one CompactPatchEdit.
858 // TODO: Add the instrument select label height!
859
860 // // const int csh = CompactSlider::getMinimumSizeHint(fm,
861 // // Qt::Horizontal,
862 // // CompactSlider::None,
863 // // xMarginHorSlider, yMarginHorSlider).height();
864 // // const int cpeh = CompactPatchEdit::getMinimumSizeHint(fm,
865 // // Qt::Horizontal,
866 // // CompactSlider::None,
867 // // xMarginHorSlider, yMarginHorSlider).height();
868 // // const int ilh = _instrLabel->sizeHint().height();
869 //
870 // // DEBUG_AUDIO_STRIP(stderr, "MidiStrip::updateRackSizes: CompactSlider h:%d CompactPatchEdit h:%d instrLabel h:%d upper frame w:%d \n",
871 // // csh, cpeh, ilh, _upperRack->frameWidth());
872
873 // _upperRack->setMinimumHeight(
874 // 3 * CompactSlider::getMinimumSizeHint(fm,
875 // Qt::Horizontal,
876 // CompactSlider::None,
877 // xMarginHorSlider, yMarginHorSlider).height() +
878 // 1 * CompactPatchEdit::getMinimumSizeHint(fm,
879 // Qt::Horizontal,
880 // CompactSlider::None,
881 // xMarginHorSlider, yMarginHorSlider).height() +
882 // upperRackSpacerHeight +
883 //
884 // _instrLabel->sizeHint().height() +
885 //
886 // 2 * rackFrameWidth);
887 }
888 if(lower)
889 {
890 // Make room for 1 CompactSlider (Pan, so far).
891
892 //DEBUG_AUDIO_STRIP(stderr, "MidiStrip::updateRackSizes: lower frame w:%d \n", _lowerRack->frameWidth());
893
894 // _lowerRack->setMinimumHeight(
895 // 1 * CompactSlider::getMinimumSizeHint(fm,
896 // Qt::Horizontal,
897 // CompactSlider::None,
898 // xMarginHorSlider, yMarginHorSlider).height() +
899 // 2 * rackFrameWidth);
900 }
901 }
902
903 //---------------------------------------------------------
904 // configChanged
905 // Catch when label font, or configuration min slider and meter values change, or viewable tracks etc.
906 //---------------------------------------------------------
907
configChanged()908 void AudioStrip::configChanged()
909 {
910 // Detect when knobs are preferred and rebuild.
911 if(_preferKnobs != MusEGlobal::config.preferKnobsVsSliders)
912 {
913 _preferKnobs = MusEGlobal::config.preferKnobsVsSliders;
914 // Rebuild the strip components.
915 buildStrip();
916 // Now set up all tabbing on the strip.
917 // Don't bother if the strip is part of the mixer (not embedded),
918 // the non-embedding parent (mixer) should set up all the tabs and make this call.
919 if(isEmbedded())
920 setupComponentTabbing();
921 }
922
923 // Set the whole strip's font, except for the label.
924 if (font() != MusEGlobal::config.fonts[1])
925 {
926 // DEBUG_AUDIO_STRIP(stderr, "AudioStrip::configChanged changing font: current size:%d\n", font().pointSize());
927 setStripStyle();
928 }
929
930 // Set the strip label's font.
931 setLabelText();
932
933 slider->setFillColor(MusEGlobal::config.audioVolumeSliderColor);
934 slider->setHandleColor(MusEGlobal::config.audioVolumeHandleColor);
935
936 // Adjust minimum volume slider and label values.
937 slider->setRange(MusEGlobal::config.minSlider, volSliderMax, volSliderStep);
938 slider->setScale(MusEGlobal::config.minSlider, volSliderMax, 6.0, false);
939
940 sl->setRange(MusEGlobal::config.minSlider, volSliderMax);
941 sl->setOff(MusEGlobal::config.minSlider);
942 // Enable special hack for line edits.
943 // if(sl->enableStyleHack() != MusEGlobal::config.lineEditStyleHack)
944 // sl->setEnableStyleHack(MusEGlobal::config.lineEditStyleHack);
945
946 // REMOVE Tim. mixer. Added.
947 // In case something in the slider changed, update the meter layout.
948 // TODO This is somewhat crude, might miss automatic changes.
949 // Later link up MeterLayout and Slider better.
950 _meterLayout->setMeterEndsMargin(slider->scaleEndpointsMargin());
951
952 // Possible, but leave it to the background painter for now.
953 //rack->setActiveColor(MusEGlobal::config.rackItemBackgroundColor);
954
955 _upperRack->configChanged();
956 // _infoRack->configChanged();
957 _lowerRack->configChanged();
958
959 // Ensure updateGeometry is called in case the number of rack items changed.
960 // Not required for at least suse, but required for at least mint cinnamon.
961 rack->updateGeometry();
962 rack->update();
963
964 // Adjust minimum meter values, and colours.
965 for(int c = 0; c < channel; ++c)
966 {
967 meter[c]->setRange(MusEGlobal::config.minMeter, volSliderMax);
968 meter[c]->setPrimaryColor(MusEGlobal::config.audioMeterPrimaryColor,
969 MusEGlobal::config.meterBackgroundColor);
970 meter[c]->setRefreshRate(MusEGlobal::config.guiRefresh);
971 }
972
973 }
974
975 //---------------------------------------------------------
976 // songChanged
977 //---------------------------------------------------------
978
songChanged(MusECore::SongChangedStruct_t val)979 void AudioStrip::songChanged(MusECore::SongChangedStruct_t val)
980 {
981 MusECore::AudioTrack* src = static_cast<MusECore::AudioTrack*>(track);
982
983 // Do channels before MusEGlobal::config...
984 if (val & SC_CHANNELS)
985 updateChannels();
986
987 // Catch when label font, or configuration min slider and meter values change.
988 if (val & SC_CONFIG)
989 {
990 // So far only 1 instance of sending SC_CONFIG in the entire app, in instrument editor when a new instrument is saved.
991 }
992
993 if (mute && (val & SC_MUTE)) { // mute && off
994 mute->blockSignals(true);
995 mute->setChecked(src->mute());
996 mute->blockSignals(false);
997 updateMuteIcon();
998 updateOffState();
999 }
1000 if (solo && (val & (SC_SOLO | SC_ROUTE))) {
1001 solo->blockSignals(true);
1002 solo->setChecked(track->solo());
1003 solo->blockSignals(false);
1004 // solo->setIconSetB(track->internalSolo());
1005 if (track->internalSolo()) {
1006 if (solo->isChecked())
1007 solo->setIcon(*soloAndProxyOnSVGIcon);
1008 else
1009 solo->setIcon(*soloProxyOnAloneSVGIcon);
1010 } else {
1011 solo->setIcon(*soloStateSVGIcon);
1012 }
1013 updateMuteIcon();
1014 }
1015 if (val & SC_RECFLAG)
1016 {
1017 setRecordFlag(track->recordFlag());
1018 }
1019 if (val & SC_TRACK_MODIFIED)
1020 {
1021 setLabelText();
1022 }
1023 //if (val & SC_CHANNELS)
1024 // updateChannels();
1025 if (val & SC_ROUTE) {
1026 updateRouteButtons();
1027 if (pre) {
1028 pre->blockSignals(true);
1029 pre->setChecked(src->prefader());
1030 pre->blockSignals(false);
1031 }
1032 }
1033
1034 if(val & SC_TRACK_REC_MONITOR)
1035 {
1036 // Set record monitor.
1037 if(_recMonitor) // && (_recMonitor->isChecked() != track->recMonitor()))
1038 {
1039 _recMonitor->blockSignals(true);
1040 _recMonitor->setChecked(track->recMonitor());
1041 _recMonitor->blockSignals(false);
1042 }
1043 }
1044 // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track!
1045 // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels.
1046 _upperRack->songChanged(val);
1047 // _infoRack->songChanged(val);
1048 _lowerRack->songChanged(val);
1049
1050 if (autoType && (val & SC_AUTOMATION)) {
1051 autoType->blockSignals(true);
1052 autoType->setCurrentItem(track->automationType());
1053 colorAutoType();
1054 autoType->blockSignals(false);
1055 }
1056 }
1057
1058 //---------------------------------------------------------
1059 // updateVolume
1060 //---------------------------------------------------------
1061
updateVolume()1062 void AudioStrip::updateVolume()
1063 {
1064 if(_volPressed) // Inhibit the controller stream if control is currently pressed.
1065 return;
1066 double vol = static_cast<MusECore::AudioTrack*>(track)->volume();
1067 if (vol != volume)
1068 {
1069 double val;
1070 if(vol == 0.0)
1071 val = MusEGlobal::config.minSlider;
1072 else
1073 {
1074 val = muse_val2dbr(vol);
1075 if(val < MusEGlobal::config.minSlider)
1076 val = MusEGlobal::config.minSlider;
1077 }
1078
1079 slider->blockSignals(true);
1080 sl->blockSignals(true);
1081 // Slider::fitValue should not be required since the log function is accurate but rounded to the nearest .000001
1082 slider->setValue(val);
1083 sl->setValue(val);
1084 sl->blockSignals(false);
1085 slider->blockSignals(false);
1086 volume = vol;
1087 }
1088 }
1089
1090 //---------------------------------------------------------
1091 // offToggled
1092 //---------------------------------------------------------
1093
offToggled(bool val)1094 void AudioStrip::offToggled(bool val)
1095 {
1096 if(!track)
1097 return;
1098 // This is a minor operation easily manually undoable. Let's not clog the undo list with it.
1099 MusECore::PendingOperationList operations;
1100 operations.add(MusECore::PendingOperationItem(track, val, MusECore::PendingOperationItem::SetTrackOff));
1101 MusEGlobal::audio->msgExecutePendingOperations(operations, true);
1102 }
1103
1104 //---------------------------------------------------------
1105 // updateOffState
1106 //---------------------------------------------------------
1107
updateOffState()1108 void AudioStrip::updateOffState()
1109 {
1110 bool val = !track->off();
1111 slider->setEnabled(val);
1112 sl->setEnabled(val);
1113
1114 _upperRack->setEnabled(val);
1115 // _infoRack->setEnabled(val);
1116 _lowerRack->setEnabled(val);
1117
1118 if (track->type() != MusECore::Track::AUDIO_SOFTSYNTH)
1119 stereo->setEnabled(val);
1120 label->setEnabled(val);
1121
1122 // Are there any Aux Track routing paths to this track? Then we cannot process aux for this track!
1123 // Hate to do this, but as a quick visual reminder, seems most logical to disable Aux knobs and labels.
1124 const bool ae = track->auxRefCount() == 0 && val;
1125 _upperRack->setAuxEnabled(ae);
1126 // _infoRack->setAuxEnabled(ae);
1127 _lowerRack->setAuxEnabled(ae);
1128
1129 if (_recMonitor)
1130 _recMonitor->setEnabled(val);
1131 if (pre)
1132 pre->setEnabled(val);
1133 if (record)
1134 record->setEnabled(val);
1135 if (solo)
1136 solo->setEnabled(val);
1137 if (mute)
1138 mute->setEnabled(val);
1139 if (off) {
1140 off->blockSignals(true);
1141 off->setChecked(track->off());
1142 off->blockSignals(false);
1143 }
1144 }
1145
1146 //---------------------------------------------------------
1147 // preToggled
1148 //---------------------------------------------------------
1149
preToggled(bool val)1150 void AudioStrip::preToggled(bool val)
1151 {
1152 if(!track)
1153 return;
1154 MusEGlobal::audio->msgSetPrefader(static_cast<MusECore::AudioTrack*>(track), val);
1155 resetPeaks();
1156 MusEGlobal::song->update(SC_ROUTE);
1157 }
1158
1159 //---------------------------------------------------------
1160 // stereoToggled
1161 //---------------------------------------------------------
1162
stereoToggled(bool val)1163 void AudioStrip::stereoToggled(bool val)
1164 {
1165 if(!track)
1166 return;
1167 const int nc = val ? 2 : 1;
1168 const int oc = track->channels();
1169 if (oc == nc)
1170 return;
1171 MusEGlobal::audio->msgSetChannels(static_cast<MusECore::AudioTrack*>(track), nc);
1172 MusEGlobal::song->update(SC_CHANNELS);
1173 }
1174
1175 //---------------------------------------------------------
1176 // recMonitorToggled
1177 //---------------------------------------------------------
1178
recMonitorToggled(bool v)1179 void AudioStrip::recMonitorToggled(bool v)
1180 {
1181 if(!track)
1182 return;
1183 // This is a minor operation easily manually undoable. Let's not clog the undo list with it.
1184 MusECore::PendingOperationList operations;
1185 operations.add(MusECore::PendingOperationItem(track, v, MusECore::PendingOperationItem::SetTrackRecMonitor));
1186 MusEGlobal::audio->msgExecutePendingOperations(operations, true);
1187 }
1188
1189 //---------------------------------------------------------
1190 // volumeMoved
1191 //---------------------------------------------------------
1192
volumeMoved(double val,int id,bool shift_pressed)1193 void AudioStrip::volumeMoved(double val, int id, bool shift_pressed)
1194 {
1195 DEBUG_AUDIO_STRIP(stderr, "AudioStrip::volumeMoved id:%d val:%.20f\n", id, val);
1196 componentMoved(ComponentRack::controllerComponent, val, id, shift_pressed);
1197 }
1198
1199 //---------------------------------------------------------
1200 // volumeChanged
1201 //---------------------------------------------------------
1202
volumeChanged(double val,int id,int scrollMode)1203 void AudioStrip::volumeChanged(double val, int id, int scrollMode)
1204 {
1205 DEBUG_AUDIO_STRIP(stderr, "AudioStrip::volumeChanged id:%d val:%.20f scrollMode:%d\n", id, val, scrollMode);
1206
1207 if(!track || track->isMidiTrack())
1208 return;
1209
1210 double vol;
1211 if (val <= MusEGlobal::config.minSlider)
1212 vol = 0.0;
1213 else
1214 vol = muse_db2val(val);
1215 volume = vol;
1216
1217 MusECore::AudioTrack* at = static_cast<MusECore::AudioTrack*>(track);
1218 // Hack: Be sure to ignore in ScrDirect mode since we get both pressed AND changed signals.
1219 // ScrDirect mode is one-time only on press with modifier.
1220 if(scrollMode != SliderBase::ScrDirect)
1221 at->recordAutomation(id, vol);
1222 at->setParam(id, vol); // Schedules a timed control change.
1223 at->enableController(id, false);
1224
1225 componentChanged(ComponentRack::controllerComponent, val, false, id, scrollMode);
1226 }
1227
1228 //---------------------------------------------------------
1229 // volumePressed
1230 //---------------------------------------------------------
1231
volumePressed(double val,int id)1232 void AudioStrip::volumePressed(double val, int id)
1233 {
1234 DEBUG_AUDIO_STRIP(stderr, "AudioStrip::volumePressed\n");
1235 if(!track || track->isMidiTrack())
1236 return;
1237 _volPressed = true;
1238 double vol;
1239 if (val <= MusEGlobal::config.minSlider)
1240 vol = 0.0;
1241 else
1242 vol = muse_db2val(val);
1243 volume = vol;
1244 DEBUG_AUDIO_STRIP(stderr, " val:%.20f\n", volume);
1245
1246 MusECore::AudioTrack* at = static_cast<MusECore::AudioTrack*>(track);
1247 at->startAutoRecord(id, vol);
1248 at->setVolume(vol);
1249 //at->setParam(MusECore::AC_VOLUME, val); // Schedules a timed control change. // TODO Try this instead
1250 DEBUG_AUDIO_STRIP(stderr, " calling enableController(false)\n");
1251 at->enableController(id, false);
1252
1253 componentPressed(ComponentRack::controllerComponent, val, id);
1254 }
1255
1256 //---------------------------------------------------------
1257 // volumeReleased
1258 //---------------------------------------------------------
1259
volumeReleased(double val,int id)1260 void AudioStrip::volumeReleased(double val, int id)
1261 {
1262 DEBUG_AUDIO_STRIP(stderr, "AudioStrip::volumeReleased\n");
1263 if(!track || track->isMidiTrack())
1264 return;
1265
1266 MusECore::AudioTrack* at = static_cast<MusECore::AudioTrack*>(track);
1267 MusECore::AutomationType atype = at->automationType();
1268 DEBUG_AUDIO_STRIP(stderr, " val:%.20f\n", volume);
1269 at->stopAutoRecord(id, volume);
1270 if(atype == MusECore::AUTO_OFF || atype == MusECore::AUTO_TOUCH)
1271 {
1272 DEBUG_AUDIO_STRIP(stderr, " calling enableController(true)\n");
1273 at->enableController(id, true);
1274 }
1275
1276 componentReleased(ComponentRack::controllerComponent, val, id);
1277 _volPressed = false;
1278 }
1279
1280 //---------------------------------------------------------
1281 // volumeRightClicked
1282 //---------------------------------------------------------
volumeRightClicked(QPoint p)1283 void AudioStrip::volumeRightClicked(QPoint p)
1284 {
1285 MusEGlobal::song->execAutomationCtlPopup(static_cast<MusECore::AudioTrack*>(track), p, MusECore::AC_VOLUME);
1286 }
1287
1288 //---------------------------------------------------------
1289 // volLabelChanged
1290 //---------------------------------------------------------
1291
volLabelChanged(double val)1292 void AudioStrip::volLabelChanged(double val)
1293 {
1294 if(!track || track->isMidiTrack())
1295 return;
1296 MusECore::AudioTrack* t = static_cast<MusECore::AudioTrack*>(track);
1297 double v = val;
1298 double vol;
1299 if (v <= MusEGlobal::config.minSlider) {
1300 vol = 0.0;
1301 v = MusEGlobal::config.minSlider;
1302 }
1303 else
1304 vol = muse_db2val(v);
1305 volume = vol;
1306 slider->blockSignals(true);
1307 slider->setValue(v);
1308 slider->blockSignals(false);
1309 t->startAutoRecord(MusECore::AC_VOLUME, vol);
1310 t->setParam(MusECore::AC_VOLUME, vol); // Schedules a timed control change.
1311 t->enableController(MusECore::AC_VOLUME, false);
1312
1313 componentChanged(ComponentRack::controllerComponent, val, false, MusECore::AC_VOLUME, SliderBase::ScrNone);
1314 }
1315
resetClipper()1316 void AudioStrip::resetClipper()
1317 {
1318 if(track)
1319 {
1320 track->resetClipper();
1321 resetPeaks();
1322 }
1323 }
1324
1325 //---------------------------------------------------------
1326 // updateChannels
1327 //---------------------------------------------------------
1328
updateChannels()1329 void AudioStrip::updateChannels()
1330 {
1331 MusECore::AudioTrack* t = static_cast<MusECore::AudioTrack*>(track);
1332 int c = t->channels();
1333 DEBUG_AUDIO_STRIP(stderr, "AudioStrip::updateChannels track channels:%d current channels:%d\n", c, channel);
1334
1335 if (c > channel) {
1336 for (int cc = channel; cc < c; ++cc) {
1337 _clipperLabel[cc] = new ClipperLabel();
1338 _clipperLabel[cc]->setContentsMargins(0, 0, 0, 0);
1339 _clipperLabel[cc]->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
1340 setClipperTooltip(cc);
1341 _clipperLayout->addWidget(_clipperLabel[cc]);
1342 connect(_clipperLabel[cc], SIGNAL(clicked()), SLOT(resetClipper()));
1343
1344 meter[cc] = new Meter(this, Meter::DBMeter, Qt::Vertical, MusEGlobal::config.minMeter, volSliderMax);
1345 meter[cc]->setRefreshRate(MusEGlobal::config.guiRefresh);
1346 meter[cc]->setFixedWidth(props.meterWidth());
1347 meter[cc]->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
1348 meter[cc]->setPrimaryColor(MusEGlobal::config.audioMeterPrimaryColor,
1349 MusEGlobal::config.meterBackgroundColor);
1350 meter[cc]->setFrame(props.meterFrame(), props.meterFrameColor());
1351 connect(meter[cc], SIGNAL(mousePress()), this, SLOT(resetClipper()));
1352 _meterLayout->hlayout()->addWidget(meter[cc], Qt::AlignLeft);
1353 // meter[cc]->show();
1354 }
1355 }
1356 else if (c < channel) {
1357 for (int cc = channel-1; cc >= c; --cc) {
1358 if(_clipperLabel[cc])
1359 delete _clipperLabel[cc];
1360 _clipperLabel[cc] = nullptr;
1361
1362 if(meter[cc])
1363 delete meter[cc];
1364 meter[cc] = nullptr;
1365 }
1366 }
1367
1368 if (meter[0] && !meter[0]->vu3d() && !props.meterWidthPerChannel()) {
1369 for (int ch = 0; ch < c; ++ch) {
1370 meter[ch]->setFixedWidth(props.meterWidth() / c);
1371 }
1372 }
1373
1374 channel = c;
1375 stereo->blockSignals(true);
1376 stereo->setChecked(channel == 2);
1377 stereo->blockSignals(false);
1378 update();
1379 }
1380
1381 //---------------------------------------------------------
1382 // AudioStrip
1383 //---------------------------------------------------------
1384
~AudioStrip()1385 AudioStrip::~AudioStrip()
1386 {
1387 }
1388
1389 //---------------------------------------------------------
1390 // AudioStrip
1391 // create mixer strip
1392 //---------------------------------------------------------
1393
AudioStrip(QWidget * parent,MusECore::AudioTrack * at,bool hasHandle,bool isEmbedded)1394 AudioStrip::AudioStrip(QWidget* parent, MusECore::AudioTrack* at, bool hasHandle, bool isEmbedded)
1395 : Strip(parent, at, hasHandle, isEmbedded)
1396 {
1397 _preferKnobs = MusEGlobal::config.preferKnobsVsSliders;
1398
1399 MusECore::Track::TrackType type = at->type();
1400
1401 volume = -1.0;
1402 _volPressed = false;
1403
1404 slider = nullptr;
1405 sl = nullptr;
1406 off = nullptr;
1407 _recMonitor = nullptr;
1408
1409 // Start the layout in mode A (normal, racks on left).
1410 _isExpanded = false;
1411
1412 setStripStyle();
1413
1414 channel = at->channels();
1415
1416 _routePos = GridPosStruct(_curGridRow, 0, 1, 3);
1417 _effectRackPos = GridPosStruct(_curGridRow + 1, 0, 1, 3);
1418 _stereoPrePos = GridPosStruct(_curGridRow + 2, 0, 1, 3);
1419 _upperRackPos = GridPosStruct(_curGridRow + 3, 0, 1, 3);
1420 _sliderMeterPos = GridPosStruct(_curGridRow + 4, 0, 1, 3);
1421 _lowerRackPos = GridPosStruct(_curGridRow + 5, 0, 1, 3);
1422 _bottomPos = GridPosStruct(_curGridRow + 6, 0, 1, 3);
1423 // _routePos = GridPosStruct(_curGridRow, 0, 1, 2);
1424 // _effectRackPos = GridPosStruct(_curGridRow + 1, 0, 1, 3);
1425 // _stereoPrePos = GridPosStruct(_curGridRow + 2, 0, 1, 2);
1426 // _upperRackPos = GridPosStruct(_curGridRow + 3, 0, 1, 3);
1427 // _sliderMeterPos = GridPosStruct(_curGridRow + 4, 0, 1, 2);
1428 // _lowerRackPos = GridPosStruct(_curGridRow + 5, 0, 1, 3);
1429 // _bottomPos = GridPosStruct(_curGridRow + 6, 0, 1, 2);
1430
1431 //---------------------------------------------------
1432 // routing
1433 //---------------------------------------------------
1434
1435 QHBoxLayout *routeLayout = new QHBoxLayout;
1436 routeLayout->setContentsMargins(1,3,1,2);
1437 routeLayout->setSpacing(1);
1438
1439 if (type != MusECore::Track::AUDIO_AUX) {
1440 // iR = new IconButton(routingInputSVGIcon, routingInputSVGIcon,
1441 // routingInputUnconnectedSVGIcon, routingInputUnconnectedSVGIcon, false, true);
1442 iR = new QPushButton(this);
1443 iR->setIcon(*routingInputSVGIcon);
1444 iR->setStatusTip(tr("Input routing. Hold CTRL to keep menu open. Press F1 for help."));
1445 iR->setFocusPolicy(Qt::NoFocus);
1446 iR->setCheckable(false);
1447 iR->setToolTip(MusEGlobal::inputRoutingToolTipBase);
1448 connect(iR, SIGNAL(pressed()), SLOT(iRoutePressed()));
1449 routeLayout->addWidget(iR);
1450 } else {
1451 QPushButton *iRx = new QPushButton(this);
1452 iRx->setIcon(*routingInputSVGIcon);
1453 iRx->setEnabled(false);
1454 routeLayout->addWidget(iRx);
1455 }
1456
1457 // oR = new IconButton(routingOutputSVGIcon, routingOutputSVGIcon,
1458 // routingOutputUnconnectedSVGIcon, routingOutputUnconnectedSVGIcon, false, true);
1459 oR = new QPushButton(this);
1460 oR->setIcon(*routingOutputSVGIcon);
1461 oR->setObjectName("OutputRouteButton");
1462 oR->setStatusTip(tr("Output routing. Hold CTRL to keep menu open. Press F1 for help."));
1463 oR->setFocusPolicy(Qt::NoFocus);
1464 oR->setCheckable(false);
1465 oR->setToolTip(MusEGlobal::outputRoutingToolTipBase);
1466 connect(oR, SIGNAL(pressed()), SLOT(oRoutePressed()));
1467 routeLayout->addWidget(oR);
1468
1469 updateRouteButtons();
1470
1471 addGridLayout(routeLayout, _routePos);
1472
1473 // _infoRack = new AudioComponentRack(at, aStripInfoRack, false);
1474 // //_infoRack->setVisible(false); // Not visible unless expanded.
1475 // _infoRack->setVisible(false); // Hide until we figure out what to put in there....
1476 // // FIXME For some reason StyledPanel has trouble, intermittent sometimes panel is drawn, sometimes not.
1477 // //_infoRack->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
1478 // _infoRack->setFrameStyle(QFrame::Box | QFrame::Sunken);
1479 // _infoRack->setLineWidth(rackFrameWidth);
1480 // _infoRack->setMidLineWidth(0);
1481 // _infoRack->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Minimum);
1482 // _infoRack->setContentsMargins(rackFrameWidth, rackFrameWidth, rackFrameWidth, rackFrameWidth);
1483 // _infoRack->setFocusPolicy(Qt::NoFocus);
1484 // _infoRack->addStretch();
1485 // addGridWidget(_infoRack, _propertyRackPos);
1486
1487 // grid->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::Expanding),
1488 // _infoSpacerTop._row, _infoSpacerTop._col, _infoSpacerTop._rowSpan, _infoSpacerTop._colSpan);
1489
1490 _upperRack = new AudioComponentRack(at, aStripUpperRack, true); // True = manage auxs.
1491 // FIXME For some reason StyledPanel has trouble, intermittent sometimes panel is drawn, sometimes not.
1492 //_upperRack->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
1493 _upperRack->setFrameStyle(QFrame::Box | QFrame::Sunken);
1494 _upperRack->setLineWidth(rackFrameWidth);
1495 _upperRack->setMidLineWidth(0);
1496 // We do set a minimum height on this widget. Tested: Must be on fixed. Thankfully, it'll expand if more controls are added.
1497 _upperRack->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
1498 _upperRack->setContentsMargins(rackFrameWidth, rackFrameWidth, rackFrameWidth, rackFrameWidth);
1499 _upperRack->setFocusPolicy(Qt::NoFocus);
1500
1501 //---------------------------------------------------
1502 // plugin rack
1503 //---------------------------------------------------
1504
1505 rack = new EffectRack(this, at);
1506 rack->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Minimum);
1507
1508 addGridWidget(rack, _effectRackPos);
1509 addGridWidget(_upperRack, _upperRackPos);
1510
1511 //---------------------------------------------------
1512 // mono/stereo pre/post
1513 //---------------------------------------------------
1514
1515 QHBoxLayout *stereoPreLayout = new QHBoxLayout;
1516 stereoPreLayout->setContentsMargins(1,2,1,2);
1517 stereoPreLayout->setSpacing(1);
1518
1519 // stereo = new IconButton(stereoOnSVGIcon, stereoOffSVGIcon, nullptr, nullptr, false, true);
1520 stereo = new QPushButton(this);
1521 stereo->setIcon(*stereoOnSVGIcon);
1522 stereo->setFocusPolicy(Qt::NoFocus);
1523 stereo->setCheckable(true);
1524 stereo->setToolTip(tr("1/2 channel"));
1525 stereo->setChecked(channel == 2);
1526
1527 // disable mono/stereo for Synthesizer-Plugins
1528 if (type == MusECore::Track::AUDIO_SOFTSYNTH)
1529 stereo->setEnabled(false);
1530
1531 connect(stereo, SIGNAL(toggled(bool)), SLOT(stereoToggled(bool)));
1532 stereoPreLayout->addWidget(stereo);
1533
1534
1535 // pre = new IconButton(preFaderOnSVGIcon, preFaderOffSVGIcon, nullptr, nullptr, false, true);
1536 pre = new QPushButton(this);
1537 pre->setIcon(*preFaderOnSVGIcon);
1538 pre->setFocusPolicy(Qt::NoFocus);
1539 pre->setCheckable(true);
1540 pre->setToolTip(tr("Pre Fader Listening (PFL)"));
1541 pre->setChecked(at->prefader());
1542 connect(pre, SIGNAL(toggled(bool)), SLOT(preToggled(bool)));
1543 stereoPreLayout->addWidget(pre);
1544
1545 addGridLayout(stereoPreLayout, _stereoPrePos);
1546
1547 //---------------------------------------------------
1548 // slider, label, meter
1549 //---------------------------------------------------
1550
1551 sliderGrid = new QGridLayout();
1552 sliderGrid->setContentsMargins(2, 0, 3, 2);
1553 sliderGrid->setSpacing(0);
1554 sliderGrid->setHorizontalSpacing(2);
1555
1556 /*-------------- clipper label -------------------*/
1557 _clipperLayout = new QHBoxLayout();
1558 _clipperLayout->setSpacing(0);
1559
1560 {
1561 int ch = 0;
1562 for (; ch < channel; ++ch)
1563 {
1564 _clipperLabel[ch] = new ClipperLabel(this);
1565 _clipperLabel[ch]->setContentsMargins(0, 0, 0, 0);
1566 _clipperLabel[ch]->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
1567 setClipperTooltip(ch);
1568 connect(_clipperLabel[ch], SIGNAL(clicked()), SLOT(resetClipper()));
1569 _clipperLayout->addWidget(_clipperLabel[ch]);
1570 }
1571 for (; ch < MusECore::MAX_CHANNELS; ++ch)
1572 {
1573 _clipperLabel[ch] = nullptr;
1574 meter[ch] = nullptr;
1575 }
1576 }
1577
1578 sliderGrid->addLayout(_clipperLayout, 0, 0, 1, 2, Qt::AlignCenter);
1579
1580 slider = new Slider(this, "vol", Qt::Vertical, MusEGui::Slider::InsideVertical, 14,
1581 MusEGlobal::config.audioVolumeSliderColor,
1582 ScaleDraw::TextHighlightSplitAndShadow,
1583 MusEGlobal::config.audioVolumeHandleColor);
1584 slider->setId(MusECore::AC_VOLUME);
1585 slider->setFocusPolicy(Qt::NoFocus);
1586 slider->setContentsMargins(0, 0, 0, 0);
1587 slider->setCursorHoming(true);
1588 DEBUG_AUDIO_STRIP(stderr, "AudioStrip::AudioStrip new slider: step:%.20f\n", volSliderStep);
1589 slider->setRange(MusEGlobal::config.minSlider, volSliderMax, volSliderStep);
1590 //slider->setScaleMaxMinor(5);
1591 slider->setScale(MusEGlobal::config.minSlider, volSliderMax, 6.0, false);
1592 slider->setSpecialText(QString('-') + QChar(0x221e)); // The infinity character.
1593 slider->setScaleBackBone(props.sliderBackbone());
1594
1595 slider->setRadius(props.sliderRadius());
1596 slider->setRadiusHandle(props.sliderRadiusHandle());
1597 slider->setHandleHeight(props.sliderHandleHeight());
1598 slider->setHandleWidth(props.sliderHandleWidth());
1599 slider->setFillThumb(props.sliderFillHandle());
1600 slider->setGrooveWidth(props.sliderGrooveWidth());
1601 slider->setFillEmptySide(props.sliderFillOver());
1602 slider->setUseGradient(props.sliderUseGradient());
1603 slider->setScalePos(static_cast<Slider::ScalePos>(props.sliderScalePos()));
1604 slider->setFrame(props.sliderFrame());
1605 slider->setFrameColor(props.sliderFrameColor());
1606
1607 slider->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
1608 slider->setMinimumHeight(80);
1609
1610 double track_vol = at->volume();
1611 if(track_vol == 0.0)
1612 track_vol = MusEGlobal::config.minSlider;
1613 else
1614 {
1615 track_vol = muse_val2dbr(track_vol);
1616 if(track_vol < MusEGlobal::config.minSlider)
1617 track_vol = MusEGlobal::config.minSlider;
1618 }
1619 // Slider::fitValue() not required so far. The log function is accurate but rounded to the nearest .000001
1620 slider->setValue(track_vol);
1621
1622 sliderGrid->addWidget(slider, 1, 0, Qt::AlignHCenter);
1623
1624 _meterLayout = new MeterLayout(slider->scaleEndpointsMargin());
1625 _meterLayout->setMargin(0);
1626 _meterLayout->setSpacing(props.meterSpacing());
1627
1628 sliderGrid->addLayout(_meterLayout, 1, 1, Qt::AlignHCenter);
1629
1630 for (int i = 0; i < channel; ++i) {
1631 meter[i] = new Meter(this, Meter::DBMeter, Qt::Vertical, MusEGlobal::config.minMeter, volSliderMax);
1632 meter[i]->setRefreshRate(MusEGlobal::config.guiRefresh);
1633 if (meter[i]->vu3d() || props.meterWidthPerChannel()) {
1634 meter[i]->setFixedWidth(props.meterWidth());
1635 }
1636 else {
1637 meter[i]->setFixedWidth(props.meterWidth() / channel);
1638 }
1639 meter[i]->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
1640 meter[i]->setRange(MusEGlobal::config.minMeter, volSliderMax);
1641 meter[i]->setPrimaryColor(MusEGlobal::config.audioMeterPrimaryColor,
1642 MusEGlobal::config.meterBackgroundColor);
1643 meter[i]->setFrame(props.meterFrame(), props.meterFrameColor());
1644 connect(meter[i], SIGNAL(mousePress()), this, SLOT(resetClipper()));
1645 _meterLayout->hlayout()->addWidget(meter[i], Qt::AlignHCenter);
1646 }
1647
1648 sl = new DoubleLabel(0.0, MusEGlobal::config.minSlider, volSliderMax, this);
1649 sl->setObjectName("VolumeEditAudio");
1650 sl->setContentsMargins(0, 0, 0, 0);
1651 sl->setTextMargins(0, 0, 0, 0);
1652 sl->setFocusPolicy(Qt::WheelFocus);
1653 sl->setMouseTracking(true);
1654 sl->setFrame(true);
1655 sl->setAlignment(Qt::AlignCenter);
1656 //sl->setAutoFillBackground(true);
1657
1658 sl->setSlider(slider);
1659 //sl->setBackgroundRole(QPalette::Mid);
1660 sl->setToolTip(tr("Volume/Gain"));
1661 sl->setSuffix("dB");
1662 sl->setSpecialText(QString('-') + QChar(0x221e) + QChar(' ') + "dB");
1663 sl->setOff(MusEGlobal::config.minSlider);
1664 sl->setPrecision(volSliderPrec);
1665 sl->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
1666 sl->setValue(track_vol);
1667 // sl->setEnableStyleHack(MusEGlobal::config.lineEditStyleHack);
1668
1669 // If smart focus is on redirect strip focus to slider label.
1670 //if(MusEGlobal::config.smartFocus)
1671 setFocusProxy(sl);
1672
1673 connect(sl, SIGNAL(valueChanged(double,int)), SLOT(volLabelChanged(double)));
1674 connect(slider, SIGNAL(valueChanged(double,int)), sl, SLOT(setValue(double)));
1675 connect(slider, SIGNAL(valueChanged(double,int,int)), SLOT(volumeChanged(double,int,int)));
1676 connect(slider, SIGNAL(sliderMoved(double,int,bool)), SLOT(volumeMoved(double,int,bool)));
1677 connect(slider, SIGNAL(sliderPressed(double, int)), SLOT(volumePressed(double,int)));
1678 connect(slider, SIGNAL(sliderReleased(double, int)), SLOT(volumeReleased(double,int)));
1679 connect(slider, SIGNAL(sliderRightClicked(QPoint,int)), SLOT(volumeRightClicked(QPoint)));
1680
1681 sliderGrid->addWidget(sl, 2, 0, 1, 2, Qt::AlignHCenter);
1682 // sliderGrid->setColumnStretch(0, slider->sizeHint().width());
1683 // sliderGrid->setColumnStretch(1, _meterLayout->sizeHint().width());
1684
1685 QHBoxLayout *sliderHLayout = new QHBoxLayout();
1686 sliderHLayout->setContentsMargins(0,0,0,0);
1687 sliderHLayout->setSpacing(0);
1688 sliderHLayout->addStretch();
1689 sliderHLayout->addLayout(sliderGrid);
1690 sliderHLayout->addStretch();
1691 sliderHLayout->setAlignment(Qt::AlignHCenter);
1692
1693 QFrame *sliderMeterFrame = new QFrame;
1694 sliderMeterFrame->setObjectName("SliderMeterFrameAudio");
1695 sliderMeterFrame->setLayout(sliderHLayout);
1696 sliderMeterFrame->setMinimumWidth(cMinStripWidth);
1697
1698 QHBoxLayout *sliderMeterLayout = new QHBoxLayout();
1699 sliderMeterLayout->setContentsMargins(1,2,1,2);
1700 sliderMeterLayout->addWidget(sliderMeterFrame);
1701 addGridLayout(sliderMeterLayout, _sliderMeterPos);
1702
1703 //---------------------------------------------------
1704 // pan, balance
1705 //---------------------------------------------------
1706
1707 _lowerRack = new AudioComponentRack(at, aStripLowerRack, false);
1708 // FIXME For some reason StyledPanel has trouble, intermittent sometimes panel is drawn, sometimes not.
1709 //_lowerRack->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
1710 _lowerRack->setFrameStyle(QFrame::Box | QFrame::Sunken);
1711 _lowerRack->setLineWidth(rackFrameWidth);
1712 _lowerRack->setMidLineWidth(0);
1713 // We do set a minimum height on this widget. Tested: Must be on fixed. Thankfully, it'll expand if more controls are added.
1714 _lowerRack->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
1715 _lowerRack->setContentsMargins(rackFrameWidth, rackFrameWidth, rackFrameWidth, rackFrameWidth);
1716 _lowerRack->setFocusPolicy(Qt::NoFocus);
1717
1718 addGridWidget(_lowerRack, _lowerRackPos);
1719
1720 _upperRack->setEnabled(!at->off());
1721 // _infoRack->setEnabled(!at->off());
1722 _lowerRack->setEnabled(!at->off());
1723
1724 //---------------------------------------------------
1725 // mute, solo, record
1726 //---------------------------------------------------
1727
1728 QGridLayout *bottomLayout = new QGridLayout;
1729 bottomLayout->setContentsMargins(1,1,1,2);
1730 bottomLayout->setSpacing(1);
1731
1732 if (track && track->canRecordMonitor()) {
1733 // _recMonitor = new IconButton(monitorOnSVGIcon, monitorOffSVGIcon, nullptr, nullptr, false, true);
1734 _recMonitor = new QPushButton;
1735 _recMonitor->setIcon(*monitorStateSVGIcon);
1736 _recMonitor->setFocusPolicy(Qt::NoFocus);
1737 _recMonitor->setCheckable(true);
1738 _recMonitor->setToolTip(tr("Input monitor"));
1739 _recMonitor->setWhatsThis(tr("Pass input through to output"));
1740 _recMonitor->setStatusTip(tr("Input monitor: Pass input through to output."));
1741 _recMonitor->setChecked(at->recMonitor());
1742 connect(_recMonitor, SIGNAL(toggled(bool)), SLOT(recMonitorToggled(bool)));
1743 bottomLayout->addWidget(_recMonitor, 0, 0, 1, 1);
1744 } else {
1745 QPushButton *recMonitorx = new QPushButton(this);
1746 recMonitorx->setIcon(*monitorOnSVGIcon);
1747 recMonitorx->setEnabled(false);
1748 bottomLayout->addWidget(recMonitorx, 0, 0, 1, 1);
1749 }
1750
1751 if (track->canRecord()) {
1752 // record = new IconButton(recArmOnSVGIcon, recArmOffSVGIcon, nullptr, nullptr, false, true);
1753 record = new QPushButton(this);
1754 if (type == MusECore::Track::AUDIO_OUTPUT)
1755 record->setIcon(*downmixStateSVGIcon);
1756 else
1757 record->setIcon(*recArmStateSVGIcon);
1758 record->setFocusPolicy(Qt::NoFocus);
1759 record->setCheckable(true);
1760 if (type == MusECore::Track::AUDIO_OUTPUT)
1761 record->setToolTip(tr("Record downmix to a file..."));
1762 else
1763 record->setToolTip(tr("Record arm"));
1764 record->setChecked(at->recordFlag());
1765 connect(record, SIGNAL(toggled(bool)), SLOT(recordToggled(bool)));
1766 bottomLayout->addWidget(record, 0, 1, 1, 1);
1767 } else {
1768 QPushButton *recordx = new QPushButton(this);
1769 recordx->setIcon(*recArmOnSVGIcon);
1770 recordx->setFocusPolicy(Qt::NoFocus);
1771 recordx->setEnabled(false);
1772 bottomLayout->addWidget(recordx, 0, 1, 1, 1);
1773 }
1774
1775 // mute = new IconButton(muteOnSVGIcon, muteOffSVGIcon, muteAndProxyOnSVGIcon, muteProxyOnSVGIcon, false, true);
1776 mute = new QPushButton(this);
1777 mute->setIcon(*muteStateSVGIcon);
1778 mute->setFocusPolicy(Qt::NoFocus);
1779 mute->setCheckable(true);
1780 mute->setToolTip(tr("Mute or proxy mute"));
1781 mute->setStatusTip(tr("Mute or proxy mute. Connected tracks are 'phantom' muted."));
1782 mute->setChecked(at->mute());
1783 updateMuteIcon();
1784 connect(mute, SIGNAL(toggled(bool)), SLOT(muteToggled(bool)));
1785 bottomLayout->addWidget(mute, 1, 0, 1, 1);
1786
1787 // solo = new IconButton(soloOnSVGIcon, soloOffSVGIcon, soloAndProxyOnSVGIcon, soloProxyOnSVGIcon, false, true);
1788 solo = new QPushButton(this);
1789 solo->setIcon(*soloStateSVGIcon);
1790 solo->setObjectName("SoloButton");
1791 solo->setToolTip(tr("Solo or proxy solo"));
1792 solo->setStatusTip(tr("Solo or proxy solo. Connected tracks are 'phantom' soloed. Press F1 for help."));
1793 solo->setFocusPolicy(Qt::NoFocus);
1794 solo->setCheckable(true);
1795 if (at->internalSolo())
1796 solo->setIcon(*soloAndProxyOnSVGIcon);
1797 // solo->setIconSetB(at->internalSolo());
1798 solo->setChecked(at->solo());
1799 connect(solo, SIGNAL(toggled(bool)), SLOT(soloToggled(bool)));
1800 bottomLayout->addWidget(solo, 1, 1, 1, 1);
1801
1802 // off = new IconButton(trackOffSVGIcon, trackOnSVGIcon, nullptr, nullptr, false, true);
1803 off = new QPushButton(this);
1804 off->setObjectName("TrackOffButton");
1805 off->setIcon(*trackOnSVGIcon);
1806 off->setFocusPolicy(Qt::NoFocus);
1807 off->setCheckable(true);
1808 off->setToolTip(tr("Track off"));
1809 off->setChecked(at->off());
1810 connect(off, SIGNAL(toggled(bool)), SLOT(offToggled(bool)));
1811 bottomLayout->addWidget(off, 3, 0, 1, 2);
1812
1813
1814 //---------------------------------------------------
1815 // automation type
1816 //---------------------------------------------------
1817
1818 autoType = new CompactComboBox();
1819 autoType->setObjectName("AudioAutoType");
1820 autoType->setContentsMargins(0, 0, 0, 0);
1821 autoType->setFocusPolicy(Qt::NoFocus);
1822 autoType->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
1823 //autoType->setAutoFillBackground(true);
1824
1825 autoType->addAction(tr("Auto off"), MusECore::AUTO_OFF);
1826 autoType->addAction(tr("Read"), MusECore::AUTO_READ);
1827 autoType->addAction(tr("Touch"), MusECore::AUTO_TOUCH);
1828 autoType->addAction(tr("Write"), MusECore::AUTO_WRITE);
1829 autoType->setCurrentItem(at->automationType());
1830
1831 autoType->ensurePolished();
1832 colorNameButton = autoType->palette().color(QPalette::Button).name();
1833 colorAutoType();
1834
1835 autoType->setToolTip(tr("Automation type"));
1836 autoType->setStatusTip(tr("Automation type: Off, Read, Touch or Write. Press F1 for help."));
1837 connect(autoType, SIGNAL(activated(int)), SLOT(setAutomationType(int)));
1838 bottomLayout->addWidget(autoType, 2, 0, 1, 2);
1839
1840 addGridLayout(bottomLayout, _bottomPos);
1841
1842 grid->setColumnStretch(2, 10);
1843
1844 off->blockSignals(true);
1845 updateOffState(); // init state
1846 off->blockSignals(false);
1847
1848
1849 // Now build the strip components.
1850 buildStrip();
1851 // Now set up all tabbing on the strip.
1852 // Don't bother if the strip is part of the mixer (not embedded),
1853 // the non-embedding parent (mixer) should set up all the tabs and make this call.
1854 if(isEmbedded)
1855 setupComponentTabbing();
1856
1857 connect(MusEGlobal::heartBeatTimer, SIGNAL(timeout()), SLOT(heartBeat()));
1858
1859 updateRouteButtons();
1860
1861 connect(_upperRack, SIGNAL(componentChanged(int,double,bool,int,int)), SLOT(componentChanged(int,double,bool,int,int)));
1862 connect(_upperRack, SIGNAL(componentMoved(int,double,int,bool)), SLOT(componentMoved(int,double,int,bool)));
1863 connect(_upperRack, SIGNAL(componentPressed(int,double,int)), SLOT(componentPressed(int,double,int)));
1864 connect(_upperRack, SIGNAL(componentReleased(int,double,int)), SLOT(componentReleased(int,double,int)));
1865
1866 // connect(_infoRack, SIGNAL(componentChanged(int,double,bool,int,int)), SLOT(componentChanged(int,double,bool,int,int)));
1867 // connect(_infoRack, SIGNAL(componentMoved(int,double,int,bool)), SLOT(componentMoved(int,double,int,bool)));
1868 // connect(_infoRack, SIGNAL(componentPressed(int,double,int)), SLOT(componentPressed(int,double,int)));
1869 // connect(_infoRack, SIGNAL(componentReleased(int,double,int)), SLOT(componentReleased(int,double,int)));
1870
1871 connect(_lowerRack, SIGNAL(componentChanged(int,double,bool,int,int)), SLOT(componentChanged(int,double,bool,int,int)));
1872 connect(_lowerRack, SIGNAL(componentMoved(int,double,int,bool)), SLOT(componentMoved(int,double,int,bool)));
1873 connect(_lowerRack, SIGNAL(componentPressed(int,double,int)), SLOT(componentPressed(int,double,int)));
1874 connect(_lowerRack, SIGNAL(componentReleased(int,double,int)), SLOT(componentReleased(int,double,int)));
1875 }
1876
1877
setStripStyle()1878 void AudioStrip::setStripStyle() {
1879 // Set the whole strip's font, except for the label.
1880 // May be good to keep this. In the midi strip without it the upper rack is too tall at first. So avoid trouble.
1881 setFont(MusEGlobal::config.fonts[1]);
1882 int iconSize = MusEGlobal::config.fonts[1].pointSize() * 2;
1883 setStyleSheet(MusECore::font2StyleSheetFull(MusEGlobal::config.fonts[1])
1884 + "#Strip > QAbstractButton { padding: 0px; qproperty-iconSize:" +
1885 QString::number(iconSize) + "px; }"
1886 + "#Strip #TrackOffButton { qproperty-iconSize:" + QString::number(iconSize - 2) + "px; }");
1887 }
1888
colorAutoType()1889 void AudioStrip::colorAutoType() {
1890
1891 if (track->automationType() == MusECore::AUTO_TOUCH || track->automationType() == MusECore::AUTO_WRITE)
1892 {
1893 autoType->setStyleSheet("QToolButton { background: rgb(150, 0, 0); }");
1894 }
1895 else if (track->automationType() == MusECore::AUTO_READ)
1896 {
1897 autoType->setStyleSheet("QToolButton { background: rgb(0, 100, 50); }");
1898 }
1899 else
1900 {
1901 autoType->setStyleSheet("QToolButton { background:" + colorNameButton + "; }");
1902 }
1903 }
1904
1905 //---------------------------------------------------
1906 // buildStrip
1907 // Destroy and rebuild strip components.
1908 //---------------------------------------------------
1909
buildStrip()1910 void AudioStrip::buildStrip()
1911 {
1912 // Destroys all components and clears the component list.
1913 // _infoRack->clearDelete();
1914 _upperRack->clearDelete();
1915 _lowerRack->clearDelete();
1916
1917 MusECore::AudioTrack* at = static_cast<MusECore::AudioTrack*>(track);
1918
1919 //---------------------------------------------------
1920 // Upper rack
1921 //---------------------------------------------------
1922
1923 // Gain...
1924 if(_preferKnobs)
1925 {
1926 CompactKnobComponentDescriptor gain_desc
1927 (
1928 ComponentRack::propertyComponent,
1929 "MixerStripAudioGain",
1930 AudioComponentRack::aStripGainProperty
1931 );
1932 _upperRack->newComponent(&gain_desc);
1933 }
1934 else
1935 {
1936 CompactSliderComponentDescriptor gain_desc
1937 (
1938 ComponentRack::propertyComponent,
1939 "MixerStripAudioGain",
1940 AudioComponentRack::aStripGainProperty
1941 );
1942 _upperRack->newComponent(&gain_desc);
1943 }
1944
1945 // Aux sends...
1946 int auxsSize = MusEGlobal::song->auxs()->size();
1947 if(at->hasAuxSend())
1948 {
1949 for (int idx = 0; idx < auxsSize; ++idx)
1950 {
1951 if(_preferKnobs)
1952 {
1953 CompactKnobComponentDescriptor aux_desc
1954 (
1955 AudioComponentRack::aStripAuxComponent,
1956 "MixerStripAudioAux",
1957 idx
1958 );
1959 _upperRack->newComponent(&aux_desc);
1960 }
1961 else
1962 {
1963 CompactSliderComponentDescriptor aux_desc
1964 (
1965 AudioComponentRack::aStripAuxComponent,
1966 "MixerStripAudioAux",
1967 idx
1968 );
1969 _upperRack->newComponent(&aux_desc);
1970 }
1971 }
1972 }
1973 else
1974 {
1975 ///if (auxsSize)
1976 //layout->addSpacing((STRIP_WIDTH/2 + 2) * auxsSize);
1977 ///grid->addSpacing((STRIP_WIDTH/2 + 2) * auxsSize); // ???
1978 }
1979
1980 // Keep this if dynamic layout (flip to right side) is desired.
1981 _upperRack->addStretch();
1982
1983 // noop
1984 updateRackSizes(true, false);
1985
1986 //---------------------------------------------------
1987 // Lower rack
1988 //---------------------------------------------------
1989
1990 // Pan...
1991 if(_preferKnobs)
1992 {
1993 CompactKnobComponentDescriptor pan_desc
1994 (
1995 ComponentRack::controllerComponent,
1996 "MixerStripAudioPan",
1997 MusECore::AC_PAN
1998 );
1999 _lowerRack->newComponent(&pan_desc);
2000 }
2001 else
2002 {
2003 CompactSliderComponentDescriptor pan_desc
2004 (
2005 ComponentRack::controllerComponent,
2006 "MixerStripAudioPan",
2007 MusECore::AC_PAN
2008 );
2009 _lowerRack->newComponent(&pan_desc);
2010 }
2011
2012 // Keep this if dynamic layout (flip to right side) is desired.
2013 _lowerRack->addStretch();
2014
2015 // noop
2016 updateRackSizes(false, true);
2017 }
2018
setupComponentTabbing(QWidget * previousWidget)2019 QWidget* AudioStrip::setupComponentTabbing(QWidget* previousWidget)
2020 {
2021 QWidget* prev = previousWidget;
2022 prev = _upperRack->setupComponentTabbing(prev);
2023 // prev = _infoRack->setupComponentTabbing(prev);
2024 if(sl)
2025 {
2026 if(prev)
2027 QWidget::setTabOrder(prev, sl);
2028 prev = sl;
2029 }
2030 prev = _lowerRack->setupComponentTabbing(prev);
2031 return prev;
2032 }
2033
setClipperTooltip(int ch)2034 void AudioStrip::setClipperTooltip(int ch)
2035 {
2036 QString clip_tt;
2037 switch(ch)
2038 {
2039 case 0:
2040 clip_tt = tr("L meter peak/clip");
2041 break;
2042 case 1:
2043 clip_tt = tr("R meter peak/clip");
2044 break;
2045 default:
2046 clip_tt = locale().toString(ch);
2047 break;
2048 }
2049 _clipperLabel[ch]->setToolTip(clip_tt);
2050 }
2051
2052 //---------------------------------------------------------
2053 // iRoutePressed
2054 //---------------------------------------------------------
2055
iRoutePressed()2056 void AudioStrip::iRoutePressed()
2057 {
2058 RoutePopupMenu* pup = new RoutePopupMenu(nullptr, false, _broadcastChanges);
2059 pup->exec(QCursor::pos(), track, false);
2060 delete pup;
2061 iR->setDown(false);
2062 }
2063
2064 //---------------------------------------------------------
2065 // oRoutePressed
2066 //---------------------------------------------------------
2067
oRoutePressed()2068 void AudioStrip::oRoutePressed()
2069 {
2070 RoutePopupMenu* pup = new RoutePopupMenu(nullptr, true, _broadcastChanges);
2071 pup->exec(QCursor::pos(), track, true);
2072 delete pup;
2073 oR->setDown(false);
2074 }
2075
incVolume(int increaseValue)2076 void AudioStrip::incVolume(int increaseValue)
2077 {
2078 if(!track || track->isMidiTrack())
2079 return;
2080
2081 const int id = MusECore::AC_VOLUME;
2082 MusECore::AudioTrack* at = static_cast<MusECore::AudioTrack*>(track);
2083
2084 // Get the slider's current value.
2085 const double prev_val = slider->value();
2086 // Increment the slider. Do not allow signalling.
2087 slider->blockSignals(true);
2088 slider->incValue(increaseValue);
2089 slider->blockSignals(false);
2090 // Now grab the control's new value.
2091 const double new_val = slider->value();
2092
2093 sl->blockSignals(true);
2094 sl->setValue(new_val);
2095 sl->blockSignals(false);
2096
2097 double d_new_val = new_val;
2098 if (d_new_val <= MusEGlobal::config.minSlider)
2099 d_new_val = 0.0;
2100 else
2101 d_new_val = muse_db2val(d_new_val);
2102 volume = d_new_val;
2103
2104 // Hack: Be sure to ignore in ScrDirect mode since we get both pressed AND changed signals.
2105 // ScrDirect mode is one-time only on press with modifier.
2106 // if(scrollMode != SliderBase::ScrDirect)
2107 at->recordAutomation(id, d_new_val);
2108 at->setParam(id, d_new_val); // Schedules a timed control change.
2109 at->enableController(id, false);
2110
2111 componentIncremented(ComponentRack::controllerComponent,
2112 prev_val, new_val,
2113 false, id, Slider::ScrNone);
2114 }
2115
incPan(int increaseValue)2116 void AudioStrip::incPan(int increaseValue)
2117 {
2118 if(!track || track->isMidiTrack())
2119 return;
2120
2121 const int id = MusECore::AC_PAN;
2122 MusECore::AudioTrack* at = static_cast<MusECore::AudioTrack*>(track);
2123
2124 ComponentRack* rack = nullptr;
2125 ComponentWidget* cw = nullptr;
2126 // Be sure to search all racks. Even if pan is in multiple racks, only one hit is
2127 // needed since after the value is set, the other pan controls will be updated too.
2128 if((cw = _upperRack->findComponent(ComponentRack::controllerComponent, -1, id)))
2129 rack = _upperRack;
2130 // else if((cw = _infoRack->findComponent(ComponentRack::controllerComponent, -1, id)))
2131 // rack = _infoRack;
2132 else if((cw = _lowerRack->findComponent(ComponentRack::controllerComponent, -1, id)))
2133 rack = _lowerRack;
2134
2135 if(!cw || !rack)
2136 return;
2137
2138 // Get the component's current value.
2139 const double prev_val = rack->componentValue(*cw);
2140 // Now increment the component. Do not allow signalling.
2141 rack->incComponentValue(*cw, increaseValue, true);
2142 // Now grab its value.
2143 const double d_new_val = rack->componentValue(*cw);
2144
2145 // Hack: Be sure to ignore in ScrDirect mode since we get both pressed AND changed signals.
2146 // ScrDirect mode is one-time only on press with modifier.
2147 // if(scrollMode != SliderBase::ScrDirect)
2148 at->recordAutomation(id, d_new_val);
2149 at->setParam(id, d_new_val); // Schedules a timed control change.
2150 at->enableController(id, false);
2151
2152 componentIncremented(ComponentRack::controllerComponent,
2153 prev_val, d_new_val,
2154 false, id, Slider::ScrNone);
2155 }
2156
2157 } // namespace MusEGui
2158