1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //  $Id: mstrip.cpp,v 1.9.2.13 2009/11/14 03:37:48 terminator356 Exp $
5 //
6 //  (C) Copyright 2000-2004 Werner Schweer (ws@seh.de)
7 //  (C) Copyright 2011 - 2017 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 <QLayout>
26 #include <QAction>
27 #include <QApplication>
28 #include <QComboBox>
29 #include <QToolTip>
30 #include <QTimer>
31 #include <QCursor>
32 #include <QGridLayout>
33 #include <QVBoxLayout>
34 #include <QPushButton>
35 
36 #include "app.h"
37 #include "midi_consts.h"
38 #include "midictrl.h"
39 #include "ctrl.h"
40 #include "mstrip.h"
41 #include "midiport.h"
42 #include "globals.h"
43 #include "audio.h"
44 #include "song.h"
45 #include "slider.h"
46 #include "knob.h"
47 #include "combobox.h"
48 #include "track.h"
49 #include "doublelabel.h"
50 #include "rack.h"
51 #include "amixer.h"
52 #include "icons.h"
53 #include "gconfig.h"
54 #include "pixmap_button.h"
55 #include "popupmenu.h"
56 #include "routepopup.h"
57 
58 #include "minstrument.h"
59 #include "midievent.h"
60 #include "compact_knob.h"
61 #include "compact_slider.h"
62 #include "compact_patch_edit.h"
63 #include "lcd_widgets.h"
64 #include "elided_label.h"
65 #include "utils.h"
66 #include "muse_math.h"
67 #include "operations.h"
68 
69 #include "synth.h"
70 #ifdef LV2_SUPPORT
71 #include "lv2host.h"
72 #endif
73 
74 // For debugging output: Uncomment the fprintf section.
75 #define DEBUG_MIDI_STRIP(dev, format, args...) // fprintf(dev, format, ##args);
76 
77 namespace MusEGui {
78 
79 const double MidiStrip::volSliderStepLin =  1.0;
80 
81 const double MidiStrip::volSliderStepDb =  0.5;
82 const double MidiStrip::volSliderMaxDb  =  0.0;
83 const int    MidiStrip::volSliderPrecDb =    1;
84 
85 const int MidiStrip::xMarginHorSlider = 1;
86 const int MidiStrip::yMarginHorSlider = 1;
87 const int MidiStrip::upperRackSpacerHeight = 2;
88 const int MidiStrip::rackFrameWidth = 1;
89 
90 //---------------------------------------------------------
91 //   MidiComponentRack
92 //---------------------------------------------------------
93 
MidiComponentRack(MusECore::MidiTrack * track,int id,QWidget * parent,Qt::WindowFlags f)94 MidiComponentRack::MidiComponentRack(MusECore::MidiTrack* track, int id, QWidget* parent, Qt::WindowFlags f)
95   : ComponentRack(id, parent, f), _track(track)
96 {
97 
98 }
99 
newComponent(ComponentDescriptor * desc,const ComponentWidget & before)100 void MidiComponentRack::newComponent( ComponentDescriptor* desc, const ComponentWidget& before )
101 {
102   int min = 0;
103   int max = 0;
104   int val = 0;
105   bool hasOffMode = false;
106   bool off = false;
107   bool showval = MusEGlobal::config.showControlValues;
108 
109   switch(desc->_componentType)
110   {
111     case controllerComponent:
112     {
113       const int midiCtrlNum = desc->_index;
114       const int chan  = _track->outChannel();
115       const int port  = _track->outPort();
116       if(chan < 0 || chan >= MusECore::MUSE_MIDI_CHANNELS || port < 0 || port >= MusECore::MIDI_PORTS)
117         return;
118       MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
119       MusECore::MidiController* mc = mp->midiController(midiCtrlNum, chan); // Auto-create the controller if necessary.
120       if(!mc)
121         return;
122       min = mc->minVal();
123       max = mc->maxVal();
124 
125       if(midiCtrlNum == MusECore::CTRL_PROGRAM)
126       {
127         val = mp->hwCtrlState(chan, midiCtrlNum);
128         if(val == MusECore::CTRL_VAL_UNKNOWN)
129         {
130           int lastv = mp->lastValidHWCtrlState(chan, midiCtrlNum);
131           if(lastv == MusECore::CTRL_VAL_UNKNOWN)
132           {
133             if(mc->initVal() == MusECore::CTRL_VAL_UNKNOWN)
134               val = 0;
135             else
136               val = mc->initVal();
137           }
138           off = true;
139         }
140       }
141       else
142       {
143         hasOffMode = true;
144         val = mp->hwCtrlState(chan, midiCtrlNum);
145         if(val == MusECore::CTRL_VAL_UNKNOWN)
146         {
147           int lastv = mp->lastValidHWCtrlState(chan, midiCtrlNum);
148           if(lastv == MusECore::CTRL_VAL_UNKNOWN)
149           {
150             if(mc->initVal() == MusECore::CTRL_VAL_UNKNOWN)
151               val = 0;
152             else
153               val = mc->initVal();
154           }
155           else
156             val = lastv - mc->bias();
157           off = true;
158         }
159         else
160         {
161           // Auto bias...
162           val -= mc->bias();
163         }
164       }
165 
166       if(desc->_label.isEmpty())
167       {
168         QString ctlname = mc->name();
169         if(ctlname.isEmpty())
170         {
171           switch(midiCtrlNum)
172           {
173             case MusECore::CTRL_PROGRAM:
174               ctlname = tr("Pro");
175             break;
176 
177             case MusECore::CTRL_VARIATION_SEND:
178               ctlname = tr("Var");
179             break;
180 
181             case MusECore::CTRL_REVERB_SEND:
182               ctlname = tr("Rev");
183             break;
184 
185             case MusECore::CTRL_CHORUS_SEND:
186               ctlname = tr("Cho");
187             break;
188 
189             case MusECore::CTRL_PANPOT:
190               ctlname = tr("Pan");
191             break;
192 
193             default:
194               ctlname = QString("#%1").arg(midiCtrlNum);
195             break;
196           }
197         }
198         desc->_label = ctlname;
199       }
200 
201       if(desc->_toolTipText.isEmpty())
202       {
203         QString ctlname = mc->name();
204         if(ctlname.isEmpty())
205         {
206           switch(midiCtrlNum)
207           {
208             case MusECore::CTRL_PROGRAM:
209               ctlname = tr("Program");
210             break;
211 
212             case MusECore::CTRL_VARIATION_SEND:
213               ctlname = tr("VariationSend");
214             break;
215 
216             case MusECore::CTRL_REVERB_SEND:
217               ctlname = tr("ReverbSend");
218             break;
219 
220             case MusECore::CTRL_CHORUS_SEND:
221               ctlname = tr("ChorusSend");
222             break;
223 
224             case MusECore::CTRL_PANPOT:
225               ctlname = tr("Pan/Balance");
226             break;
227 
228             default:
229               ctlname = tr("Controller");
230             break;
231           }
232         }
233         desc->_toolTipText = QString("%1 (# %2)\n%3").arg(ctlname).arg(midiCtrlNum).arg(tr("(Ctrl-double-click on/off)"));
234       }
235 
236       if(!desc->_color.isValid())
237       {
238         switch(midiCtrlNum)
239         {
240           case MusECore::CTRL_PANPOT:
241             desc->_color = MusEGlobal::config.panSliderColor;
242           break;
243 
244           case MusECore::CTRL_PROGRAM:
245             desc->_color = MusEGlobal::config.midiPatchReadoutColor;
246           break;
247 
248           default:
249             desc->_color = MusEGlobal::config.midiControllerSliderColor;
250           break;
251        }
252       }
253     }
254     break;
255 
256     case propertyComponent:
257     {
258       switch(desc->_index)
259       {
260         case mStripInstrumentProperty:
261         {
262           const int port = _track->outPort();
263           if(port >= 0 && port < MusECore::MIDI_PORTS)
264           {
265             if(MusECore::MidiInstrument* minstr = MusEGlobal::midiPorts[_track->outPort()].instrument())
266             {
267               //desc->_enabled = !minstr->isSynti();
268               if(desc->_label.isEmpty())
269                 desc->_label = minstr->iname();
270             }
271             else
272             {
273               desc->_enabled = false;
274               if(desc->_label.isEmpty())
275                 desc->_label = tr("<unknown>");
276             }
277           }
278           if(desc->_toolTipText.isEmpty())
279             desc->_toolTipText = tr("Instrument");
280         }
281         break;
282 
283         case mStripTranspProperty:
284         {
285           val = _track->transposition;
286           min = -127;
287           max = 127;
288           if(desc->_label.isEmpty())
289             desc->_label = tr("Transpose");
290           if(desc->_toolTipText.isEmpty())
291             desc->_toolTipText = tr("Transpose notes up or down");
292           if(!desc->_color.isValid())
293             desc->_color = MusEGlobal::config.midiPropertySliderColor;
294         }
295         break;
296 
297         case mStripDelayProperty:
298         {
299           val = _track->delay;
300           min = -1000;
301           max = 1000;
302           if(desc->_label.isEmpty())
303             desc->_label = tr("Delay");
304           if(desc->_toolTipText.isEmpty())
305             desc->_toolTipText = tr("Offset playback of notes before or after actual note");
306           if(!desc->_color.isValid())
307             desc->_color = MusEGlobal::config.midiPropertySliderColor;
308         }
309         break;
310 
311         case mStripLenProperty:
312         {
313           val = _track->len;
314           min = 25;
315           max = 200;
316           if(desc->_label.isEmpty())
317             desc->_label = tr("Length");
318           if(desc->_toolTipText.isEmpty())
319             desc->_toolTipText = tr("Change note length in percent of actual length");
320           if(!desc->_color.isValid())
321             desc->_color = MusEGlobal::config.midiPropertySliderColor;
322         }
323         break;
324 
325         case mStripVeloProperty:
326         {
327           val = _track->velocity;
328           min = -127;
329           max = 127;
330           if(desc->_label.isEmpty())
331             desc->_label = tr("Velocity");
332           if(desc->_toolTipText.isEmpty())
333             desc->_toolTipText = tr("<html><head/><body><p>Add or substract velocity to notes"
334                                      " on track.</p><p><span style="" font-style:italic;"">Since"
335                                      " the midi note range is 0-127 this <br/>might mean that the"
336                                      " notes do not reach <br/>the combined velocity, note + "
337                                      " Velocity.</span></p></body></html>");
338           if(!desc->_color.isValid())
339             desc->_color = MusEGlobal::config.midiPropertySliderColor;
340         }
341         break;
342 
343         case mStripComprProperty:
344         {
345           val = _track->compression;
346           min = 25;
347           max = 200;
348           if(desc->_label.isEmpty())
349             desc->_label = tr("Compress");
350           if(desc->_toolTipText.isEmpty())
351             desc->_toolTipText = tr("Compress the notes velocity range, in percent of actual velocity");
352           if(!desc->_color.isValid())
353             desc->_color = MusEGlobal::config.midiPropertySliderColor;
354         }
355         break;
356 
357       }
358     }
359     break;
360   }
361 
362   switch(desc->_widgetType)
363   {
364     case ElidedLabelComponentWidget:
365     {
366       ElidedLabelComponentDescriptor* d = static_cast<ElidedLabelComponentDescriptor*>(desc);
367 
368       d->_color = MusEGlobal::config.midiInstrumentBorderColor;
369       d->_bgColor = MusEGlobal::config.midiInstrumentBackgroundColor;
370       d->_bgActiveColor = MusEGlobal::config.midiInstrumentBgActiveColor;
371       d->_fontColor = MusEGlobal::config.midiInstrumentFontColor;
372       d->_fontActiveColor = MusEGlobal::config.midiInstrumentFontActiveColor;
373 
374       // Adds a component. Creates a new component using the given desc values if the desc widget is not given.
375       // Connects known widget types' signals to slots.
376       newComponentWidget(d, before);
377     }
378     break;
379 
380     case CompactKnobComponentWidget:
381     {
382       CompactKnobComponentDescriptor* d = static_cast<CompactKnobComponentDescriptor*>(desc);
383       d->_min = min;
384       d->_max = max;
385       d->_precision = 0;
386       d->_step = 1.0;
387       d->_initVal = val;
388       d->_hasOffMode = hasOffMode;
389       d->_isOff = off;
390       d->_showValue = showval;
391       if(!d->_color.isValid())
392         d->_color = MusEGlobal::config.sliderBackgroundColor;
393 
394       // Adds a component. Creates a new component using the given desc values if the desc widget is not given.
395       // Connects known widget types' signals to slots.
396       newComponentWidget(d, before);
397     }
398     break;
399 
400     case CompactSliderComponentWidget:
401     {
402       CompactSliderComponentDescriptor* d = static_cast<CompactSliderComponentDescriptor*>(desc);
403       d->_min = min;
404       d->_max = max;
405       d->_precision = 0;
406       d->_step = 1.0;
407       d->_initVal = val;
408       d->_hasOffMode = hasOffMode;
409       d->_isOff = off;
410       d->_showValue = showval;
411 
412       if(!d->_color.isValid()) // wrong color, but hopefully set before...
413           d->_color = MusEGlobal::config.sliderBackgroundColor;
414       if(!d->_barColor.isValid())
415         d->_barColor = MusEGlobal::config.sliderBarColor;
416       if(!d->_slotColor.isValid())
417           d->_slotColor = MusEGlobal::config.sliderBackgroundColor;
418 
419       // Adds a component. Creates a new component using the given desc values if the desc widget is not given.
420       // Connects known widget types' signals to slots.
421       newComponentWidget(d, before);
422     }
423     break;
424 
425     case mStripCompactPatchEditComponentWidget:
426     {
427       CompactPatchEditComponentDescriptor* d = static_cast<CompactPatchEditComponentDescriptor*>(desc);
428       d->_initVal = val;
429       d->_isOff = off;
430       if(!d->_color.isValid())
431         d->_color = MusEGlobal::config.midiPatchReadoutColor;
432 
433       // Adds a component. Creates a new component using the given desc values if the desc widget is not given.
434       // Connects known widget types' signals to slots.
435       newComponentWidget(d, before);
436     }
437     break;
438   }
439 }
440 
newComponentWidget(ComponentDescriptor * desc,const ComponentWidget & before)441 void MidiComponentRack::newComponentWidget( ComponentDescriptor* desc, const ComponentWidget& before )
442 {
443   switch(desc->_widgetType)
444   {
445     case mStripCompactPatchEditComponentWidget:
446     {
447       CompactPatchEditComponentDescriptor* d = static_cast<CompactPatchEditComponentDescriptor*>(desc);
448       if(!d->_compactPatchEdit)
449       {
450         CompactPatchEdit* control = new CompactPatchEdit(nullptr,
451                                                          d->_objName,
452                                                          CompactSlider::None);
453         d->_compactPatchEdit = control;
454         control->setId(d->_index);
455         control->setValue(d->_initVal);
456         // Don't allow anything here, it interferes with the CompactPatchEdit which sets it's own controls' tooltips.
457         //control->setToolTip(d->_toolTipText);
458         control->setEnabled(d->_enabled);
459         control->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
460         control->setContentsMargins(0, 0, 0, 0);
461 
462         if(d->_color.isValid())
463           control->setReadoutColor(d->_color);
464 
465         control->setBgColor(MusEGlobal::config.midiInstrumentBackgroundColor);
466         control->setBgActiveColor(MusEGlobal::config.midiInstrumentBgActiveColor);
467         control->setBorderColor(MusEGlobal::config.midiInstrumentBorderColor);
468 //        control->setBorderColorPatchEdit(MusEGlobal::config.midiInstrumentBgActiveColor);
469         control->setFontColor(MusEGlobal::config.midiInstrumentFontColor);
470         control->setFontActiveColor(MusEGlobal::config.midiInstrumentFontActiveColor);
471 
472         control->setMaxAliasedPointSize(MusEGlobal::config.maxAliasedPointSize);
473 
474         connect(d->_compactPatchEdit, SIGNAL(valueChanged(int,int)), SLOT(controllerChanged(int,int)));
475         connect(d->_compactPatchEdit, SIGNAL(patchValueRightClicked(QPoint,int)), SLOT(controllerRightClicked(QPoint,int)));
476         connect(d->_compactPatchEdit, SIGNAL(patchNameClicked(QPoint,int)), SLOT(patchEditNameClicked(QPoint,int)));
477         connect(d->_compactPatchEdit, SIGNAL(patchNameRightClicked(QPoint,int)), SLOT(controllerRightClicked(QPoint,int)));
478       }
479 
480       ComponentWidget cw = ComponentWidget(
481                             d->_compactPatchEdit,
482                             d->_widgetType,
483                             d->_componentType,
484                             d->_index
485                           );
486 
487       addComponentWidget(cw, before);
488       return;
489     }
490     break;
491   }
492 
493   // If not handled above, let ancestor handle it.
494   ComponentRack::newComponentWidget(desc, before);
495 }
496 
scanControllerComponents()497 void MidiComponentRack::scanControllerComponents()
498 {
499   const int chan  = _track->outChannel();
500   const int port  = _track->outPort();
501   if(chan < 0 || chan >= MusECore::MUSE_MIDI_CHANNELS || port < 0 || port >= MusECore::MIDI_PORTS)
502     return;
503 
504   QString namestr;
505   std::vector<iComponentWidget> to_be_erased;
506   for(iComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
507   {
508     ComponentWidget& cw = *ic;
509     if(!cw._widget)
510       continue;
511 
512     switch(cw._componentType)
513     {
514       case controllerComponent:
515       {
516         MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
517         MusECore::MidiCtrlValListList* mcvll = mp->controller();
518         MusECore::ciMidiCtrlValList imcvll = mcvll->find(chan, cw._index);
519         if(imcvll == mcvll->end())
520           to_be_erased.push_back(ic);
521         else
522         {
523           // While we are here, let's update the name of the control, in case the instrument changed.
524           switch(cw._widgetType)
525           {
526             case CompactKnobComponentWidget:
527             case CompactSliderComponentWidget:
528             {
529               // false = do not create the controller if not found.
530               MusECore::MidiController* mc = mp->midiController(cw._index, chan, false);
531               if(mc)
532                 setComponentText(cw, mc->name());
533             }
534             break;
535           }
536         }
537       }
538       break;
539     }
540   }
541   for(std::vector<iComponentWidget>::iterator i = to_be_erased.begin(); i != to_be_erased.end(); ++i)
542   {
543     iComponentWidget icw = *i;
544     ComponentWidget& cw = *icw;
545     DEBUG_MIDI_STRIP(stderr, "MidiComponentRack::scanControllerComponents: deleting controller component index:%d\n", cw._index);
546     if(cw._widget)
547       cw._widget->deleteLater();
548     _components.erase(icw);
549   }
550 }
551 
updateComponents()552 void MidiComponentRack::updateComponents()
553 {
554   for(iComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
555   {
556     ComponentWidget& cw = *ic;
557     if(!cw._widget)
558       continue;
559 
560     switch(cw._componentType)
561     {
562       case controllerComponent:
563       {
564         // Inhibit the controller stream if control is currently pressed.
565         // Note _pressed operates differently than simply checking if the control is pressed!
566         if(cw._pressed)
567           continue;
568 
569         const int channel  = _track->outChannel();
570         const int port  = _track->outPort();
571         if(channel < 0 || channel >= MusECore::MUSE_MIDI_CHANNELS || port < 0 || port >= MusECore::MIDI_PORTS)
572           continue;
573 
574         MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
575         MusECore::MidiCtrlValListList* mcvll = mp->controller();
576 
577         MusECore::ciMidiCtrlValList imcvl = mcvll->find(channel, cw._index);
578         const bool enable = imcvl != mcvll->end() && !_track->off();
579         if(cw._widget->isEnabled() != enable)
580           cw._widget->setEnabled(enable);
581 
582         if(enable)
583         {
584           MusECore::MidiCtrlValList* mcvl = imcvl->second;
585           switch(cw._index)
586           {
587             case MusECore::CTRL_PROGRAM:
588             {
589               switch(cw._widgetType)
590               {
591                 case mStripCompactPatchEditComponentWidget:
592                 {
593                   // Special for new LCD patch edit control: Need to give both current and last values.
594                   // Keeping a local last value with the control won't work.
595                   CompactPatchEdit* control = static_cast<CompactPatchEdit*>(cw._widget);
596                   const int hwVal = mcvl->hwVal();
597                   control->blockSignals(true);
598                   control->setLastValidValue(mcvl->lastValidHWVal());
599                   control->setLastValidBytes(mcvl->lastValidByte2(), mcvl->lastValidByte1(), mcvl->lastValidByte0());
600                   control->setValue(hwVal);
601                   control->blockSignals(false);
602 
603                   if(hwVal == MusECore::CTRL_VAL_UNKNOWN)
604                   {
605                     control->setPatchNameOff(true);
606                     const QString patchName(tr("<Patch>"));
607                     if(control->patchName() != patchName)
608                       control->setPatchName(patchName);
609                   }
610                   else
611                   {
612                     // Try to avoid calling MidiInstrument::getPatchName too often.
613 //                     if(_heartBeatCounter == 0)
614                     {
615                       control->setPatchNameOff(false);
616                       MusECore::MidiInstrument* instr = mp->instrument();
617                       QString patchName(instr->getPatchName(channel, hwVal, _track->isDrumTrack(), true)); // Include default.
618                       if(patchName.isEmpty())
619                         patchName = QString("???");
620                       if(control->patchName() != patchName)
621                         control->setPatchName(patchName);
622                     }
623                   }
624                 }
625                 break;
626               }
627             }
628             break;
629 
630             default:
631             {
632               switch(cw._widgetType)
633               {
634                 case CompactKnobComponentWidget:
635                 {
636                   CompactKnob* control = static_cast<CompactKnob*>(cw._widget);
637 
638                   int hwVal = mcvl->hwVal();
639                   int min = 0;
640                   int max = 127;
641                   int bias = 0;
642                   int initval = 0;
643                   MusECore::MidiController* mc = mp->midiController(cw._index, channel, false);
644                   if(mc)
645                   {
646                     bias = mc->bias();
647                     min = mc->minVal();
648                     max = mc->maxVal();
649                     initval = mc->initVal();
650                     if(initval == MusECore::CTRL_VAL_UNKNOWN)
651                       initval = 0;
652                   }
653 
654                   const double dmin = (double)min;
655                   const double dmax = (double)max;
656                   const double c_dmin = control->minValue();
657                   const double c_dmax = control->maxValue();
658                   if(c_dmin != min && c_dmax != max)
659                   {
660                     control->blockSignals(true);
661                     control->setRange(dmin, dmax, 1.0);
662                     control->blockSignals(false);
663                   }
664                   else if(c_dmin != min)
665                   {
666                     control->blockSignals(true);
667                     control->setMinValue(min);
668                     control->blockSignals(false);
669                   }
670                   else if(c_dmax != max)
671                   {
672                     control->blockSignals(true);
673                     control->setMaxValue(max);
674                     control->blockSignals(false);
675                   }
676 
677                   if(hwVal == MusECore::CTRL_VAL_UNKNOWN)
678                   {
679                     hwVal = mcvl->lastValidHWVal();
680                     if(hwVal == MusECore::CTRL_VAL_UNKNOWN)
681                     {
682                       hwVal = initval;
683                       if(!control->isOff() || hwVal != control->value())
684                       {
685                         control->blockSignals(true);
686                         control->setValueState(hwVal, true);
687                         control->blockSignals(false);
688                       }
689                     }
690                     else
691                     {
692                       hwVal -= bias;
693                       if(!control->isOff() || hwVal != control->value())
694                       {
695                         control->blockSignals(true);
696                         control->setValueState(hwVal, true);
697                         control->blockSignals(false);
698                       }
699                     }
700                   }
701                   else
702                   {
703                     hwVal -= bias;
704                     if(control->isOff() || hwVal != control->value())
705                     {
706                       control->blockSignals(true);
707                       control->setValueState(hwVal, false);
708                       control->blockSignals(false);
709                     }
710                   }
711                 }
712                 break;
713 
714                 case CompactSliderComponentWidget:
715                 {
716                   CompactSlider* control = static_cast<CompactSlider*>(cw._widget);
717 
718                   int hwVal = mcvl->hwVal();
719                   int min = 0;
720                   int max = 127;
721                   int bias = 0;
722                   int initval = 0;
723                   MusECore::MidiController* mc = mp->midiController(cw._index, channel, false);
724                   if(mc)
725                   {
726                     bias = mc->bias();
727                     min = mc->minVal();
728                     max = mc->maxVal();
729                     initval = mc->initVal();
730                     if(initval == MusECore::CTRL_VAL_UNKNOWN)
731                       initval = 0;
732                   }
733 
734                   const double dmin = (double)min;
735                   const double dmax = (double)max;
736                   const double c_dmin = control->minValue();
737                   const double c_dmax = control->maxValue();
738                   if(c_dmin != min && c_dmax != max)
739                   {
740                     control->blockSignals(true);
741                     control->setRange(dmin, dmax, 1.0);
742                     control->blockSignals(false);
743                   }
744                   else if(c_dmin != min)
745                   {
746                     control->blockSignals(true);
747                     control->setMinValue(min);
748                     control->blockSignals(false);
749                   }
750                   else if(c_dmax != max)
751                   {
752                     control->blockSignals(true);
753                     control->setMaxValue(max);
754                     control->blockSignals(false);
755                   }
756 
757                   if(hwVal == MusECore::CTRL_VAL_UNKNOWN)
758                   {
759                     hwVal = mcvl->lastValidHWVal();
760                     if(hwVal == MusECore::CTRL_VAL_UNKNOWN)
761                     {
762                       hwVal = initval;
763                       if(!control->isOff() || hwVal != control->value())
764                       {
765                         control->blockSignals(true);
766                         control->setValueState(hwVal, true);
767                         control->blockSignals(false);
768                       }
769                     }
770                     else
771                     {
772                       hwVal -= bias;
773                       if(!control->isOff() || hwVal != control->value())
774                       {
775                         control->blockSignals(true);
776                         control->setValueState(hwVal, true);
777                         control->blockSignals(false);
778                       }
779                     }
780                   }
781                   else
782                   {
783                     hwVal -= bias;
784                     if(control->isOff() || hwVal != control->value())
785                     {
786                       control->blockSignals(true);
787                       control->setValueState(hwVal, false);
788                       control->blockSignals(false);
789                     }
790                   }
791                 }
792                 break;
793               }
794             }
795             break;
796           }
797         }
798       }
799       break;
800 
801       case propertyComponent:
802       {
803         switch(cw._index)
804         {
805           case mStripInstrumentProperty:
806           {
807             const int port = _track->outPort();
808             if(port >= 0 && port < MusECore::MIDI_PORTS)
809             {
810               if(MusECore::MidiInstrument* minstr = MusEGlobal::midiPorts[_track->outPort()].instrument())
811               {
812                 //setComponentEnabled(cw, !minstr->isSynti());
813                 setComponentText(cw, minstr->iname());
814               }
815               else
816               {
817                 setComponentEnabled(cw, false);
818                 setComponentText(cw, tr("<unknown>"));
819               }
820             }
821           }
822           break;
823 
824           case mStripTranspProperty:
825             setComponentValue(cw, _track->transposition);  // Signals blocked. Redundant ignored.
826           break;
827 
828           case mStripDelayProperty:
829             setComponentValue(cw, _track->delay);  // Signals blocked. Redundant ignored.
830           break;
831 
832           case mStripLenProperty:
833             setComponentValue(cw, _track->len);  // Signals blocked. Redundant ignored.
834           break;
835 
836           case mStripVeloProperty:
837             setComponentValue(cw, _track->velocity);  // Signals blocked. Redundant ignored.
838           break;
839 
840           case mStripComprProperty:
841             setComponentValue(cw, _track->compression);  // Signals blocked. Redundant ignored.
842           break;
843         }
844       }
845       break;
846     }
847   }
848 }
849 
850 //---------------------------------------------------------
851 //   instrPopup
852 //---------------------------------------------------------
853 
instrPopup(QPoint p)854 void MidiComponentRack::instrPopup(QPoint p)
855 {
856   const int port = _track->outPort();
857   if(port < 0 || port >= MusECore::MIDI_PORTS)
858     return;
859 
860   MusECore::MidiInstrument* instr = MusEGlobal::midiPorts[port].instrument();
861   //if(!instr)
862   //  return;
863 
864   PopupMenu* pup = new PopupMenu(false);
865 
866   //MusECore::MidiInstrument::populateInstrPopup(pup, port, false);
867   MusECore::MidiInstrument::populateInstrPopup(pup, port, true);
868 
869   if(pup->actions().count() == 0)
870   {
871     delete pup;
872     return;
873   }
874 
875   QAction *act = pup->exec(p);
876   if(!act)
877   {
878     delete pup;
879     return;
880   }
881 
882   const QString s = act->text();
883   const int actid = act->data().toInt();
884   delete pup;
885 
886   // Edit instrument
887   if(actid == 100)
888   {
889     MusEGlobal::muse->startEditInstrument(instr && !instr->isSynti() ? instr->iname() : QString());
890   }
891   else
892   {
893     for(MusECore::iMidiInstrument i = MusECore::midiInstruments.begin(); i != MusECore::midiInstruments.end(); ++i)
894     {
895       if((*i)->iname() == s)
896       {
897         MusEGlobal::audio->msgIdle(true); // Make it safe to edit structures
898         MusEGlobal::midiPorts[port].changeInstrument(*i);
899         MusEGlobal::audio->msgIdle(false);
900         // Make sure device initializations are sent if necessary.
901         MusEGlobal::audio->msgInitMidiDevices(false);  // false = Don't force
902         MusEGlobal::song->update(SC_MIDI_INSTRUMENT);
903         break;
904       }
905     }
906   }
907 }
908 
909 //---------------------------------------------------------
910 //   patchPopup
911 //---------------------------------------------------------
912 
patchPopup(QPoint p)913 void MidiComponentRack::patchPopup(QPoint p)
914 {
915   const int channel = _track->outChannel();
916   const int port    = _track->outPort();
917   if(channel < 0 || channel >= MusECore::MUSE_MIDI_CHANNELS || port < 0 || port >= MusECore::MIDI_PORTS)
918     return;
919 
920   MusECore::MidiInstrument* instr = MusEGlobal::midiPorts[port].instrument();
921   PopupMenu* pup = new PopupMenu(true);
922 
923   instr->populatePatchPopup(pup, channel, _track->isDrumTrack());
924 
925   if(pup->actions().count() == 0)
926   {
927     delete pup;
928     return;
929   }
930 
931   connect(pup, SIGNAL(triggered(QAction*)), SLOT(patchPopupActivated(QAction*)));
932 
933   pup->exec(p);
934   delete pup;
935 }
936 
937 //---------------------------------------------------------
938 //   patchPopupActivated
939 //---------------------------------------------------------
940 
patchPopupActivated(QAction * act)941 void MidiComponentRack::patchPopupActivated(QAction* act)
942 {
943   if(!act)
944     return;
945 
946   const int channel = _track->outChannel();
947   const int port    = _track->outPort();
948   if(channel < 0 || channel >= MusECore::MUSE_MIDI_CHANNELS || port < 0 || port >= MusECore::MIDI_PORTS)
949     return;
950 
951   MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
952   MusECore::MidiInstrument* instr = mp->instrument();
953   if(!instr)
954     return;
955 
956   if(act->data().type() == QVariant::Int || act->data().type() == QVariant::UInt)
957   {
958     bool ok;
959     int rv = act->data().toInt(&ok);
960     if(ok && rv != -1)
961     {
962         // If the chosen patch's number is don't care (0xffffff),
963         //  then by golly since we "don't care" let's just set it to '-/-/1'.
964         // 0xffffff cannot be a valid patch number... yet...
965         if(rv == MusECore::CTRL_PROGRAM_VAL_DONT_CARE)
966           rv = 0xffff00;
967         MusECore::MidiPlayEvent ev(MusEGlobal::audio->curFrame(), port, channel, MusECore::ME_CONTROLLER, MusECore::CTRL_PROGRAM, rv);
968         mp->putEvent(ev);
969     }
970   }
971   else if(instr->isSynti() && act->data().canConvert<void *>())
972   {
973 #ifdef LV2_SUPPORT
974     MusECore::SynthI *si = static_cast<MusECore::SynthI *>(instr);
975     MusECore::Synth *s = si->synth();
976     //only for lv2 synths call applyPreset function.
977     if(s && s->synthType() == MusECore::Synth::LV2_SYNTH)
978     {
979         MusECore::LV2SynthIF *sif = static_cast<MusECore::LV2SynthIF *>(si->sif());
980         //be pedantic about checks
981         if(sif)
982         {
983           if(mp)
984           {
985               if(mp->hwCtrlState(channel, MusECore::CTRL_PROGRAM) != MusECore::CTRL_VAL_UNKNOWN)
986                 mp->putHwCtrlEvent(MusECore::MidiPlayEvent(MusEGlobal::audio->curFrame(), port, channel,
987                                                            MusECore::ME_CONTROLLER,
988                                                            MusECore::CTRL_PROGRAM,
989                                                            MusECore::CTRL_VAL_UNKNOWN));
990               sif->applyPreset(act->data().value<void *>());
991           }
992         }
993     }
994 #endif
995   }
996 }
997 
controllerChanged(int v,int id)998 void MidiComponentRack::controllerChanged(int v, int id)
999 {
1000   DEBUG_MIDI_STRIP(stderr, "MidiComponentRack::controllerChanged id:%d val:%d\n", id, val);
1001 
1002 //   if (inHeartBeat)
1003 //         return;
1004   int val = v;
1005   int port     = _track->outPort();
1006   int channel  = _track->outChannel();
1007   if(channel < 0 || channel >= MusECore::MUSE_MIDI_CHANNELS || port < 0 || port >= MusECore::MIDI_PORTS)
1008   {
1009     emit componentChanged(controllerComponent, val, false, id, 0);
1010     return;
1011   }
1012 
1013   MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
1014 
1015   MusECore::MidiCtrlValListList* mcvll = mp->controller();
1016   MusECore::ciMidiCtrlValList imcvl = mcvll->find(channel, id);
1017   if(imcvl == mcvll->end())
1018   {
1019     emit componentChanged(controllerComponent, val, false, id, 0);
1020     return;
1021   }
1022 
1023   MusECore::MidiController* mc = mp->midiController(id, channel, false);
1024   if(mc)
1025   {
1026     int ival = val;
1027     //if(off || ival < mc->minVal() || ival > mc->maxVal())
1028     if(ival < mc->minVal() || ival > mc->maxVal())
1029       ival = MusECore::CTRL_VAL_UNKNOWN;
1030 
1031     if(ival != MusECore::CTRL_VAL_UNKNOWN)
1032       // Auto bias...
1033       ival += mc->bias();
1034 
1035     MusECore::MidiPlayEvent ev(MusEGlobal::audio->curFrame(), port, channel, MusECore::ME_CONTROLLER, id, ival);
1036     mp->putEvent(ev);
1037   }
1038 
1039   emit componentChanged(controllerComponent, v, false, id, 0);
1040 }
1041 
controllerChanged(double val,int id)1042 void MidiComponentRack::controllerChanged(double val, int id)
1043 {
1044   DEBUG_MIDI_STRIP(stderr, "MidiComponentRack::controllerChanged id:%d val:%.20f\n", id, val);
1045   controllerChanged(int(lrint(val)), id);
1046 }
1047 
controllerChanged(double val,bool off,int id,int scrollMode)1048 void MidiComponentRack::controllerChanged(double val, bool off, int id, int scrollMode)
1049 {
1050   DEBUG_MIDI_STRIP(stderr, "MidiComponentRack::controllerChanged id:%d val:%.20f scrollMode:%d\n", id, val, scrollMode);
1051 
1052   int port     = _track->outPort();
1053   int channel  = _track->outChannel();
1054   if(channel < 0 || channel >= MusECore::MUSE_MIDI_CHANNELS || port < 0 || port >= MusECore::MIDI_PORTS)
1055   {
1056     emit componentChanged(controllerComponent, val, off, id, scrollMode);
1057     return;
1058   }
1059 
1060   MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
1061 
1062   MusECore::MidiCtrlValListList* mcvll = mp->controller();
1063   MusECore::ciMidiCtrlValList imcvl = mcvll->find(channel, id);
1064   if(imcvl == mcvll->end())
1065   {
1066     emit componentChanged(controllerComponent, val, off, id, scrollMode);
1067     return;
1068   }
1069 
1070   MusECore::MidiController* mc = mp->midiController(id, channel, false);
1071   if(mc)
1072   {
1073     int ival = lrint(val);
1074     if(off || ival < mc->minVal() || ival > mc->maxVal())
1075       ival = MusECore::CTRL_VAL_UNKNOWN;
1076 
1077     if(ival != MusECore::CTRL_VAL_UNKNOWN)
1078       // Auto bias...
1079       ival += mc->bias();
1080 
1081     MusECore::MidiPlayEvent ev(MusEGlobal::audio->curFrame(), port, channel, MusECore::ME_CONTROLLER, id, ival);
1082     mp->putEvent(ev);
1083   }
1084 
1085   emit componentChanged(controllerComponent, val, off, id, scrollMode);
1086 }
1087 
controllerMoved(double val,int id,bool shift_pressed)1088 void MidiComponentRack::controllerMoved(double val, int id, bool shift_pressed)
1089 {
1090   DEBUG_MIDI_STRIP(stderr, "MidiComponentRack::controllerMoved id:%d val:%.20f\n", id, val);
1091   emit componentMoved(controllerComponent, val, id, shift_pressed);
1092 }
1093 
controllerPressed(double val,int id)1094 void MidiComponentRack::controllerPressed(double val, int id)
1095 {
1096   DEBUG_MIDI_STRIP(stderr, "MidiComponentRack::controllerPressed id:%d\n", id);
1097   emit componentPressed(controllerComponent, val, id);
1098 }
1099 
controllerReleased(double val,int id)1100 void MidiComponentRack::controllerReleased(double val, int id)
1101 {
1102   DEBUG_MIDI_STRIP(stderr, "MidiComponentRack::controllerReleased id:%d\n", id);
1103   emit componentReleased(controllerComponent, val, id);
1104 }
1105 
controllerRightClicked(QPoint p,int id)1106 void MidiComponentRack::controllerRightClicked(QPoint p, int id)
1107 {
1108   DEBUG_MIDI_STRIP(stderr, "MidiComponentRack::controllerRightClicked id:%d\n", id);
1109   MusEGlobal::song->execMidiAutomationCtlPopup(_track, 0, p, id); // Do not give a parent here, otherwise accelerators are returned in text() !
1110 }
1111 
1112 
propertyChanged(double val,bool off,int id,int scrollMode)1113 void MidiComponentRack::propertyChanged(double val, bool off, int id, int scrollMode)
1114 {
1115   DEBUG_MIDI_STRIP(stderr, "MidiComponentRack::propertyChanged id:%d val:%.20f\n", id, val);
1116 
1117   const int ival = lrint(val);
1118 
1119   // FIXME ! This direct setting is probably not safe. Use a FIFO buffer or something.
1120   //         A problem with using MidiPort::putEvent is that it does not appear to be safe
1121   //          when directly setting the hwValues.
1122   switch(id)
1123   {
1124     case mStripTranspProperty:
1125       _track->transposition = ival;
1126     break;
1127 
1128     case mStripDelayProperty:
1129       _track->delay = ival;
1130     break;
1131 
1132     case mStripLenProperty:
1133       _track->len = ival;
1134     break;
1135 
1136     case mStripVeloProperty:
1137       _track->velocity = ival;
1138     break;
1139 
1140     case mStripComprProperty:
1141       _track->compression = ival;
1142     break;
1143   }
1144 
1145   emit componentChanged(propertyComponent, val, off, id, scrollMode);
1146 }
1147 
propertyMoved(double val,int id,bool shift_pressed)1148 void MidiComponentRack::propertyMoved(double val, int id, bool shift_pressed)
1149 {
1150   DEBUG_MIDI_STRIP(stderr, "MidiComponentRack::propertyMoved id:%d val:%.20f\n", id, val);
1151   emit componentMoved(propertyComponent, val, id, shift_pressed);
1152 }
1153 
propertyPressed(double val,int id)1154 void MidiComponentRack::propertyPressed(double val, int id)
1155 {
1156   emit componentPressed(propertyComponent, val, id);
1157 }
1158 
propertyReleased(double val,int id)1159 void MidiComponentRack::propertyReleased(double val, int id)
1160 {
1161   emit componentReleased(propertyComponent, val, id);
1162 }
1163 
propertyRightClicked(QPoint,int)1164 void MidiComponentRack::propertyRightClicked(QPoint, int)
1165 {
1166 
1167 }
1168 
labelPropertyPressed(QPoint p,int id,Qt::MouseButtons,Qt::KeyboardModifiers keys)1169 void MidiComponentRack::labelPropertyPressed(QPoint p, int id, Qt::MouseButtons /*buttons*/, Qt::KeyboardModifiers keys)
1170 {
1171   labelPropertyPressHandler(p, id, keys);
1172 }
1173 
labelPropertyReleased(QPoint,int,Qt::MouseButtons,Qt::KeyboardModifiers)1174 void MidiComponentRack::labelPropertyReleased(QPoint /*p*/, int /*id*/, Qt::MouseButtons /*buttons*/, Qt::KeyboardModifiers /*keys*/)
1175 {
1176 
1177 }
1178 
labelPropertyReturnPressed(QPoint p,int id,Qt::KeyboardModifiers keys)1179 void MidiComponentRack::labelPropertyReturnPressed(QPoint p, int id, Qt::KeyboardModifiers keys)
1180 {
1181   labelPropertyPressHandler(p, id, keys);
1182 }
1183 
labelPropertyPressHandler(QPoint,int id,Qt::KeyboardModifiers)1184 void MidiComponentRack::labelPropertyPressHandler(QPoint /*p*/, int id, Qt::KeyboardModifiers /*keys*/)
1185 {
1186   switch(id)
1187   {
1188     case mStripInstrumentProperty:
1189     {
1190       ciComponentWidget icw = _components.find(propertyComponent, -1, id);
1191       if(icw == _components.end())
1192         return;
1193 
1194       const ComponentWidget& cw = *icw;
1195       if(!cw._widget)
1196         return;
1197 
1198       instrPopup(cw._widget->mapToGlobal(QPoint(10,5)));
1199     }
1200     break;
1201   }
1202 }
1203 
patchEditNameClicked(QPoint,int id)1204 void MidiComponentRack::patchEditNameClicked(QPoint /*p*/, int id)
1205 {
1206   ciComponentWidget icw = _components.find(controllerComponent, -1, id);
1207   if(icw == _components.end())
1208     return;
1209 
1210   const ComponentWidget& cw = *icw;
1211   if(!cw._widget)
1212     return;
1213 
1214   patchPopup(cw._widget->mapToGlobal(QPoint(10,5)));
1215 }
1216 
1217 
1218 //---------------------------------------------------------
1219 //   songChanged
1220 //---------------------------------------------------------
1221 
songChanged(MusECore::SongChangedStruct_t flags)1222 void MidiComponentRack::songChanged(MusECore::SongChangedStruct_t flags)
1223 {
1224   // Scan controllers.
1225   if(flags & (SC_RACK | SC_MIDI_CONTROLLER_ADD | SC_MIDI_INSTRUMENT))
1226   {
1227     scanControllerComponents();
1228   }
1229 }
1230 
1231 //---------------------------------------------------------
1232 //   configChanged
1233 //   Catch when label font, or configuration min slider and meter values change, or viewable tracks etc.
1234 //---------------------------------------------------------
1235 
configChanged()1236 void MidiComponentRack::configChanged()
1237 {
1238   // Handle font changes etc.
1239   ComponentRack::configChanged();
1240 
1241   for(ciComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
1242   {
1243     const ComponentWidget& cw = *ic;
1244     if(!cw._widget)
1245       continue;
1246 
1247     // Whether to show values along with labels for certain controls.
1248     setComponentShowValue(cw, MusEGlobal::config.showControlValues);
1249 
1250     switch(cw._widgetType)
1251     {
1252       case mStripCompactPatchEditComponentWidget:
1253       {
1254         //CompactPatchEdit* w = static_cast<CompactPatchEdit*>(cw._widget);
1255         //w->setMaxAliasedPointSize(MusEGlobal::config.maxAliasedPointSize);
1256       }
1257       break;
1258 
1259       case CompactKnobComponentWidget:
1260       {
1261         //CompactKnob* w = static_cast<CompactKnob*>(cw._widget);
1262         //w->setMaxAliasedPointSize(MusEGlobal::config.maxAliasedPointSize);
1263       }
1264       break;
1265     }
1266   }
1267   setComponentColors();
1268 }
1269 
1270 //---------------------------------------------------------
1271 //   setComponentColors
1272 //---------------------------------------------------------
1273 
setComponentColors()1274 void MidiComponentRack::setComponentColors()
1275 {
1276   for(ciComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
1277   {
1278     const ComponentWidget& cw = *ic;
1279     if(!cw._widget)
1280       continue;
1281 
1282     QColor color = MusEGlobal::config.sliderBackgroundColor;
1283     switch(cw._componentType)
1284     {
1285       case controllerComponent:
1286       {
1287         switch(cw._index)
1288         {
1289           case MusECore::CTRL_PANPOT:
1290             color = MusEGlobal::config.panSliderColor;
1291           break;
1292 
1293           case MusECore::CTRL_PROGRAM:
1294             color = MusEGlobal::config.midiPatchReadoutColor;
1295           break;
1296 
1297           default:
1298             color = MusEGlobal::config.midiControllerSliderColor;
1299           break;
1300         }
1301       }
1302       break;
1303 
1304       case propertyComponent:
1305       {
1306         switch(cw._index)
1307         {
1308           case mStripInstrumentProperty:
1309           break;
1310 
1311           case mStripTranspProperty:
1312           case mStripDelayProperty:
1313           case mStripLenProperty:
1314           case mStripVeloProperty:
1315           case mStripComprProperty:
1316             color = MusEGlobal::config.midiPropertySliderColor;
1317           break;
1318         }
1319       }
1320       break;
1321     }
1322 
1323     switch(cw._widgetType)
1324     {
1325       case CompactKnobComponentWidget:
1326       {
1327         CompactKnob* w = static_cast<CompactKnob*>(cw._widget);
1328         w->setFaceColor(color);
1329       }
1330       break;
1331 
1332       case CompactSliderComponentWidget:
1333       {
1334         CompactSlider* w = static_cast<CompactSlider*>(cw._widget);
1335         w->setBorderColor(color);
1336         w->setThumbColor(color);
1337         w->setBarColor(MusEGlobal::config.sliderBarColor);
1338         w->setSlotColor(MusEGlobal::config.sliderBackgroundColor);
1339       }
1340       break;
1341 
1342       case mStripCompactPatchEditComponentWidget:
1343       {
1344         CompactPatchEdit* w = static_cast<CompactPatchEdit*>(cw._widget);
1345         w->setReadoutColor(color);
1346         w->setBgColor(MusEGlobal::config.midiInstrumentBackgroundColor);
1347         w->setBgActiveColor(MusEGlobal::config.midiInstrumentBgActiveColor);
1348         w->setBorderColor(MusEGlobal::config.midiInstrumentBorderColor);
1349 //        w->setBorderColorPatchEdit(MusEGlobal::config.midiInstrumentBgActiveColor);
1350         w->setFontColor(MusEGlobal::config.midiInstrumentFontColor);
1351         w->setFontActiveColor(MusEGlobal::config.midiInstrumentFontActiveColor);
1352       }
1353       break;
1354 
1355     case ElidedLabelComponentWidget:
1356     {
1357         ElidedLabel* w = static_cast<ElidedLabel*>(cw._widget);
1358 
1359         w->setBgColor(MusEGlobal::config.midiInstrumentBackgroundColor);
1360         w->setBgActiveColor(MusEGlobal::config.midiInstrumentBgActiveColor);
1361         w->setBorderColor(MusEGlobal::config.midiInstrumentBorderColor);
1362         w->setFontColor(MusEGlobal::config.midiInstrumentFontColor);
1363         w->setFontActiveColor(MusEGlobal::config.midiInstrumentFontActiveColor);
1364     }
1365         break;
1366     }
1367   }
1368 }
1369 
setupComponentTabbing(QWidget * previousWidget)1370 QWidget* MidiComponentRack::setupComponentTabbing(QWidget* previousWidget)
1371 {
1372   QWidget* prev = previousWidget;
1373   for(ciComponentWidget ic = _components.begin(); ic != _components.end(); ++ic)
1374   {
1375     const ComponentWidget& cw = *ic;
1376     if(cw._widget)
1377     {
1378       switch(cw._widgetType)
1379       {
1380         case mStripCompactPatchEditComponentWidget:
1381         {
1382           CompactPatchEdit* w = static_cast<CompactPatchEdit*>(cw._widget);
1383           prev = w->setupComponentTabbing(prev);
1384         }
1385         break;
1386 
1387         default:
1388           if(prev)
1389             QWidget::setTabOrder(prev, cw._widget);
1390           prev = cw._widget;
1391         break;
1392       }
1393     }
1394   }
1395   return prev;
1396 }
1397 
1398 
1399 //---------------------------------------------------------
1400 //   MidiStripProperties
1401 //---------------------------------------------------------
1402 
MidiStripProperties()1403 MidiStripProperties::MidiStripProperties()
1404 {
1405     _sliderRadius = 4;
1406     _sliderRadiusHandle = 2;
1407     _sliderHandleHeight = 16;
1408     _sliderHandleWidth = 16;
1409     _sliderFillOver = true;
1410     _sliderUseGradient = true;
1411     _sliderBackbone = false;
1412     _sliderFillHandle = true;
1413     _sliderGrooveWidth = 14;
1414     _sliderScalePos = Slider::InsideVertical;
1415     _sliderFrame = false;
1416     _sliderFrameColor = Qt::darkGray;
1417     _meterWidth = Strip::FIXED_METER_WIDTH;
1418     _meterSpacing = 2;
1419     _meterFrame = false;
1420     _meterFrameColor = Qt::darkGray;
1421     ensurePolished();
1422 }
1423 
1424 
1425 //---------------------------------------------------------
1426 //   MidiStrip
1427 //---------------------------------------------------------
1428 
MidiStrip(QWidget * parent,MusECore::MidiTrack * t,bool hasHandle,bool isEmbedded)1429 MidiStrip::MidiStrip(QWidget* parent, MusECore::MidiTrack* t, bool hasHandle, bool isEmbedded)
1430    : Strip(parent, t, hasHandle, isEmbedded)
1431       {
1432       inHeartBeat = true;
1433       _heartBeatCounter = 0;
1434       volume = MusECore::CTRL_VAL_UNKNOWN;
1435 
1436       _preferKnobs = MusEGlobal::config.preferKnobsVsSliders;
1437       _preferMidiVolumeDb = MusEGlobal::config.preferMidiVolumeDb;
1438 
1439       slider        = nullptr;
1440       sl            = nullptr;
1441       off           = nullptr;
1442       _recMonitor   = nullptr;
1443 
1444       // Start the layout in mode A (normal, racks on left).
1445       _isExpanded = false;
1446 
1447       setStripStyle();
1448 
1449       // Clear so the meters don't start off by showing stale values.
1450       t->setActivity(0);
1451       t->setLastActivity(0);
1452 
1453       _routePos            = GridPosStruct(_curGridRow,     0, 1, 3);
1454       _upperStackTabPos    = GridPosStruct(_curGridRow + 1, 0, 1, 3);
1455       _sliderMeterPos      = GridPosStruct(_curGridRow + 2, 0, 1, 3);
1456       _lowerRackPos        = GridPosStruct(_curGridRow + 3, 0, 1, 3);
1457       _bottomPos           = GridPosStruct(_curGridRow + 4, 0, 1, 3);
1458 //      _routePos            = GridPosStruct(_curGridRow,     0, 1, 2);
1459 //      _upperStackTabPos    = GridPosStruct(_curGridRow + 1, 0, 1, 3);
1460 //      _sliderMeterPos      = GridPosStruct(_curGridRow + 2, 0, 1, 2);
1461 //      _lowerRackPos        = GridPosStruct(_curGridRow + 3, 0, 1, 3);
1462 //      _bottomPos           = GridPosStruct(_curGridRow + 4, 0, 1, 2);
1463 
1464       //---------------------------------------------------
1465       //    routing
1466       //---------------------------------------------------
1467 
1468       QHBoxLayout *routeLayout = new QHBoxLayout;
1469       routeLayout->setContentsMargins(1,3,1,2);
1470       routeLayout->setSpacing(1);
1471 
1472 //      iR = new IconButton(routingInputSVGIcon, routingInputSVGIcon,
1473 //                          routingInputUnconnectedSVGIcon, routingInputUnconnectedSVGIcon, false, true);
1474       iR = new QPushButton(this);
1475       iR->setIcon(*routingInputSVGIcon);
1476       iR->setObjectName("InputRouteButton");
1477       iR->setStatusTip(tr("Input routing. Hold CTRL to keep menu open. Press F1 for help."));
1478       iR->setFocusPolicy(Qt::NoFocus);
1479       iR->setToolTip(MusEGlobal::inputRoutingToolTipBase);
1480       connect(iR, SIGNAL(pressed()), SLOT(iRoutePressed()));
1481       routeLayout->addWidget(iR);
1482 
1483 //      oR = new IconButton(routingOutputSVGIcon, routingOutputSVGIcon,
1484 //                          routingOutputUnconnectedSVGIcon, routingOutputUnconnectedSVGIcon, false, true);
1485       oR = new QPushButton(this);
1486       oR->setIcon(*routingOutputSVGIcon);
1487       oR->setObjectName("OutputRouteButton");
1488       oR->setStatusTip(tr("Output routing. Hold CTRL to keep menu open. Press F1 for help."));
1489       oR->setFocusPolicy(Qt::NoFocus);
1490       oR->setToolTip(MusEGlobal::outputRoutingToolTipBase);
1491       connect(oR, SIGNAL(pressed()), SLOT(oRoutePressed()));
1492       routeLayout->addWidget(oR);
1493 
1494       updateRouteButtons();
1495 
1496       addGridLayout(routeLayout, _routePos);
1497 
1498 
1499       tabwidget = new QTabWidget(this);
1500       tabwidget->setObjectName("MidiStripTabWidget");
1501       tabwidget->setUsesScrollButtons(false);
1502 
1503       _infoRack = new MidiComponentRack(t, mStripInfoRack);
1504       _infoRack->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Minimum);
1505       _infoRack->setContentsMargins(0,0,0,0);
1506       _infoRack->setFocusPolicy(Qt::NoFocus);
1507 
1508       _upperRack = new MidiComponentRack(t, mStripUpperRack);
1509       _upperRack->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Minimum);
1510       _upperRack->setContentsMargins(0,0,0,0);
1511       _upperRack->setFocusPolicy(Qt::NoFocus);
1512 
1513       tabwidget->addTab(_upperRack, tr("Inst"));
1514       tabwidget->addTab(_infoRack, tr("Prop"));
1515       tabwidget->setTabToolTip(0, tr("Instruments and controllers"));
1516       tabwidget->setTabToolTip(1, tr("Properties"));
1517       tabwidget->setContentsMargins(0,0,0,0);
1518       tabwidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Minimum);
1519       addGridWidget(tabwidget, _upperStackTabPos);
1520 
1521       //---------------------------------------------------
1522       //    slider, label, meter
1523       //---------------------------------------------------
1524 
1525       MusECore::MidiPort* mp = &MusEGlobal::midiPorts[t->outPort()];
1526       const int chan  = t->outChannel();
1527       MusECore::MidiController* mc = mp->midiController(MusECore::CTRL_VOLUME, chan); // Auto-create the controller if necessary.
1528 
1529       slider = new Slider(nullptr, "vol", Qt::Vertical, Slider::InsideVertical, 14,
1530                           MusEGlobal::config.midiVolumeSliderColor,
1531                           ScaleDraw::TextHighlightSplitAndShadow,
1532                           MusEGlobal::config.midiVolumeHandleColor);
1533       slider->setId(MusECore::CTRL_VOLUME);
1534       slider->setFocusPolicy(Qt::NoFocus);
1535       slider->setContentsMargins(0, 0, 0, 0);
1536       slider->setCursorHoming(true);
1537       slider->setSpecialText(tr("off"));
1538       slider->setScaleBackBone(props.sliderBackbone());
1539 
1540       slider->setRadius(props.sliderRadius());
1541       slider->setRadiusHandle(props.sliderRadiusHandle());
1542       slider->setHandleHeight(props.sliderHandleHeight());
1543       slider->setHandleWidth(props.sliderHandleWidth());
1544       slider->setFillThumb(props.sliderFillHandle());
1545       slider->setGrooveWidth(props.sliderGrooveWidth());
1546       slider->setFillEmptySide(props.sliderFillOver());
1547       slider->setUseGradient(props.sliderUseGradient());
1548       slider->setScalePos(static_cast<Slider::ScalePos>(props.sliderScalePos()));
1549       slider->setFrame(props.sliderFrame());
1550       slider->setFrameColor(props.sliderFrameColor());
1551 
1552       slider->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
1553       slider->setMinimumHeight(80);
1554 
1555       _meterLayout = new MeterLayout(slider->scaleEndpointsMargin());
1556       _meterLayout->setMargin(0);
1557       _meterLayout->setSpacing(props.meterSpacing());
1558 
1559       meter[0] = new Meter(nullptr, Meter::LinMeter, Qt::Vertical, 0.0, 127.0);
1560       meter[0]->setRefreshRate(MusEGlobal::config.guiRefresh);
1561       meter[0]->setContentsMargins(0, 0, 0, 0);
1562       meter[0]->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
1563       meter[0]->setFixedWidth(props.meterWidth());
1564       meter[0]->setPrimaryColor(MusEGlobal::config.midiMeterPrimaryColor,
1565                                 MusEGlobal::config.meterBackgroundColor);
1566       meter[0]->setFrame(props.meterFrame(), props.meterFrameColor());
1567       connect(meter[0], SIGNAL(mousePress()), this, SLOT(resetPeaks()));
1568       _meterLayout->hlayout()->addWidget(meter[0], Qt::AlignHCenter);
1569 
1570       sl = new MusEGui::DoubleLabel(0.0, -98.0, 0.0);
1571       sl->setObjectName("VolumeEditMidi");
1572       sl->setContentsMargins(0, 0, 0, 0);
1573       sl->setTextMargins(0, 0, 0, 0);
1574       sl->setFocusPolicy(Qt::WheelFocus);
1575       sl->setMouseTracking(true);
1576       sl->setFrame(true);
1577       sl->setAlignment(Qt::AlignCenter);
1578       //sl->setAutoFillBackground(true);
1579 
1580       //sl->setBackgroundRole(QPalette::Mid);
1581       sl->setSpecialText(tr("off"));
1582       sl->setToolTip(tr("Volume/Gain\n(Ctrl-double-click on/off)"));
1583       sl->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
1584       // Set the label's slider 'buddy'.
1585       sl->setSlider(slider);
1586 //      sl->setEnableStyleHack(MusEGlobal::config.lineEditStyleHack);
1587 
1588       // Special for midi volume slider and label: Setup midi volume as decibel preference.
1589       setupMidiVolume();
1590 
1591       // If smart focus is on redirect strip focus to slider label.
1592       //if(MusEGlobal::config.smartFocus)
1593         setFocusProxy(sl);
1594 
1595       if(mc)
1596       {
1597         double dlv;
1598         double v = mp->hwDCtrlState(chan, MusECore::CTRL_VOLUME);
1599         if(MusECore::MidiController::dValIsUnknown(v))
1600         {
1601           double lastv = mp->lastValidHWDCtrlState(chan, MusECore::CTRL_VOLUME);
1602           if(MusECore::MidiController::dValIsUnknown(lastv))
1603           {
1604             if(mc->initValIsUnknown())
1605               v = 0.0;
1606             else
1607               v = double(mc->initVal());
1608           }
1609           else
1610             v = lastv - double(mc->bias());
1611           dlv = sl->off() - 1.0;
1612         }
1613         else
1614         {
1615           if(v <= 0.0)
1616             dlv = sl->minValue() - 0.5 * (sl->minValue() - sl->off());
1617           else
1618           {
1619             dlv = _preferMidiVolumeDb ? (muse_val2dbr(v / double(mc->maxVal())) * 2.0) : v;
1620             if(dlv > sl->maxValue())
1621               dlv = sl->maxValue();
1622           }
1623           // Auto bias...
1624           v -= double(mc->bias());
1625         }
1626         double slv;
1627         if(v <= 0.0)
1628         {
1629           if(_preferMidiVolumeDb)
1630             slv = MusEGlobal::config.minSlider;
1631           else
1632             slv = 0.0;
1633         }
1634         else
1635           slv = _preferMidiVolumeDb ? (muse_val2dbr(v / double(mc->maxVal())) * 2.0) : v;
1636 
1637         slider->setValue(slv);
1638         sl->setValue(dlv);
1639       }
1640 
1641       connect(slider, SIGNAL(valueChanged(double,int,int)), SLOT(setVolume(double,int,int)));
1642       connect(slider, SIGNAL(sliderRightClicked(QPoint,int)), SLOT(controlRightClicked(QPoint,int)));
1643       connect(slider, SIGNAL(sliderPressed(double, int)), SLOT(volumePressed(double, int)));
1644       connect(slider, SIGNAL(sliderReleased(double, int)), SLOT(volumeReleased(double, int)));
1645       connect(sl, SIGNAL(valueChanged(double, int)), SLOT(volLabelChanged(double)));
1646       connect(sl, SIGNAL(ctrlDoubleClicked(int)), SLOT(volLabelDoubleClicked()));
1647 
1648       sliderGrid = new QGridLayout();
1649       sliderGrid->setSpacing(0);
1650       sliderGrid->setHorizontalSpacing(2);
1651       sliderGrid->setContentsMargins(2, 0, 3, 2);
1652 
1653       sliderGrid->addWidget(slider, 0, 0, Qt::AlignHCenter);
1654       sliderGrid->addLayout(_meterLayout, 0, 1, Qt::AlignHCenter);
1655       sliderGrid->addWidget(sl, 2, 0, 1, 2, Qt::AlignHCenter);
1656 
1657 //      sliderGrid->setColumnStretch(0, slider->sizeHint().width());
1658 //      sliderGrid->setColumnStretch(1, meter[0]->sizeHint().width());
1659 
1660       QHBoxLayout *sliderHLayout = new QHBoxLayout();
1661       sliderHLayout->setContentsMargins(0,0,0,0);
1662       sliderHLayout->setSpacing(0);
1663       sliderHLayout->addStretch();
1664       sliderHLayout->addLayout(sliderGrid);
1665       sliderHLayout->addStretch();
1666       sliderHLayout->setAlignment(Qt::AlignHCenter);
1667 
1668       QFrame *sliderMeterFrame = new QFrame;
1669       sliderMeterFrame->setObjectName("SliderMeterFrameMidi");
1670       sliderMeterFrame->setLayout(sliderHLayout);
1671 //      sliderMeterFrame->setLayout(sliderGrid);
1672       sliderMeterFrame->setMinimumWidth(cMinStripWidth);
1673 
1674       QHBoxLayout *sliderMeterLayout = new QHBoxLayout();
1675       sliderMeterLayout->setContentsMargins(1,0,1,2);
1676       sliderMeterLayout->addWidget(sliderMeterFrame);
1677       addGridLayout(sliderMeterLayout, _sliderMeterPos);
1678 
1679       //---------------------------------------------------
1680       //    pan, balance
1681       //---------------------------------------------------
1682 
1683       _lowerRack = new MidiComponentRack(t, mStripLowerRack);
1684       // FIXME For some reason StyledPanel has trouble, intermittent sometimes panel is drawn, sometimes not.
1685       //_lowerRack->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
1686       _lowerRack->setFrameStyle(QFrame::Box | QFrame::Sunken);
1687       _lowerRack->setLineWidth(rackFrameWidth);
1688       _lowerRack->setMidLineWidth(0);
1689       // We do set a minimum height on this widget. Tested: Must be on fixed. Thankfully, it'll expand if more controls are added.
1690       _lowerRack->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
1691       _lowerRack->setContentsMargins(rackFrameWidth, rackFrameWidth, rackFrameWidth, rackFrameWidth);
1692       _lowerRack->setFocusPolicy(Qt::NoFocus);
1693 
1694       addGridWidget(_lowerRack, _lowerRackPos);
1695 
1696       _upperRack->setEnabled(!t->off());
1697       _infoRack->setEnabled(!t->off());
1698       _lowerRack->setEnabled(!t->off());
1699 
1700       //---------------------------------------------------
1701       //    mute, solo
1702       //    or
1703       //    record, mixdownfile
1704       //---------------------------------------------------
1705 
1706       QGridLayout *bottomLayout = new QGridLayout;
1707       bottomLayout->setContentsMargins(1,1,1,2);
1708       bottomLayout->setSpacing(1);
1709 
1710       if (track && track->canRecordMonitor()) {
1711           //        _recMonitor = new IconButton(monitorOnSVGIcon, monitorOffSVGIcon, nullptr, nullptr, false, true);
1712           _recMonitor = new QPushButton;
1713           _recMonitor->setIcon(*monitorStateSVGIcon);
1714           _recMonitor->setFocusPolicy(Qt::NoFocus);
1715           _recMonitor->setCheckable(true);
1716           _recMonitor->setToolTip(tr("Input monitor"));
1717           _recMonitor->setWhatsThis(tr("Pass input through to output"));
1718           _recMonitor->setStatusTip(tr("Input monitor: Pass input through to output."));
1719           _recMonitor->setChecked(t->recMonitor());
1720           connect(_recMonitor, SIGNAL(toggled(bool)), SLOT(recMonitorToggled(bool)));
1721           bottomLayout->addWidget(_recMonitor, 0, 0, 1, 1);
1722       } else {
1723           QPushButton *recMonitorx = new QPushButton(this);
1724           recMonitorx->setIcon(*monitorOnSVGIcon);
1725           recMonitorx->setEnabled(false);
1726           bottomLayout->addWidget(recMonitorx, 0, 0, 1, 1);
1727       }
1728 
1729 //      record  = new IconButton(recArmOnSVGIcon, recArmOffSVGIcon, 0, 0, false, true);
1730       record  = new QPushButton(this);
1731       record->setIcon(*recArmStateSVGIcon);
1732       record->setFocusPolicy(Qt::NoFocus);
1733       record->setCheckable(true);
1734       record->setToolTip(tr("Record arm"));
1735       record->setChecked(track->recordFlag());
1736       connect(record, SIGNAL(toggled(bool)), SLOT(recordToggled(bool)));
1737       bottomLayout->addWidget(record, 0, 1, 1, 1);
1738 
1739 //      mute  = new IconButton(muteOnSVGIcon, muteOffSVGIcon, muteAndProxyOnSVGIcon, muteProxyOnSVGIcon, false, true);
1740       mute  = new QPushButton(this);
1741       mute->setIcon(*muteStateSVGIcon);
1742       mute->setFocusPolicy(Qt::NoFocus);
1743       mute->setCheckable(true);
1744       mute->setToolTip(tr("Mute or proxy mute"));
1745       mute->setStatusTip(tr("Mute or proxy mute. Connected tracks are 'phantom' muted."));
1746       mute->setChecked(track->mute());
1747       updateMuteIcon();
1748       connect(mute, SIGNAL(toggled(bool)), SLOT(muteToggled(bool)));
1749       bottomLayout->addWidget(mute, 1, 0, 1, 1);
1750 
1751 //      solo  = new IconButton(soloOnSVGIcon, soloOffSVGIcon, soloAndProxyOnSVGIcon, soloProxyOnSVGIcon, false, true);
1752       solo  = new QPushButton(this);
1753       solo->setIcon(*soloStateSVGIcon);
1754       solo->setObjectName("SoloButton");
1755       solo->setToolTip(tr("Solo or proxy solo"));
1756       solo->setStatusTip(tr("Solo or proxy solo. Connected tracks are 'phantom' soloed. Press F1 for help."));
1757       solo->setFocusPolicy(Qt::NoFocus);
1758       solo->setCheckable(true);
1759       if (track->internalSolo())
1760         solo->setIcon(*soloAndProxyOnSVGIcon);
1761       //      solo->setIconSetB(track->internalSolo());
1762       solo->setChecked(track->solo());
1763       connect(solo, SIGNAL(toggled(bool)), SLOT(soloToggled(bool)));
1764       bottomLayout->addWidget(solo, 1, 1, 1, 1);
1765 
1766 //      off  = new IconButton(trackOffSVGIcon, trackOnSVGIcon, 0, 0, false, true);
1767       off = new QPushButton(this);
1768       off->setObjectName("TrackOffButton");
1769       off->setIcon(*trackOnSVGIcon);
1770       off->setFocusPolicy(Qt::NoFocus);
1771       off->setCheckable(true);
1772       off->setToolTip(tr("Track off"));
1773       off->setChecked(track->off());
1774       connect(off, SIGNAL(toggled(bool)), SLOT(offToggled(bool)));
1775       bottomLayout->addWidget(off, 3, 0, 1, 2);
1776 
1777 
1778       //---------------------------------------------------
1779       //    automation mode
1780       //---------------------------------------------------
1781 
1782       autoType = new CompactComboBox();
1783       autoType->setObjectName("MidiAutoType");
1784       autoType->setContentsMargins(0, 0, 0, 0);
1785       autoType->setFocusPolicy(Qt::NoFocus);
1786       autoType->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
1787       autoType->setEnabled(false);
1788 
1789       // Removed by T356.
1790       // Disabled for now. There is no midi automation mechanism yet...
1791       //autoType->addAction(tr("Off"), AUTO_OFF);
1792       //autoType->addAction(tr("Read"), AUTO_READ);
1793       //autoType->addAction(tr("Touch"), AUTO_TOUCH);
1794       //autoType->addAction(tr("Write"), AUTO_WRITE);
1795       //autoType->setCurrentItem(t->automationType());
1796       //autoType->setToolTip(tr("automation type"));
1797       //connect(autoType, SIGNAL(activated(int)), SLOT(setAutomationType(int)));
1798 //      autoType->addAction("", MusECore::AUTO_OFF);  // Just a dummy text to fix sizing problems. REMOVE later if full automation added.
1799       autoType->addAction("n/a", MusECore::AUTO_OFF);
1800       autoType->setCurrentItem(MusECore::AUTO_OFF);
1801 
1802       bottomLayout->addWidget(autoType, 2, 0, 1, 2);
1803 
1804       addGridLayout(bottomLayout, _bottomPos);
1805 
1806       grid->setColumnStretch(2, 10);
1807 
1808       off->blockSignals(true);
1809       updateOffState();   // init state
1810       off->blockSignals(false);
1811 
1812 
1813       // Now build the strip components.
1814       buildStrip();
1815 
1816       // Now set up all tabbing on the strip.
1817       // Don't bother if the strip is part of the mixer (not embedded),
1818       //  the non-embedding parent (mixer) should set up all the tabs and make this call.
1819       if(isEmbedded)
1820         setupComponentTabbing();
1821 
1822       // TODO: Activate this. But owners want to marshall this signal and send it themselves. Change that.
1823       //connect(MusEGlobal::song, SIGNAL(songChanged(MusECore::SongChangedStruct_t)), SLOT(songChanged(MusECore::SongChangedStruct_t)));
1824 
1825       connect(MusEGlobal::heartBeatTimer, SIGNAL(timeout()), SLOT(heartBeat()));
1826 
1827       connect(_upperRack, SIGNAL(componentChanged(int,double,bool,int,int)), SLOT(componentChanged(int,double,bool,int,int)));
1828       connect(_upperRack, SIGNAL(componentMoved(int,double,int,bool)), SLOT(componentMoved(int,double,int,bool)));
1829       connect(_upperRack, SIGNAL(componentPressed(int,double,int)), SLOT(componentPressed(int,double,int)));
1830       connect(_upperRack, SIGNAL(componentReleased(int,double,int)), SLOT(componentReleased(int,double,int)));
1831 
1832       connect(_infoRack, SIGNAL(componentChanged(int,double,bool,int,int)), SLOT(componentChanged(int,double,bool,int,int)));
1833       connect(_infoRack, SIGNAL(componentMoved(int,double,int,bool)), SLOT(componentMoved(int,double,int,bool)));
1834       connect(_infoRack, SIGNAL(componentPressed(int,double,int)), SLOT(componentPressed(int,double,int)));
1835       connect(_infoRack, SIGNAL(componentReleased(int,double,int)), SLOT(componentReleased(int,double,int)));
1836 
1837       connect(_lowerRack, SIGNAL(componentChanged(int,double,bool,int,int)), SLOT(componentChanged(int,double,bool,int,int)));
1838       connect(_lowerRack, SIGNAL(componentMoved(int,double,int,bool)), SLOT(componentMoved(int,double,int,bool)));
1839       connect(_lowerRack, SIGNAL(componentPressed(int,double,int)), SLOT(componentPressed(int,double,int)));
1840       connect(_lowerRack, SIGNAL(componentReleased(int,double,int)), SLOT(componentReleased(int,double,int)));
1841 
1842       inHeartBeat = false;
1843       }
1844 
setStripStyle()1845 void MidiStrip::setStripStyle() {
1846     // Set the whole strip's font, except for the label.
1847     setFont(MusEGlobal::config.fonts[1]); // For some reason must keep this, the upper rack is too tall at first.
1848     int iconSize = MusEGlobal::config.fonts[1].pointSize() * 2;
1849     setStyleSheet(MusECore::font2StyleSheetFull(MusEGlobal::config.fonts[1])
1850             + "#Strip > QAbstractButton { padding: 0px; qproperty-iconSize:" +
1851                   QString::number(iconSize) + "px; }"
1852             + "#Strip #TrackOffButton { qproperty-iconSize:" + QString::number(iconSize - 2) + "px; }");
1853 }
1854 
1855 //---------------------------------------------------
1856 //  buildStrip
1857 //    Destroy and rebuild strip components.
1858 //---------------------------------------------------
1859 
buildStrip()1860 void MidiStrip::buildStrip()
1861 {
1862   // Destroys all components and clears the component list.
1863   _infoRack->clearDelete();
1864   _upperRack->clearDelete();
1865   _lowerRack->clearDelete();
1866 
1867   //---------------------------------------------------
1868   //    Upper rack
1869   //---------------------------------------------------
1870 
1871   ElidedLabelComponentDescriptor instrPropertyDesc(ComponentRack::propertyComponent,
1872                                             "MixerStripInstrumentProperty",
1873                                             MidiComponentRack::mStripInstrumentProperty,
1874                                             Qt::ElideNone);
1875   _upperRack->newComponent(&instrPropertyDesc);
1876 
1877   CompactPatchEditComponentDescriptor progControllerDesc(ComponentRack::controllerComponent, "MixerStripMidiProgramController", MusECore::CTRL_PROGRAM);
1878   _upperRack->newComponent(&progControllerDesc);
1879 
1880 
1881   if(_preferKnobs)
1882   {
1883     _upperRack->layout()->addItem(new QSpacerItem(0, 4));
1884 
1885     CompactKnobComponentDescriptor varSendControllerDesc(ComponentRack::controllerComponent, "MixerStripMidiVarSendController", MusECore::CTRL_VARIATION_SEND);
1886     CompactKnobComponentDescriptor revSendControllerDesc(ComponentRack::controllerComponent, "MixerStripMidiRevSendController", MusECore::CTRL_REVERB_SEND);
1887     CompactKnobComponentDescriptor choSendControllerDesc(ComponentRack::controllerComponent, "MixerStripMidiChoSendController", MusECore::CTRL_CHORUS_SEND);
1888     _upperRack->newComponent(&varSendControllerDesc);
1889     _upperRack->newComponent(&revSendControllerDesc);
1890     _upperRack->newComponent(&choSendControllerDesc);
1891   }
1892   else
1893   {
1894     _upperRack->layout()->addItem(new QSpacerItem(0, 2));
1895 
1896     // To avoid too bright or annoying joined borders which are twice the normal width,
1897     //  show no bottom borders except for last one!
1898     CompactSliderComponentDescriptor varSendControllerDesc(
1899       ComponentRack::controllerComponent,
1900       "MixerStripMidiVarSendController",
1901       MusECore::CTRL_VARIATION_SEND,
1902       CompactSlider::AllBordersExceptBottom);
1903     CompactSliderComponentDescriptor revSendControllerDesc(
1904       ComponentRack::controllerComponent,
1905       "MixerStripMidiRevSendController",
1906       MusECore::CTRL_REVERB_SEND,
1907       CompactSlider::AllBordersExceptBottom);
1908     CompactSliderComponentDescriptor choSendControllerDesc(
1909       ComponentRack::controllerComponent,
1910       "MixerStripMidiChoSendController",
1911       MusECore::CTRL_CHORUS_SEND,
1912       CompactSlider::AllBorders);
1913     _upperRack->newComponent(&varSendControllerDesc);
1914     _upperRack->newComponent(&revSendControllerDesc);
1915     _upperRack->newComponent(&choSendControllerDesc);
1916   }
1917 
1918   // Keep this if dynamic layout (flip to right side) is desired.
1919   _upperRack->addStretch();
1920 
1921   updateRackSizes(true, false);
1922 
1923 
1924   //---------------------------------------------------
1925   //    Track properties rack
1926   //---------------------------------------------------
1927 
1928   if(_preferKnobs)
1929   {
1930     CompactKnobComponentDescriptor transpPropertyDesc(ComponentRack::propertyComponent, "MixerStripMidiTranspProperty", MidiComponentRack::mStripTranspProperty);
1931     CompactKnobComponentDescriptor delayPropertyDesc(ComponentRack::propertyComponent, "MixerStripMidiDelayProperty", MidiComponentRack::mStripDelayProperty);
1932     CompactKnobComponentDescriptor lenPropertyDesc(ComponentRack::propertyComponent, "MixerStripMidiLenProperty", MidiComponentRack::mStripLenProperty);
1933     CompactKnobComponentDescriptor veloPropertyDesc(ComponentRack::propertyComponent, "MixerStripMidiVeloProperty", MidiComponentRack::mStripVeloProperty);
1934     CompactKnobComponentDescriptor comprPropertyDesc(ComponentRack::propertyComponent, "MixerStripMidiComprProperty", MidiComponentRack::mStripComprProperty);
1935 
1936     _infoRack->newComponent(&transpPropertyDesc);
1937     _infoRack->newComponent(&delayPropertyDesc);
1938     _infoRack->newComponent(&lenPropertyDesc);
1939     _infoRack->newComponent(&veloPropertyDesc);
1940     _infoRack->newComponent(&comprPropertyDesc);
1941   }
1942   else
1943   {
1944     // To avoid too bright or annoying joined borders which are twice the normal width,
1945     //  show no bottom borders except for last one!
1946     CompactSliderComponentDescriptor transpPropertyDesc(
1947       ComponentRack::propertyComponent,
1948       "MixerStripMidiTranspProperty",
1949       MidiComponentRack::mStripTranspProperty,
1950       CompactSlider::AllBordersExceptBottom);
1951     CompactSliderComponentDescriptor delayPropertyDesc(
1952       ComponentRack::propertyComponent,
1953       "MixerStripMidiDelayProperty",
1954       MidiComponentRack::mStripDelayProperty,
1955       CompactSlider::AllBordersExceptBottom);
1956     CompactSliderComponentDescriptor lenPropertyDesc(
1957       ComponentRack::propertyComponent,
1958       "MixerStripMidiLenProperty",
1959       MidiComponentRack::mStripLenProperty,
1960       CompactSlider::AllBordersExceptBottom);
1961     CompactSliderComponentDescriptor veloPropertyDesc(
1962       ComponentRack::propertyComponent,
1963       "MixerStripMidiVeloProperty",
1964       MidiComponentRack::mStripVeloProperty,
1965       CompactSlider::AllBordersExceptBottom);
1966     CompactSliderComponentDescriptor comprPropertyDesc(
1967       ComponentRack::propertyComponent,
1968       "MixerStripMidiComprProperty",
1969       MidiComponentRack::mStripComprProperty,
1970       CompactSlider::AllBorders);
1971 
1972     _infoRack->newComponent(&transpPropertyDesc);
1973     _infoRack->newComponent(&delayPropertyDesc);
1974     _infoRack->newComponent(&lenPropertyDesc);
1975     _infoRack->newComponent(&veloPropertyDesc);
1976     _infoRack->newComponent(&comprPropertyDesc);
1977   }
1978   _infoRack->addStretch();
1979 
1980 
1981   //---------------------------------------------------
1982   //    Lower rack
1983   //---------------------------------------------------
1984 
1985   // Pan...
1986   if(_preferKnobs)
1987   {
1988     CompactKnobComponentDescriptor panControllerDesc
1989     (
1990       ComponentRack::controllerComponent,
1991       "MixerStripMidiPanController",
1992       MusECore::CTRL_PANPOT
1993     );
1994     _lowerRack->newComponent(&panControllerDesc);
1995   }
1996   else
1997   {
1998     CompactSliderComponentDescriptor panControllerDesc
1999     (
2000       ComponentRack::controllerComponent,
2001       "MixerStripMidiPanController",
2002       MusECore::CTRL_PANPOT
2003     );
2004     _lowerRack->newComponent(&panControllerDesc);
2005   }
2006 
2007   // Keep this if dynamic layout (flip to right side) is desired.
2008   _lowerRack->addStretch();
2009 
2010   updateRackSizes(false, true);
2011 }
2012 
setupComponentTabbing(QWidget * previousWidget)2013 QWidget* MidiStrip::setupComponentTabbing(QWidget* previousWidget)
2014 {
2015   QWidget* prev = previousWidget;
2016   if(tabwidget->currentIndex() == 0)
2017   {
2018     if(prev)
2019       QWidget::setTabOrder(prev, tabwidget->currentWidget());
2020     prev = tabwidget->currentWidget();
2021   }
2022   if(tabwidget->currentIndex() == 1)
2023   {
2024     if(prev)
2025         QWidget::setTabOrder(prev, tabwidget->currentWidget());
2026       prev = tabwidget->currentWidget();
2027   }
2028   //  if(_upperStackTabButtonA)
2029   //  {
2030   //    if(prev)
2031   //      QWidget::setTabOrder(prev, _upperStackTabButtonA);
2032   //    prev = _upperStackTabButtonA;
2033   //  }
2034   //  if(_upperStackTabButtonB)
2035   //  {
2036   //    if(prev)
2037   //      QWidget::setTabOrder(prev, _upperStackTabButtonB);
2038   //    prev = _upperStackTabButtonB;
2039   //  }
2040   prev = _upperRack->setupComponentTabbing(prev);
2041   prev = _infoRack->setupComponentTabbing(prev);
2042   if(sl)
2043   {
2044     if(prev)
2045       QWidget::setTabOrder(prev, sl);
2046     prev = sl;
2047   }
2048   prev = _lowerRack->setupComponentTabbing(prev);
2049   return prev;
2050 }
2051 
setupMidiVolume()2052 void MidiStrip::setupMidiVolume()
2053 {
2054   const bool show_db = MusEGlobal::config.preferMidiVolumeDb;
2055 
2056   if(track && track->isMidiTrack())
2057   {
2058     const int num = MusECore::CTRL_VOLUME;
2059     MusECore::MidiTrack* mt = static_cast<MusECore::MidiTrack*>(track);
2060     MusECore::MidiPort* mp = &MusEGlobal::midiPorts[mt->outPort()];
2061     const int chan = mt->outChannel();
2062     MusECore::MidiController* mc = mp->midiController(num, chan, false);
2063     if(!mc)
2064       return;
2065     const int mn = mc->minVal();
2066     const int mx = mc->maxVal();
2067 
2068     if(show_db)
2069     {
2070       slider->setRange(MusEGlobal::config.minSlider, volSliderMaxDb, volSliderStepDb);
2071       //slider->setScaleMaxMinor(5);
2072       slider->setScale(MusEGlobal::config.minSlider, volSliderMaxDb, 6.0, false);
2073       //slider->setSpecialText(tr("off"));
2074       //slider->setSpecialText(QString('-') + QChar(0x221e)); // The infinity character.
2075 
2076       sl->setPrecision(volSliderPrecDb);
2077       sl->setRange(MusEGlobal::config.minSlider, volSliderMaxDb);
2078       sl->setOff(MusEGlobal::config.minSlider);
2079       //sl->setSpecialText(tr("off"));
2080       //sl->setSpecialText(QString('-') + QChar(0x221e) + QChar(' ') + "dB");  // The infinity character.
2081       //sl->setToolTip(tr("Volume/gain"));
2082       sl->setSuffix("dB");
2083     }
2084     else
2085     {
2086       slider->setRange(double(mn), double(mx), volSliderStepLin);
2087       //slider->setScaleMaxMinor(5);
2088       slider->setScale(double(mn), double(mx), 10.0, false);
2089       //slider->setSpecialText(tr("off"));
2090       //slider->setSpecialText(QString('-') + QChar(0x221e)); // The infinity character.
2091 
2092       sl->setPrecision(0);
2093       sl->setRange(double(mn), double(mx));
2094       sl->setOff(double(mn) - 1.0); // Reset to default.
2095       //sl->setSpecialText(tr("off"));
2096       //sl->setSpecialText(QString('-') + QChar(0x221e)); // The infinity character.
2097       //sl->setToolTip(tr("Volume/gain\n(Ctrl-double-click on/off)"));
2098       sl->setSuffix(QString());
2099     }
2100 
2101     // Invalidate the cached volume so that the next heartbeat updates with a new value.
2102     volume = MusECore::CTRL_VAL_UNKNOWN;
2103 
2104     if(_preferMidiVolumeDb != show_db)
2105     {
2106       const int chan = mt->outChannel();
2107       const double d_lastv = mp->lastValidHWDCtrlState(chan, num);
2108       const double d_curv = mp->hwDCtrlState(chan, num);
2109 
2110       if(MusECore::MidiController::dValIsUnknown(d_curv))
2111       {
2112         // If no value has ever been set yet, use the current knob value
2113         //  (or the controller's initial value?) to 'turn on' the controller.
2114         if(MusECore::MidiController::dValIsUnknown(d_lastv))
2115         {
2116           double slider_v = slider->value();
2117           if(slider_v == 0.0)
2118           {
2119             if(show_db)
2120               slider_v = MusEGlobal::config.minSlider;
2121           }
2122           else
2123           {
2124             if(show_db)
2125               slider_v = muse_val2dbr(slider_v / double(mx)) * 2.0;
2126             else
2127               slider_v = double(mx) * muse_db2val(slider_v / 2.0);
2128           }
2129 
2130           slider->blockSignals(true);
2131           slider->setValue(slider_v);
2132           slider->blockSignals(false);
2133         }
2134       }
2135     }
2136   }
2137 
2138   _preferMidiVolumeDb = show_db;
2139 }
2140 
2141 //---------------------------------------------------------
2142 //   updateOffState
2143 //---------------------------------------------------------
2144 
updateOffState()2145 void MidiStrip::updateOffState()
2146       {
2147       if(!track)
2148         return;
2149 
2150       bool val = !track->off();
2151       slider->setEnabled(val);
2152       sl->setEnabled(val);
2153 
2154       _upperRack->setEnabled(val);
2155       _infoRack->setEnabled(val);
2156       _lowerRack->setEnabled(val);
2157 
2158       label->setEnabled(val);
2159 
2160       if (_recMonitor)
2161             _recMonitor->setEnabled(val);
2162       if (record)
2163             record->setEnabled(val);
2164       if (solo)
2165             solo->setEnabled(val);
2166       if (mute)
2167             mute->setEnabled(val);
2168       // TODO: Disabled for now.
2169       //if (autoType)
2170       //      autoType->setEnabled(val);
2171       //if (iR)
2172       //      iR->setEnabled(val);
2173       //if (oR)
2174       //      oR->setEnabled(val);
2175 
2176       if (off) {
2177             off->blockSignals(true);
2178             off->setChecked(track->off());
2179             off->blockSignals(false);
2180             }
2181       }
2182 
updateRackSizes(bool upper,bool lower)2183 void MidiStrip::updateRackSizes(bool upper, bool lower)
2184 {
2185 //   const QFontMetrics fm = fontMetrics();
2186   if(upper)
2187   {
2188     // Make room for 3 CompactSliders and one CompactPatchEdit.
2189     // TODO: Add the instrument select label height!
2190 
2191 // //     const int csh = CompactSlider::getMinimumSizeHint(fm,
2192 // //                                             Qt::Horizontal,
2193 // //                                             CompactSlider::None,
2194 // //                                             xMarginHorSlider, yMarginHorSlider).height();
2195 // //     const int cpeh = CompactPatchEdit::getMinimumSizeHint(fm,
2196 // //                                             Qt::Horizontal,
2197 // //                                             CompactSlider::None,
2198 // //                                             xMarginHorSlider, yMarginHorSlider).height();
2199 // //     const int ilh = _instrLabel->sizeHint().height();
2200 //
2201 // //     DEBUG_MIDI_STRIP(stderr, "MidiStrip::updateRackSizes: CompactSlider h:%d CompactPatchEdit h:%d instrLabel h:%d upper frame w:%d \n",
2202 // //                      csh, cpeh, ilh, _upperRack->frameWidth());
2203 //
2204 //     _upperRack->setMinimumHeight(
2205 //       3 * CompactSlider::getMinimumSizeHint(fm,
2206 //                                             Qt::Horizontal,
2207 //                                             CompactSlider::None,
2208 //                                             xMarginHorSlider, yMarginHorSlider).height() +
2209 //       1 * CompactPatchEdit::getMinimumSizeHint(fm,
2210 //                                             Qt::Horizontal,
2211 //                                             CompactSlider::None,
2212 //                                             xMarginHorSlider, yMarginHorSlider).height() +
2213 //       upperRackSpacerHeight +
2214 //
2215 //       _instrLabel->sizeHint().height() +
2216 //
2217 //       2 * rackFrameWidth);
2218   }
2219   if(lower)
2220   {
2221     // Make room for 1 CompactSlider (Pan, so far).
2222 
2223     //DEBUG_MIDI_STRIP(stderr, "MidiStrip::updateRackSizes: lower frame w:%d \n", _lowerRack->frameWidth());
2224 
2225 //     _lowerRack->setMinimumHeight(
2226 //       1 * CompactSlider::getMinimumSizeHint(fm,
2227 //                                             Qt::Horizontal,
2228 //                                             CompactSlider::None,
2229 //                                             xMarginHorSlider, yMarginHorSlider).height() +
2230 //       2 * rackFrameWidth);
2231   }
2232 }
2233 
2234 //---------------------------------------------------------
2235 //   configChanged
2236 //   Catch when config label font changes, viewable tracks etc.
2237 //---------------------------------------------------------
2238 
configChanged()2239 void MidiStrip::configChanged()
2240 {
2241   // Detect when knobs are preferred and rebuild.
2242   if(_preferKnobs != MusEGlobal::config.preferKnobsVsSliders)
2243   {
2244     _preferKnobs = MusEGlobal::config.preferKnobsVsSliders;
2245     // Rebuild the strip components.
2246     buildStrip();
2247     // Now set up all tabbing on the strip.
2248     // Don't bother if the strip is part of the mixer (not embedded),
2249     //  the non-embedding parent (mixer) should set up all the tabs and make this call.
2250     if(isEmbedded())
2251       setupComponentTabbing();
2252   }
2253 
2254   // Set the whole strip's font, except for the label.
2255   if(font() != MusEGlobal::config.fonts[1])
2256   {
2257     //DEBUG_MIDI_STRIP(stderr, "MidiStrip::configChanged changing font: current size:%d\n", font().pointSize());
2258     setStripStyle();
2259     // Update in case font changed.
2260 //    updateRackSizes(true, true); // function has no content
2261   }
2262   // Update always, in case style, stylesheet, or font changed.
2263   //updateRackSizes(true, true);
2264 
2265   // Set the strip label's font.
2266   setLabelText();
2267 
2268   slider->setFillColor(MusEGlobal::config.midiVolumeSliderColor);
2269   slider->setHandleColor(MusEGlobal::config.midiVolumeHandleColor);
2270 
2271 //  _upperStackTabButtonA->setBgColor(MusEGlobal::config.palSwitchBackgroundColor);
2272 //  _upperStackTabButtonB->setBgColor(MusEGlobal::config.palSwitchBackgroundColor);
2273 //  _upperStackTabButtonA->setBgActiveColor(MusEGlobal::config.palSwitchBgActiveColor);
2274 //  _upperStackTabButtonB->setBgActiveColor(MusEGlobal::config.palSwitchBgActiveColor);
2275 //  _upperStackTabButtonA->setBorderColor(MusEGlobal::config.palSwitchBorderColor);
2276 //  _upperStackTabButtonB->setBorderColor(MusEGlobal::config.palSwitchBorderColor);
2277 //  _upperStackTabButtonA->setFontColor(MusEGlobal::config.palSwitchFontColor);
2278 //  _upperStackTabButtonB->setFontColor(MusEGlobal::config.palSwitchFontColor);
2279 //  _upperStackTabButtonA->setFontActiveColor(MusEGlobal::config.palSwitchFontActiveColor);
2280 //  _upperStackTabButtonB->setFontActiveColor(MusEGlobal::config.palSwitchFontActiveColor);
2281 
2282   // Enable special hack for line edits.
2283 //  if(sl->enableStyleHack() != MusEGlobal::config.lineEditStyleHack)
2284 //    sl->setEnableStyleHack(MusEGlobal::config.lineEditStyleHack);
2285 
2286   // Special for midi volume slider and label: Setup midi volume as decibel preference.
2287   setupMidiVolume();
2288 
2289   // REMOVE Tim. mixer. Added.
2290   // In case something in the slider changed, update the meter layout.
2291   // TODO This is somewhat crude, might miss automatic changes.
2292   // Later link up MeterLayout and Slider better.
2293   _meterLayout->setMeterEndsMargin(slider->scaleEndpointsMargin());
2294 
2295   _upperRack->configChanged();
2296   _infoRack->configChanged();
2297   _lowerRack->configChanged();
2298 
2299   // Adjust meter and colour.
2300   meter[0]->setPrimaryColor(MusEGlobal::config.midiMeterPrimaryColor,
2301                             MusEGlobal::config.meterBackgroundColor);
2302   meter[0]->setRefreshRate(MusEGlobal::config.guiRefresh);
2303 
2304   // If smart focus is on redirect strip focus to slider label.
2305 //   if(MusEGlobal::config.smartFocus)
2306 //     setFocusProxy(sl);
2307 //   else
2308 //     setFocusProxy(0);
2309 }
2310 
2311 //---------------------------------------------------------
2312 //   songChanged
2313 //---------------------------------------------------------
2314 
songChanged(MusECore::SongChangedStruct_t val)2315 void MidiStrip::songChanged(MusECore::SongChangedStruct_t val)
2316       {
2317       if (mute && (val & SC_MUTE)) {      // mute && off
2318             mute->blockSignals(true);
2319             mute->setChecked(track->mute());
2320             mute->blockSignals(false);
2321             updateMuteIcon();
2322             updateOffState();
2323             }
2324       if (solo && (val & (SC_SOLO | SC_ROUTE)))
2325       {
2326             solo->blockSignals(true);
2327             solo->setChecked(track->solo());
2328             solo->blockSignals(false);
2329 //            solo->setIconSetB(track->internalSolo());
2330             if (track->internalSolo()) {
2331                 if (solo->isChecked())
2332                     solo->setIcon(*soloAndProxyOnSVGIcon);
2333                 else
2334                     solo->setIcon(*soloProxyOnAloneSVGIcon);
2335             } else {
2336                 solo->setIcon(*soloStateSVGIcon);
2337             }
2338             updateMuteIcon();
2339       }
2340 
2341       if (val & SC_RECFLAG)
2342       {
2343             setRecordFlag(track->recordFlag());
2344       }
2345       if (val & SC_TRACK_MODIFIED)
2346       {
2347             setLabelText();
2348       }
2349 
2350       // Catch when label font changes.
2351       if (val & SC_CONFIG)
2352       {
2353         // So far only 1 instance of sending SC_CONFIG in the entire app, in instrument editor when a new instrument is saved.
2354       }
2355 
2356       _upperRack->songChanged(val);
2357       _infoRack->songChanged(val);
2358       _lowerRack->songChanged(val);
2359 
2360       if (val & SC_ROUTE) {
2361         updateRouteButtons();
2362       }
2363 
2364       if(val & SC_TRACK_REC_MONITOR)
2365       {
2366         // Set record monitor.
2367         if(_recMonitor)
2368         {
2369           _recMonitor->blockSignals(true);
2370           _recMonitor->setChecked(track->recMonitor());
2371           _recMonitor->blockSignals(false);
2372         }
2373       }
2374     }
2375 
2376 //---------------------------------------------------------
2377 //   controlRightClicked
2378 //---------------------------------------------------------
2379 
controlRightClicked(QPoint p,int id)2380 void MidiStrip::controlRightClicked(QPoint p, int id)
2381 {
2382   MusEGlobal::song->execMidiAutomationCtlPopup(static_cast<MusECore::MidiTrack*>(track), 0, p, id);
2383 }
2384 
2385 //void MidiStrip::upperStackTabButtonAPressed()
2386 //{
2387 //  _infoRack->hide();
2388 //  _upperRack->show();
2389 //  _upperStackTabButtonA->setOff(false);
2390 //  _upperStackTabButtonB->setOff(true);
2391 //}
2392 
2393 //void MidiStrip::upperStackTabButtonBPressed()
2394 //{
2395 //  _upperRack->hide();
2396 //  _infoRack->show();
2397 //  _upperStackTabButtonA->setOff(true);
2398 //  _upperStackTabButtonB->setOff(false);
2399 //}
2400 
2401 //---------------------------------------------------------
2402 //   recMonitorToggled
2403 //---------------------------------------------------------
2404 
recMonitorToggled(bool v)2405 void MidiStrip::recMonitorToggled(bool v)
2406 {
2407   if(!track)
2408     return;
2409   // This is a minor operation easily manually undoable. Let's not clog the undo list with it.
2410   MusECore::PendingOperationList operations;
2411   operations.add(MusECore::PendingOperationItem(track, v, MusECore::PendingOperationItem::SetTrackRecMonitor));
2412   MusEGlobal::audio->msgExecutePendingOperations(operations, true);
2413 }
2414 
2415 //---------------------------------------------------------
2416 //   volLabelDoubleClicked
2417 //---------------------------------------------------------
2418 
volLabelDoubleClicked()2419 void MidiStrip::volLabelDoubleClicked()
2420 {
2421   const int num = MusECore::CTRL_VOLUME;
2422   const int outport = static_cast<MusECore::MidiTrack*>(track)->outPort();
2423   const int chan = static_cast<MusECore::MidiTrack*>(track)->outChannel();
2424   MusECore::MidiPort* mp = &MusEGlobal::midiPorts[outport];
2425   MusECore::MidiController* mc = mp->midiController(num, chan, false);
2426   if(!mc)
2427     return;
2428 
2429   const double lastv = mp->lastValidHWDCtrlState(chan, num);
2430   const double curv = mp->hwDCtrlState(chan, num);
2431 
2432   if(MusECore::MidiController::dValIsUnknown(curv))
2433   {
2434     // If no value has ever been set yet, use the current knob value
2435     //  (or the controller's initial value?) to 'turn on' the controller.
2436     if(MusECore::MidiController::dValIsUnknown(lastv))
2437     {
2438       double slv = slider->value();
2439       if(_preferMidiVolumeDb)
2440         slv = double(mc->maxVal()) * muse_db2val(slv / 2.0);
2441       if(slv < double(mc->minVal()))
2442         slv = mc->minVal();
2443       if(slv > double(mc->maxVal()))
2444         slv = mc->maxVal();
2445       slv += double(mc->bias());
2446 
2447       mp->putControllerValue(outport, chan, num, slv, false);
2448     }
2449     else
2450     {
2451       mp->putControllerValue(outport, chan, num, lastv, false);
2452     }
2453   }
2454   else
2455   {
2456     if(mp->hwCtrlState(chan, num) != MusECore::CTRL_VAL_UNKNOWN)
2457       mp->putHwCtrlEvent(MusECore::MidiPlayEvent(MusEGlobal::audio->curFrame(), outport, chan,
2458                                                   MusECore::ME_CONTROLLER,
2459                                                   num,
2460                                                   MusECore::CTRL_VAL_UNKNOWN));
2461   }
2462 }
2463 
2464 //---------------------------------------------------------
2465 //   offToggled
2466 //---------------------------------------------------------
2467 
offToggled(bool val)2468 void MidiStrip::offToggled(bool val)
2469       {
2470       if(!track)
2471         return;
2472       // This is a minor operation easily manually undoable. Let's not clog the undo list with it.
2473       MusECore::PendingOperationList operations;
2474       operations.add(MusECore::PendingOperationItem(track, val, MusECore::PendingOperationItem::SetTrackOff));
2475       MusEGlobal::audio->msgExecutePendingOperations(operations, true);
2476       }
2477 
2478 //---------------------------------------------------------
2479 //   heartBeat
2480 //---------------------------------------------------------
2481 
heartBeat()2482 void MidiStrip::heartBeat()
2483       {
2484       inHeartBeat = true;
2485 
2486       // Try to avoid calling MidiInstrument::getPatchName too often.
2487       if(++_heartBeatCounter >= 10)
2488         _heartBeatCounter = 0;
2489 
2490       if(track && track->isMidiTrack())
2491       {
2492         int act = track->activity();
2493         double m_val = slider->value();
2494 
2495         if(_preferMidiVolumeDb)
2496         {
2497           MusECore::MidiTrack* t = static_cast<MusECore::MidiTrack*>(track);
2498           const int port = t->outPort();
2499           MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
2500           const int chan = t->outChannel();
2501           MusECore::MidiController* mctl = mp->midiController(MusECore::CTRL_VOLUME, chan, false);
2502           if(!mctl)
2503               return;
2504 
2505           m_val = double(mctl->maxVal()) * muse_db2val(m_val / 2.0);
2506           m_val += double(mctl->bias());
2507 
2508           if(m_val < double(mctl->minVal()))
2509             m_val = double(mctl->minVal());
2510           if(m_val > double(mctl->maxVal()))
2511             m_val = double(mctl->maxVal());
2512         }
2513 
2514         double dact = double(act) * (m_val / 127.0);
2515 
2516         if((int)dact > track->lastActivity())
2517           track->setLastActivity((int)dact);
2518 
2519         if(meter[0])
2520           meter[0]->setVal(dact, track->lastActivity(), false);
2521 
2522         // Gives reasonable decay with gui update set to 20/sec.
2523         if(act)
2524           track->setActivity((int)((double)act * 0.8));
2525       }
2526 
2527       updateControls();
2528 
2529       _upperRack->updateComponents();
2530       _infoRack->updateComponents();
2531       _lowerRack->updateComponents();
2532 
2533       //if(_recMonitor && _recMonitor->isChecked() && MusEGlobal::blinkTimerPhase != _recMonitor->blinkPhase())
2534       //  _recMonitor->setBlinkPhase(MusEGlobal::blinkTimerPhase);
2535 
2536       Strip::heartBeat();
2537       inHeartBeat = false;
2538       }
2539 
2540 //---------------------------------------------------------
2541 //   updateControls
2542 //---------------------------------------------------------
2543 
updateControls()2544 void MidiStrip::updateControls()
2545 {
2546   MusECore::MidiTrack* mt = dynamic_cast<MusECore::MidiTrack*>(track);
2547   if (!mt)
2548       return;
2549 
2550   const int channel  = mt->outChannel();
2551   const int port  = mt->outPort();
2552   if(channel < 0 || channel >= MusECore::MUSE_MIDI_CHANNELS || port < 0 || port >= MusECore::MIDI_PORTS)
2553     return;
2554 
2555   MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
2556   MusECore::MidiCtrlValListList* mcvll = mp->controller();
2557 
2558   MusECore::ciMidiCtrlValList imcvl = mcvll->find(channel, MusECore::CTRL_VOLUME);
2559   const bool enable = imcvl != mcvll->end() && !mt->off();
2560   if(slider->isEnabled() != enable)
2561     slider->setEnabled(enable);
2562   if(sl->isEnabled() != enable)
2563     sl->setEnabled(enable);
2564 
2565   if(enable)
2566   {
2567     MusECore::MidiCtrlValList* mcvl = imcvl->second;
2568     double d_hwVal = mcvl->hwDVal();
2569     int max = 127;
2570     int bias = 0;
2571     MusECore::MidiController* mc = mp->midiController(MusECore::CTRL_VOLUME, channel, false);
2572     if(mc)
2573     {
2574       max = mc->maxVal();
2575       bias = mc->bias();
2576     }
2577 
2578     if(mcvl->hwValIsUnknown())
2579     {
2580       sl->setValue(sl->off() - 1.0);
2581       volume = MusECore::CTRL_VAL_UNKNOWN;
2582 
2583       d_hwVal = mcvl->lastValidHWDVal();
2584       if(mcvl->lastHwValIsUnknown())
2585       {
2586 // TODO
2587 //         if(!control->isOff())
2588 //         {
2589 //           control->blockSignals(true);
2590 //           control->setOff(true);
2591 //           control->blockSignals(false);
2592 //         }
2593       }
2594       else
2595       {
2596         d_hwVal -= double(bias);
2597 
2598         double slider_v;
2599         if(d_hwVal <= 0.0)
2600         {
2601           if(_preferMidiVolumeDb)
2602             slider_v = MusEGlobal::config.minSlider;
2603           else
2604             slider_v = 0.0;
2605         }
2606         else
2607         {
2608           if(_preferMidiVolumeDb)
2609           {
2610             slider_v = muse_val2dbr(d_hwVal / double(max)) * 2.0;
2611             if(slider_v < MusEGlobal::config.minSlider)
2612               slider_v = MusEGlobal::config.minSlider;
2613           }
2614           else
2615             slider_v = d_hwVal;
2616         }
2617 
2618         if(slider_v != slider->value())
2619         {
2620           slider->blockSignals(true);
2621           slider->setValue(slider_v);
2622           slider->blockSignals(false);
2623         }
2624       }
2625     }
2626     else
2627     {
2628       double d_vol = d_hwVal;
2629       d_hwVal -= double(bias);
2630       if(d_hwVal != volume)
2631       {
2632         double slider_v;
2633         if(d_hwVal <= 0.0)
2634         {
2635           if(_preferMidiVolumeDb)
2636             slider_v = MusEGlobal::config.minSlider;
2637           else
2638             slider_v = 0.0;
2639         }
2640         else
2641         {
2642           if(_preferMidiVolumeDb)
2643           {
2644             slider_v = muse_val2dbr(d_hwVal / double(max)) * 2.0;
2645             if(slider_v < MusEGlobal::config.minSlider)
2646               slider_v = MusEGlobal::config.minSlider;
2647           }
2648           else
2649             slider_v = d_hwVal;
2650         }
2651 
2652         if(slider_v != slider->value())
2653         {
2654           slider->blockSignals(true);
2655           slider->setValue(slider_v);
2656           slider->blockSignals(false);
2657         }
2658 
2659         if(d_vol <= 0.0)
2660           sl->setValue(sl->minValue() - 0.5 * (sl->minValue() - sl->off()));
2661         else
2662         {
2663           double sl_v = _preferMidiVolumeDb ? (muse_val2dbr(d_vol / double(max)) * 2.0) : d_vol;
2664 
2665           if(sl_v > sl->maxValue())
2666             sl->setValue(sl->maxValue());
2667           else
2668             sl->setValue(sl_v);
2669         }
2670 
2671         volume = d_hwVal;
2672       }
2673     }
2674   }
2675 }
2676 
2677 //---------------------------------------------------------
2678 //   ctrlChanged
2679 //---------------------------------------------------------
2680 
ctrlChanged(double v,bool off,int num,int scrollMode)2681 void MidiStrip::ctrlChanged(double v, bool off, int num, int scrollMode)
2682     {
2683       if (inHeartBeat)
2684             return;
2685       if(!track || !track->isMidiTrack())
2686         return;
2687 
2688       MusECore::MidiTrack* t = static_cast<MusECore::MidiTrack*>(track);
2689       int port     = t->outPort();
2690       int chan  = t->outChannel();
2691       MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
2692       MusECore::MidiController* mctl = mp->midiController(num, chan, false);
2693       if(mctl)
2694       {
2695         double m_val = v;
2696         if(_preferMidiVolumeDb)
2697           m_val = double(mctl->maxVal()) * muse_db2val(m_val / 2.0);
2698 
2699         if(off || (m_val < double(mctl->minVal())) || (m_val > double(mctl->maxVal())))
2700         {
2701           if(mp->hwCtrlState(chan, num) != MusECore::CTRL_VAL_UNKNOWN)
2702             mp->putHwCtrlEvent(MusECore::MidiPlayEvent(MusEGlobal::audio->curFrame(), port, chan,
2703                                                       MusECore::ME_CONTROLLER,
2704                                                       num,
2705                                                       MusECore::CTRL_VAL_UNKNOWN));
2706         }
2707         else
2708         {
2709           m_val += double(mctl->bias());
2710           mp->putControllerValue(port, chan, num, m_val, false);
2711         }
2712       }
2713 
2714       componentChanged(ComponentRack::controllerComponent, v, off, num, scrollMode);
2715     }
2716 
2717 //---------------------------------------------------------
2718 //   volLabelChanged
2719 //---------------------------------------------------------
2720 
volLabelChanged(double val)2721 void MidiStrip::volLabelChanged(double val)
2722 {
2723   ctrlChanged(val, false, MusECore::CTRL_VOLUME, SliderBase::ScrNone);
2724 }
2725 
2726 //---------------------------------------------------------
2727 //   setVolume
2728 //---------------------------------------------------------
2729 
setVolume(double val,int id,int scrollMode)2730 void MidiStrip::setVolume(double val, int id, int scrollMode)
2731 {
2732       DEBUG_MIDI_STRIP("Vol %d\n", lrint(val));
2733       ctrlChanged(val, false, id, scrollMode);
2734 }
2735 
2736 //---------------------------------------------------------
2737 //   volumePressed
2738 //---------------------------------------------------------
2739 
volumePressed(double val,int id)2740 void MidiStrip::volumePressed(double val, int id)
2741       {
2742       DEBUG_MIDI_STRIP(stderr, "MidiStrip::volumePressed\n");
2743       if(!track || !track->isMidiTrack())
2744         return;
2745       componentPressed(ComponentRack::controllerComponent, val, id);
2746       }
2747 
2748 //---------------------------------------------------------
2749 //   volumeReleased
2750 //---------------------------------------------------------
2751 
volumeReleased(double val,int id)2752 void MidiStrip::volumeReleased(double val, int id)
2753       {
2754       DEBUG_MIDI_STRIP(stderr, "MidiStrip::volumeReleased\n");
2755       if(!track || !track->isMidiTrack())
2756         return;
2757       componentReleased(ComponentRack::controllerComponent, val, id);
2758       }
2759 
2760 
2761 //---------------------------------------------------------
2762 //   iRoutePressed
2763 //---------------------------------------------------------
2764 
iRoutePressed()2765 void MidiStrip::iRoutePressed()
2766 {
2767   RoutePopupMenu* pup = new RoutePopupMenu(0, false, _broadcastChanges);
2768   pup->exec(QCursor::pos(), track, false);
2769   delete pup;
2770   iR->setDown(false);
2771 }
2772 
2773 //---------------------------------------------------------
2774 //   oRoutePressed
2775 //---------------------------------------------------------
2776 
oRoutePressed()2777 void MidiStrip::oRoutePressed()
2778 {
2779   RoutePopupMenu* pup = new RoutePopupMenu(0, true, _broadcastChanges);
2780   pup->exec(QCursor::pos(), track, true);
2781   delete pup;
2782   oR->setDown(false);
2783 }
2784 
incVolume(int incrementValue)2785 void MidiStrip::incVolume(int incrementValue)
2786 {
2787   if(!track || !track->isMidiTrack())
2788     return;
2789 
2790   const int id = MusECore::CTRL_VOLUME;
2791 
2792   MusECore::MidiTrack* t = static_cast<MusECore::MidiTrack*>(track);
2793   const int port     = t->outPort();
2794   const int chan  = t->outChannel();
2795   MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
2796   MusECore::MidiController* mctl = mp->midiController(id, chan, false);
2797 
2798   if(mctl)
2799   {
2800     // Get the slider's current value.
2801     const double prev_val = slider->value();
2802     double d_prev_val = prev_val;
2803     if(_preferMidiVolumeDb)
2804       d_prev_val = double(mctl->maxVal()) * muse_db2val(d_prev_val / 2.0);
2805 
2806     // Increment the slider. Do not allow signalling.
2807     slider->blockSignals(true);
2808     slider->incValue(incrementValue * 2);
2809     slider->blockSignals(false);
2810     // Now grab the control's new value.
2811     const double new_val = slider->value();
2812 
2813     double d_new_val = new_val;
2814     if(_preferMidiVolumeDb)
2815       d_new_val = double(mctl->maxVal()) * muse_db2val(d_new_val / 2.0);
2816 
2817     if((d_new_val < double(mctl->minVal())) || (d_new_val > double(mctl->maxVal())))
2818     {
2819       if(mp->hwCtrlState(chan, id) != MusECore::CTRL_VAL_UNKNOWN)
2820         mp->putHwCtrlEvent(MusECore::MidiPlayEvent(MusEGlobal::audio->curFrame(), port, chan,
2821                                                     MusECore::ME_CONTROLLER,
2822                                                     id,
2823                                                     MusECore::CTRL_VAL_UNKNOWN));
2824     }
2825     else
2826     {
2827       d_new_val += double(mctl->bias());
2828       mp->putControllerValue(port, chan, id, d_new_val, false);
2829     }
2830 
2831     componentIncremented(ComponentRack::controllerComponent,
2832                         prev_val, new_val,
2833                         false, id, Slider::ScrNone);
2834   }
2835 }
2836 
incPan(int v)2837 void MidiStrip::incPan(int v)
2838 {
2839   if(!track || !track->isMidiTrack())
2840     return;
2841 
2842   const int id = MusECore::CTRL_PANPOT;
2843 
2844   ComponentRack* rack = 0;
2845   ComponentWidget* cw = 0;
2846   // Be sure to search all racks. Even if pan is in multiple racks, only one hit is
2847   //  needed since after the value is set, the other pan controls will be updated too.
2848   if((cw = _upperRack->findComponent(ComponentRack::controllerComponent, -1, id)))
2849     rack = _upperRack;
2850   else if((cw = _infoRack->findComponent(ComponentRack::controllerComponent, -1, id)))
2851     rack = _infoRack;
2852   else if((cw = _lowerRack->findComponent(ComponentRack::controllerComponent, -1, id)))
2853     rack = _lowerRack;
2854 
2855   if(!cw || !rack)
2856     return;
2857 
2858   MusECore::MidiTrack* t = static_cast<MusECore::MidiTrack*>(track);
2859   const int port     = t->outPort();
2860   const int chan  = t->outChannel();
2861   MusECore::MidiPort* mp = &MusEGlobal::midiPorts[port];
2862   MusECore::MidiController* mctl = mp->midiController(id, chan, false);
2863   if(mctl)
2864   {
2865     // Get the component's current value.
2866     double prev_val = rack->componentValue(*cw);
2867     // Now increment the component. Do not allow signalling.
2868     rack->incComponentValue(*cw, v, true);
2869     // Now grab its value.
2870     const double d_new_val = rack->componentValue(*cw);
2871 
2872     double d_fin_val = d_new_val;
2873 
2874     if((d_fin_val < double(mctl->minVal())) || (d_fin_val > double(mctl->maxVal())))
2875     {
2876       if(mp->hwCtrlState(chan, MusECore::CTRL_PANPOT) != MusECore::CTRL_VAL_UNKNOWN)
2877         mp->putHwCtrlEvent(MusECore::MidiPlayEvent(MusEGlobal::audio->curFrame(), port, chan,
2878                                                     MusECore::ME_CONTROLLER,
2879                                                     id,
2880                                                     MusECore::CTRL_VAL_UNKNOWN));
2881     }
2882     else
2883     {
2884       d_fin_val += double(mctl->bias());
2885       mp->putControllerValue(port, chan, id, d_fin_val, false);
2886     }
2887 
2888     componentIncremented(ComponentRack::controllerComponent,
2889                          prev_val, d_new_val,
2890                          false, id, Slider::ScrNone);
2891   }
2892 }
2893 
2894 } // namespace MusEGui
2895