diff --git a/include/InstrumentTrack.h b/include/InstrumentTrack.h index b30d5cb21c9..29348b98eb6 100644 --- a/include/InstrumentTrack.h +++ b/include/InstrumentTrack.h @@ -219,6 +219,8 @@ class LMMS_EXPORT InstrumentTrack : public Track, public MidiEventProcessor return m_previewMode; } + void autoAssignMidiDevice( bool ); + signals: void instrumentChanged(); void midiNoteOn( const Note& ); @@ -260,6 +262,9 @@ protected slots: bool m_previewMode; + bool m_hasAutoMidiDev; + static InstrumentTrack *s_autoAssignedTrack; + IntModel m_baseNoteModel; NotePlayHandleList m_processHandles; diff --git a/include/PianoRoll.h b/include/PianoRoll.h index ef32f19eccf..bf8aa983c06 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -178,6 +178,7 @@ class PianoRoll : public QWidget void resizeEvent( QResizeEvent * re ) override; void wheelEvent( QWheelEvent * we ) override; void focusOutEvent( QFocusEvent * ) override; + void focusInEvent( QFocusEvent * ) override; int getKey( int y ) const; void drawNoteRect( QPainter & p, int x, int y, diff --git a/include/PianoView.h b/include/PianoView.h index b793ee76813..2f2fea2c935 100644 --- a/include/PianoView.h +++ b/include/PianoView.h @@ -56,6 +56,7 @@ class PianoView : public QWidget, public ModelView void mouseReleaseEvent( QMouseEvent * me ) override; void mouseMoveEvent( QMouseEvent * me ) override; void focusOutEvent( QFocusEvent * _fe ) override; + void focusInEvent( QFocusEvent * fe ) override; void resizeEvent( QResizeEvent * _event ) override; diff --git a/include/SetupDialog.h b/include/SetupDialog.h index 80a22d69c35..fa0ebde6af6 100644 --- a/include/SetupDialog.h +++ b/include/SetupDialog.h @@ -175,6 +175,7 @@ private slots: QComboBox * m_midiInterfaces; MswMap m_midiIfaceSetupWidgets; trMap m_midiIfaceNames; + QComboBox * m_assignableMidiDevices; // Paths settings widgets. QString m_workingDir; diff --git a/src/gui/PianoView.cpp b/src/gui/PianoView.cpp index c5f1b623fca..58eb59dafbc 100644 --- a/src/gui/PianoView.cpp +++ b/src/gui/PianoView.cpp @@ -673,10 +673,17 @@ void PianoView::focusOutEvent( QFocusEvent * ) m_piano->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOff, -1, i, 0 ) ); m_piano->setKeyState( i, false ); } + + update(); } +void PianoView::focusInEvent( QFocusEvent * ) +{ + m_piano->instrumentTrack()->autoAssignMidiDevice(true); +} + /*! \brief update scrollbar range after resize diff --git a/src/gui/SetupDialog.cpp b/src/gui/SetupDialog.cpp index 6de547b5ae2..2a7aeba7294 100644 --- a/src/gui/SetupDialog.cpp +++ b/src/gui/SetupDialog.cpp @@ -677,9 +677,32 @@ SetupDialog::SetupDialog(ConfigTabs tab_to_open) : this, SLOT(midiInterfaceChanged(const QString &))); + // MIDI autoassign tab. + TabWidget * midiAutoAssign_tw = new TabWidget( + tr("Automatically assign MIDI controller to selected track"), midi_w); + midiAutoAssign_tw->setFixedHeight(56); + + m_assignableMidiDevices = new QComboBox(midiAutoAssign_tw); + m_assignableMidiDevices->setGeometry(10, 20, 240, 28); + m_assignableMidiDevices->addItem("none"); + if ( !Engine::mixer()->midiClient()->isRaw() ) + { + m_assignableMidiDevices->addItems(Engine::mixer()->midiClient()->readablePorts()); + } + else + { + m_assignableMidiDevices->addItem("all"); + } + int current = m_assignableMidiDevices->findText(ConfigManager::inst()->value("midi", "midiautoassign")); + if (current >= 0) + { + m_assignableMidiDevices->setCurrentIndex(current); + } + // MIDI layout ordering. midi_layout->addWidget(midiiface_tw); midi_layout->addWidget(ms_w); + midi_layout->addWidget(midiAutoAssign_tw); midi_layout->addStretch(); @@ -917,6 +940,8 @@ void SetupDialog::accept() QString::number(m_bufferSize)); ConfigManager::inst()->setValue("mixer", "mididev", m_midiIfaceNames[m_midiInterfaces->currentText()]); + ConfigManager::inst()->setValue("midi", "midiautoassign", + m_assignableMidiDevices->currentText()); ConfigManager::inst()->setWorkingDir(QDir::fromNativeSeparators(m_workingDir)); diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 5e9ec8af067..e0f4fdadff0 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -3600,6 +3600,14 @@ void PianoRoll::focusOutEvent( QFocusEvent * ) update(); } +void PianoRoll::focusInEvent( QFocusEvent * ) +{ + if ( hasValidPattern() ) + { + // Assign midi device + m_pattern->instrumentTrack()->autoAssignMidiDevice(true); + } +} diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 8ed7d2b85fc..855902fe961 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -97,6 +97,7 @@ InstrumentTrack::InstrumentTrack( TrackContainer* tc ) : m_sustainPedalPressed( false ), m_silentBuffersProcessed( false ), m_previewMode( false ), + m_hasAutoMidiDev( false ), m_baseNoteModel( 0, 0, KeysPerOctave * NumOctaves - 1, this, tr( "Base note" ) ), m_volumeModel( DefaultVolume, MinVolume, MaxVolume, 0.1f, this, tr( "Volume" ) ), @@ -149,6 +150,13 @@ int InstrumentTrack::baseNote() const InstrumentTrack::~InstrumentTrack() { + // De-assign midi device + if (m_hasAutoMidiDev) + { + autoAssignMidiDevice(false); + s_autoAssignedTrack = NULL; + } + // kill all running notes and the iph silenceAllNotes( true ); @@ -766,7 +774,13 @@ void InstrumentTrack::saveTrackSpecificSettings( QDomDocument& doc, QDomElement if (Engine::getSong()->isSavingProject() && !Engine::getSong()->getSaveOptions().discardMIDIConnections.value()) { + // Don't save auto assigned midi device connection + bool hasAuto = m_hasAutoMidiDev; + autoAssignMidiDevice(false); + m_midiPort.saveState( doc, thisElement ); + + autoAssignMidiDevice(hasAuto); } m_audioPort.effects()->saveState( doc, thisElement ); @@ -914,6 +928,38 @@ Instrument * InstrumentTrack::loadInstrument(const QString & _plugin_name, +InstrumentTrack *InstrumentTrack::s_autoAssignedTrack = NULL; + +/*! \brief Automatically assign a midi controller to this track, based on the midiautoassign setting + * + * \param assign set to true to connect the midi device, set to false to disconnect + */ +void InstrumentTrack::autoAssignMidiDevice(bool assign) +{ + if (assign) + { + if (s_autoAssignedTrack) + { + s_autoAssignedTrack->autoAssignMidiDevice(false); + } + s_autoAssignedTrack = this; + } + + const QString &device = ConfigManager::inst()->value("midi", "midiautoassign"); + if ( Engine::mixer()->midiClient()->isRaw() && device != "none" ) + { + m_midiPort.setReadable( assign ); + return; + } + + // Check if the device exists + if ( Engine::mixer()->midiClient()->readablePorts().indexOf(device) >= 0 ) + { + m_midiPort.subscribeReadablePort(device, assign); + m_hasAutoMidiDev = assign; + } +} + // #### ITV: