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