Adds support for MIDI CC events inside LMMS (#5581)
This commit is contained in:
BIN
data/themes/classic/midi_cc_rack.png
Normal file
BIN
data/themes/classic/midi_cc_rack.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 554 B |
BIN
data/themes/default/midi_cc_rack.png
Normal file
BIN
data/themes/default/midi_cc_rack.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 554 B |
@@ -50,6 +50,7 @@ public:
|
||||
}
|
||||
|
||||
void setModel( Model* model, bool isOldModelValid = true ) override;
|
||||
void unsetModel() override;
|
||||
|
||||
template<typename T>
|
||||
inline T value() const
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "GroupBox.h"
|
||||
#include "InstrumentFunctions.h"
|
||||
#include "InstrumentSoundShaping.h"
|
||||
#include "Midi.h"
|
||||
#include "MidiCCRackView.h"
|
||||
#include "MidiEventProcessor.h"
|
||||
#include "MidiPort.h"
|
||||
#include "NotePlayHandle.h"
|
||||
@@ -228,7 +230,6 @@ signals:
|
||||
void newNote();
|
||||
void endNote();
|
||||
|
||||
|
||||
protected:
|
||||
QString nodeName() const override
|
||||
{
|
||||
@@ -247,6 +248,8 @@ protected slots:
|
||||
|
||||
|
||||
private:
|
||||
void processCCEvent(int controller);
|
||||
|
||||
MidiPort m_midiPort;
|
||||
|
||||
NotePlayHandle* m_notes[NumKeys];
|
||||
@@ -286,11 +289,14 @@ private:
|
||||
|
||||
Piano m_piano;
|
||||
|
||||
std::unique_ptr<BoolModel> m_midiCCEnable;
|
||||
std::unique_ptr<FloatModel> m_midiCCModel[MidiControllerCount];
|
||||
|
||||
friend class InstrumentTrackView;
|
||||
friend class InstrumentTrackWindow;
|
||||
friend class NotePlayHandle;
|
||||
friend class InstrumentMiscView;
|
||||
friend class MidiCCRackView;
|
||||
|
||||
} ;
|
||||
|
||||
@@ -334,6 +340,7 @@ protected:
|
||||
|
||||
private slots:
|
||||
void toggleInstrumentWindow( bool _on );
|
||||
void toggleMidiCCRack();
|
||||
void activityIndicatorPressed();
|
||||
void activityIndicatorReleased();
|
||||
|
||||
@@ -361,6 +368,8 @@ private:
|
||||
QAction * m_midiInputAction;
|
||||
QAction * m_midiOutputAction;
|
||||
|
||||
std::unique_ptr<MidiCCRackView> m_midiCCRackView;
|
||||
|
||||
QPoint m_lastPos;
|
||||
|
||||
FadeButton * getActivityIndicator() override
|
||||
|
||||
40
include/MidiCCRackView.h
Normal file
40
include/MidiCCRackView.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef MIDI_CC_RACK_VIEW_H
|
||||
#define MIDI_CC_RACK_VIEW_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "GroupBox.h"
|
||||
#include "Knob.h"
|
||||
#include "Midi.h"
|
||||
#include "SerializingObject.h"
|
||||
|
||||
class InstrumentTrack;
|
||||
|
||||
class MidiCCRackView : public QWidget, public SerializingObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MidiCCRackView(InstrumentTrack * track);
|
||||
~MidiCCRackView() override;
|
||||
|
||||
void saveSettings(QDomDocument & doc, QDomElement & parent) override;
|
||||
void loadSettings(const QDomElement &) override;
|
||||
|
||||
inline QString nodeName() const override
|
||||
{
|
||||
return "MidiCCRackView";
|
||||
}
|
||||
|
||||
private slots:
|
||||
void renameWindow();
|
||||
|
||||
private:
|
||||
InstrumentTrack *m_track;
|
||||
|
||||
GroupBox *m_midiCCGroupBox; // MIDI CC GroupBox (used to enable disable MIDI CC)
|
||||
|
||||
Knob *m_controllerKnob[MidiControllerCount]; // Holds the knob widgets for each controller
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -33,27 +33,30 @@
|
||||
class MidiEvent
|
||||
{
|
||||
public:
|
||||
MidiEvent( MidiEventTypes type = MidiActiveSensing,
|
||||
MidiEvent(MidiEventTypes type = MidiActiveSensing,
|
||||
int8_t channel = 0,
|
||||
int16_t param1 = 0,
|
||||
int16_t param2 = 0,
|
||||
const void* sourcePort = NULL ) :
|
||||
const void* sourcePort = nullptr,
|
||||
bool ignoreOnExport = true) :
|
||||
m_type( type ),
|
||||
m_metaEvent( MidiMetaInvalid ),
|
||||
m_channel( channel ),
|
||||
m_sysExData( NULL ),
|
||||
m_sourcePort( sourcePort )
|
||||
m_sourcePort(sourcePort),
|
||||
m_ignoreOnExport(ignoreOnExport)
|
||||
{
|
||||
m_data.m_param[0] = param1;
|
||||
m_data.m_param[1] = param2;
|
||||
}
|
||||
|
||||
MidiEvent( MidiEventTypes type, const char* sysExData, int dataLen ) :
|
||||
MidiEvent(MidiEventTypes type, const char* sysExData, int dataLen, bool ignoreOnExport = true) :
|
||||
m_type( type ),
|
||||
m_metaEvent( MidiMetaInvalid ),
|
||||
m_channel( 0 ),
|
||||
m_sysExData( sysExData ),
|
||||
m_sourcePort( NULL )
|
||||
m_sourcePort(nullptr),
|
||||
m_ignoreOnExport(ignoreOnExport)
|
||||
{
|
||||
m_data.m_sysExDataLen = dataLen;
|
||||
}
|
||||
@@ -64,7 +67,8 @@ public:
|
||||
m_channel( other.m_channel ),
|
||||
m_data( other.m_data ),
|
||||
m_sysExData( other.m_sysExData ),
|
||||
m_sourcePort( other.m_sourcePort )
|
||||
m_sourcePort(other.m_sourcePort),
|
||||
m_ignoreOnExport(other.m_ignoreOnExport)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -190,6 +194,16 @@ public:
|
||||
setParam( 0, pitchBend );
|
||||
}
|
||||
|
||||
bool ignoreOnExport() const
|
||||
{
|
||||
return m_ignoreOnExport;
|
||||
}
|
||||
|
||||
void setIgnoreOnExport(bool value)
|
||||
{
|
||||
m_ignoreOnExport = value;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
MidiEventTypes m_type; // MIDI event type
|
||||
@@ -205,6 +219,9 @@ private:
|
||||
const char* m_sysExData;
|
||||
const void* m_sourcePort;
|
||||
|
||||
// This helps us ignore MIDI events that shouldn't be processed
|
||||
// during a project export, like physical controller events.
|
||||
bool m_ignoreOnExport;
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
virtual ~ModelView();
|
||||
|
||||
virtual void setModel( Model* model, bool isOldModelValid = true );
|
||||
virtual void unsetModel();
|
||||
|
||||
Model* model()
|
||||
{
|
||||
|
||||
@@ -142,6 +142,31 @@ void AutomatableModelView::setModel( Model* model, bool isOldModelValid )
|
||||
|
||||
|
||||
|
||||
// Unsets the current model by setting a dummy empty model. The dummy model is marked as
|
||||
// "defaultConstructed", so the next call to setModel will delete it.
|
||||
void AutomatableModelView::unsetModel()
|
||||
{
|
||||
if (dynamic_cast<FloatModelView*>(this))
|
||||
{
|
||||
setModel(new FloatModel(0, 0, 0, 1, nullptr, QString(), true));
|
||||
}
|
||||
else if (dynamic_cast<IntModelView*>(this))
|
||||
{
|
||||
setModel(new IntModel(0, 0, 0, nullptr, QString(), true));
|
||||
}
|
||||
else if (dynamic_cast<BoolModelView*>(this))
|
||||
{
|
||||
setModel(new BoolModel(false, nullptr, QString(), true));
|
||||
}
|
||||
else
|
||||
{
|
||||
ModelView::unsetModel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AutomatableModelView::mousePressEvent( QMouseEvent* event )
|
||||
{
|
||||
if( event->button() == Qt::LeftButton && event->modifiers() & Qt::ControlModifier )
|
||||
|
||||
@@ -22,6 +22,7 @@ SET(LMMS_SRCS
|
||||
gui/Lv2ViewBase.cpp
|
||||
gui/MainApplication.cpp
|
||||
gui/MainWindow.cpp
|
||||
gui/MidiCCRackView.cpp
|
||||
gui/MidiSetupWidget.cpp
|
||||
gui/ModelView.cpp
|
||||
gui/PeakControllerDialog.cpp
|
||||
|
||||
133
src/gui/MidiCCRackView.cpp
Normal file
133
src/gui/MidiCCRackView.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* MidiCCRackView.cpp - implementation of the MIDI CC rack widget
|
||||
*
|
||||
* Copyright (c) 2020 Ian Caio <iancaio_dev/at/hotmail.com>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "MidiCCRackView.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QMdiSubWindow>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include "embed.h"
|
||||
#include "GroupBox.h"
|
||||
#include "GuiApplication.h"
|
||||
#include "InstrumentTrack.h"
|
||||
#include "Knob.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Track.h"
|
||||
|
||||
|
||||
MidiCCRackView::MidiCCRackView(InstrumentTrack * track) :
|
||||
QWidget(),
|
||||
m_track(track)
|
||||
{
|
||||
setWindowIcon(embed::getIconPixmap("midi_cc_rack"));
|
||||
setWindowTitle(tr("MIDI CC Rack - %1").arg(m_track->name()));
|
||||
|
||||
QMdiSubWindow * subWin = gui->mainWindow()->addWindowedWidget(this);
|
||||
|
||||
// Remove maximize button
|
||||
Qt::WindowFlags flags = subWin->windowFlags();
|
||||
flags &= ~Qt::WindowMaximizeButtonHint;
|
||||
subWin->setWindowFlags(flags);
|
||||
|
||||
// Adjust window attributes, sizing and position
|
||||
subWin->setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
subWin->resize(350, 300);
|
||||
subWin->setFixedWidth(350);
|
||||
subWin->setMinimumHeight(300);
|
||||
subWin->hide();
|
||||
|
||||
// Main window layout
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
||||
|
||||
// Knobs GroupBox - Here we have the MIDI CC controller knobs for the selected track
|
||||
m_midiCCGroupBox = new GroupBox(tr("MIDI CC Knobs:"));
|
||||
|
||||
// Layout to keep scrollable area under the GroupBox header
|
||||
QVBoxLayout *knobsGroupBoxLayout = new QVBoxLayout();
|
||||
knobsGroupBoxLayout->setContentsMargins(5, 16, 5, 5);
|
||||
|
||||
m_midiCCGroupBox->setLayout(knobsGroupBoxLayout);
|
||||
|
||||
// Scrollable area + widget + its layout that will have all the knobs
|
||||
QScrollArea *knobsScrollArea = new QScrollArea();
|
||||
QWidget *knobsArea = new QWidget();
|
||||
QGridLayout *knobsAreaLayout = new QGridLayout();
|
||||
|
||||
knobsArea->setLayout(knobsAreaLayout);
|
||||
knobsScrollArea->setWidget(knobsArea);
|
||||
knobsScrollArea->setWidgetResizable(true);
|
||||
|
||||
knobsGroupBoxLayout->addWidget(knobsScrollArea);
|
||||
|
||||
// Adds the controller knobs
|
||||
for (int i = 0; i < MidiControllerCount; ++i)
|
||||
{
|
||||
m_controllerKnob[i] = new Knob(knobBright_26);
|
||||
m_controllerKnob[i]->setLabel(tr("CC %1").arg(i));
|
||||
knobsAreaLayout->addWidget(m_controllerKnob[i], i/4, i%4);
|
||||
}
|
||||
|
||||
// Set all the models
|
||||
// Set the LED button to enable/disable the track midi cc
|
||||
m_midiCCGroupBox->setModel(m_track->m_midiCCEnable.get());
|
||||
|
||||
// Set the model for each Knob
|
||||
for (int i = 0; i < MidiControllerCount; ++i)
|
||||
{
|
||||
m_controllerKnob[i]->setModel(m_track->m_midiCCModel[i].get());
|
||||
}
|
||||
|
||||
// Connection to update the name of the track on the label
|
||||
connect(m_track, SIGNAL(nameChanged()),
|
||||
this, SLOT(renameWindow()));
|
||||
|
||||
// Adding everything to the main layout
|
||||
mainLayout->addWidget(m_midiCCGroupBox);
|
||||
}
|
||||
|
||||
MidiCCRackView::~MidiCCRackView()
|
||||
{
|
||||
if(parentWidget())
|
||||
{
|
||||
parentWidget()->hide();
|
||||
parentWidget()->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void MidiCCRackView::renameWindow()
|
||||
{
|
||||
setWindowTitle(tr("MIDI CC Rack - %1").arg(m_track->name()));
|
||||
}
|
||||
|
||||
void MidiCCRackView::saveSettings(QDomDocument & doc, QDomElement & parent)
|
||||
{
|
||||
}
|
||||
|
||||
void MidiCCRackView::loadSettings(const QDomElement &)
|
||||
{
|
||||
}
|
||||
@@ -74,6 +74,16 @@ void ModelView::setModel( Model* model, bool isOldModelValid )
|
||||
|
||||
|
||||
|
||||
// Unsets the current model by setting a dummy empty model. The dummy model is marked as
|
||||
// "defaultConstructed", so the next call to setModel will delete it.
|
||||
void ModelView::unsetModel()
|
||||
{
|
||||
setModel(new Model(nullptr, QString(), true));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void ModelView::doConnections()
|
||||
{
|
||||
if( m_model != NULL )
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
#include "StringPairDrag.h"
|
||||
#include "TrackContainerView.h"
|
||||
#include "TrackLabelButton.h"
|
||||
#include "MidiCCRackView.h"
|
||||
|
||||
|
||||
const int INSTRUMENT_WIDTH = 254;
|
||||
@@ -119,6 +120,21 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) :
|
||||
}
|
||||
|
||||
|
||||
// Initialize the m_midiCCEnabled variable, but it's actually going to be connected
|
||||
// to a LedButton
|
||||
m_midiCCEnable = std::make_unique<BoolModel>(false, nullptr, tr("Enable/Disable MIDI CC"));
|
||||
|
||||
// Initialize the MIDI CC controller models and connect them to the method that processes
|
||||
// the midi cc events
|
||||
for (int i = 0; i < MidiControllerCount; ++i)
|
||||
{
|
||||
m_midiCCModel[i] = std::make_unique<FloatModel>(0.0f, 0.0f, 127.0f, 1.0f,
|
||||
nullptr, tr("CC Controller %1").arg(i));
|
||||
|
||||
connect(m_midiCCModel[i].get(), &FloatModel::dataChanged,
|
||||
this, [this, i]{ processCCEvent(i); }, Qt::DirectConnection);
|
||||
}
|
||||
|
||||
setName( tr( "Default preset" ) );
|
||||
|
||||
connect( &m_baseNoteModel, SIGNAL( dataChanged() ),
|
||||
@@ -242,9 +258,27 @@ MidiEvent InstrumentTrack::applyMasterKey( const MidiEvent& event )
|
||||
|
||||
|
||||
|
||||
void InstrumentTrack::processCCEvent(int controller)
|
||||
{
|
||||
// Does nothing if the LED is disabled
|
||||
if (!m_midiCCEnable->value()) { return; }
|
||||
|
||||
uint8_t channel = static_cast<uint8_t>(midiPort()->realOutputChannel());
|
||||
uint16_t cc = static_cast<uint16_t>(controller);
|
||||
uint16_t value = static_cast<uint16_t>(m_midiCCModel[controller]->value());
|
||||
|
||||
// Process the MIDI CC event as an input event but with ignoreOnExport set to false
|
||||
// so we can know LMMS generated the event, not a controller, and can process it during
|
||||
// the project export
|
||||
processInEvent(MidiEvent(MidiControlChange, channel, cc, value, NULL, false));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void InstrumentTrack::processInEvent( const MidiEvent& event, const TimePos& time, f_cnt_t offset )
|
||||
{
|
||||
if( Engine::getSong()->isExporting() )
|
||||
if (Engine::getSong()->isExporting() && event.ignoreOnExport())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -373,9 +407,11 @@ void InstrumentTrack::processInEvent( const MidiEvent& event, const TimePos& tim
|
||||
break;
|
||||
}
|
||||
|
||||
if( eventHandled == false && instrument()->handleMidiEvent( event, time, offset ) == false )
|
||||
// If the event wasn't handled, check if there's a loaded instrument and if so send the
|
||||
// event to it. If it returns false means the instrument didn't handle the event, so we trigger a warning.
|
||||
if (eventHandled == false && !(instrument() && instrument()->handleMidiEvent(event, time, offset)))
|
||||
{
|
||||
qWarning( "InstrumentTrack: unhandled MIDI event %d", event.type() );
|
||||
qWarning("InstrumentTrack: unhandled MIDI event %d", event.type());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -740,6 +776,15 @@ void InstrumentTrack::saveTrackSpecificSettings( QDomDocument& doc, QDomElement
|
||||
m_baseNoteModel.saveSettings( doc, thisElement, "basenote" );
|
||||
m_useMasterPitchModel.saveSettings( doc, thisElement, "usemasterpitch");
|
||||
|
||||
// Save MIDI CC stuff
|
||||
m_midiCCEnable->saveSettings(doc, thisElement, "enablecc");
|
||||
QDomElement midiCC = doc.createElement("midicontrollers");
|
||||
thisElement.appendChild(midiCC);
|
||||
for (int i = 0; i < MidiControllerCount; ++i)
|
||||
{
|
||||
m_midiCCModel[i]->saveSettings(doc, midiCC, "cc" + QString::number(i));
|
||||
}
|
||||
|
||||
if( m_instrument != NULL )
|
||||
{
|
||||
QDomElement i = doc.createElement( "instrument" );
|
||||
@@ -798,6 +843,10 @@ void InstrumentTrack::loadTrackSpecificSettings( const QDomElement & thisElement
|
||||
// clear effect-chain just in case we load an old preset without FX-data
|
||||
m_audioPort.effects()->clear();
|
||||
|
||||
// We set MIDI CC enable to false so the knobs don't trigger MIDI CC events while
|
||||
// they are being loaded. After all knobs are loaded we load the right value of m_midiCCEnable.
|
||||
m_midiCCEnable->setValue(false);
|
||||
|
||||
QDomNode node = thisElement.firstChild();
|
||||
while( !node.isNull() )
|
||||
{
|
||||
@@ -842,6 +891,13 @@ void InstrumentTrack::loadTrackSpecificSettings( const QDomElement & thisElement
|
||||
emit instrumentChanged();
|
||||
}
|
||||
}
|
||||
else if (node.nodeName() == "midicontrollers")
|
||||
{
|
||||
for (int i = 0; i < MidiControllerCount; ++i)
|
||||
{
|
||||
m_midiCCModel[i]->loadSettings(node.toElement(), "cc" + QString::number(i));
|
||||
}
|
||||
}
|
||||
// compat code - if node-name doesn't match any known
|
||||
// one, we assume that it is an instrument-plugin
|
||||
// which we'll try to load
|
||||
@@ -862,6 +918,10 @@ void InstrumentTrack::loadTrackSpecificSettings( const QDomElement & thisElement
|
||||
}
|
||||
node = node.nextSibling();
|
||||
}
|
||||
|
||||
// Load the right value of m_midiCCEnable
|
||||
m_midiCCEnable->loadSettings(thisElement, "enablecc");
|
||||
|
||||
updatePitchRange();
|
||||
unlock();
|
||||
}
|
||||
@@ -997,7 +1057,7 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV
|
||||
m_panningKnob = new Knob( knobSmall_17, getTrackSettingsWidget(),
|
||||
tr( "Panning" ) );
|
||||
m_panningKnob->setModel( &_it->m_panningModel );
|
||||
m_panningKnob->setHintText( tr( "Panning:" ), "%" );
|
||||
m_panningKnob->setHintText(tr("Panning:"), "%");
|
||||
m_panningKnob->move( widgetWidth-24, 2 );
|
||||
m_panningKnob->setLabel( tr( "PAN" ) );
|
||||
m_panningKnob->show();
|
||||
@@ -1037,6 +1097,11 @@ InstrumentTrackView::InstrumentTrackView( InstrumentTrack * _it, TrackContainerV
|
||||
m_midiInputAction->setText( tr( "Input" ) );
|
||||
m_midiOutputAction->setText( tr( "Output" ) );
|
||||
|
||||
QAction *midiRackAction = m_midiMenu->addAction(tr("Open/Close MIDI CC Rack"));
|
||||
midiRackAction->setIcon(embed::getIconPixmap("midi_cc_rack"));
|
||||
connect(midiRackAction, SIGNAL(triggered()),
|
||||
this, SLOT(toggleMidiCCRack()));
|
||||
|
||||
m_activityIndicator = new FadeButton( QApplication::palette().color( QPalette::Active,
|
||||
QPalette::Background),
|
||||
QApplication::palette().color( QPalette::Active,
|
||||
@@ -1074,6 +1139,29 @@ InstrumentTrackView::~InstrumentTrackView()
|
||||
|
||||
|
||||
|
||||
void InstrumentTrackView::toggleMidiCCRack()
|
||||
{
|
||||
// Lazy creation: midiCCRackView is only created when accessed the first time.
|
||||
// this->model() returns pointer to the InstrumentTrack who owns this InstrumentTrackView.
|
||||
if (!m_midiCCRackView)
|
||||
{
|
||||
m_midiCCRackView = std::unique_ptr<MidiCCRackView>(new MidiCCRackView(this->model()));
|
||||
}
|
||||
|
||||
if (m_midiCCRackView->parentWidget()->isVisible())
|
||||
{
|
||||
m_midiCCRackView->parentWidget()->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_midiCCRackView->parentWidget()->show();
|
||||
m_midiCCRackView->show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
InstrumentTrackWindow * InstrumentTrackView::topLevelInstrumentTrackWindow()
|
||||
{
|
||||
InstrumentTrackWindow * w = NULL;
|
||||
|
||||
Reference in New Issue
Block a user