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