From d1880566830e2962f0647bfbb5c33b655af92e9a Mon Sep 17 00:00:00 2001 From: Paul Giblock Date: Mon, 2 Jun 2008 05:02:09 +0000 Subject: [PATCH] Add initial controller support for MIDI CC and various tweaks git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@1040 0778d3d1-df1d-0410-868b-ea421aaaa00d --- ChangeLog | 34 +++ Makefile.am | 3 + include/controller.h | 8 +- include/controller_connection.h | 39 +-- include/controller_connection_dialog.h | 67 ++--- include/midi.h | 4 +- include/midi_controller.h | 97 +++++++ src/core/automatable_model.cpp | 5 + src/core/controller.cpp | 8 +- src/core/controller_connection.cpp | 21 +- src/core/midi/midi_client.cpp | 6 +- src/core/midi/midi_controller.cpp | 159 ++++++++++++ src/core/track.cpp | 4 +- src/gui/controller_connection_dialog.cpp | 305 ++++++++++++----------- src/tracks/instrument_track.cpp | 4 + src/tracks/pattern.cpp | 2 +- 16 files changed, 530 insertions(+), 236 deletions(-) create mode 100644 include/midi_controller.h create mode 100644 src/core/midi/midi_controller.cpp diff --git a/ChangeLog b/ChangeLog index 5691ffa71..a10621895 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2008-06-02 Paul Giblock + + * include/controller_connection.h: + * src/core/automatable_model.cpp: + * src/core/controller_connection.cpp: + Support for automatic deletion of controller if owned by connection + + * include/controller.h: + * include/midi_controller.h: + * include/controller_connection_dialog.h: + * src/gui/controller_connection_dialog.cpp: + * src/core/midi/midi_controller.cpp: + * src/core/controller.cpp: + * Makefile.am: + + - Add midi-controller support + - Code clean-up + + * include/midi.h: + add const for max controller ID and add bytes array to the midiEvent + m_data union + + * src/core/midi/midi_client.cpp: + Don't subtract octave from control change events + + * src/tracks/instrument_track.cpp: + Ignore unhandled control change events + + * src/tracks/pattern.cpp: + Minor pixel adjustment to TCO drawing + + * src/core/track.cpp: + Correct misleading textFloat + 2008-06-01 Paul Giblock * src/tracks/pattern.cpp: diff --git a/Makefile.am b/Makefile.am index 7714e7346..bc2663440 100644 --- a/Makefile.am +++ b/Makefile.am @@ -102,6 +102,7 @@ lmms_MOC = \ ./nstate_button.moc \ ./meter_model.moc \ ./midi_alsa_seq.moc \ + ./midi_controller.moc \ ./instrument_midi_io.moc \ ./pattern.moc \ ./piano_roll.moc \ @@ -230,6 +231,7 @@ lmms_SOURCES = \ $(srcdir)/src/core/midi/midi_alsa_raw.cpp \ $(srcdir)/src/core/midi/midi_alsa_seq.cpp \ $(srcdir)/src/core/midi/midi_client.cpp \ + $(srcdir)/src/core/midi/midi_controller.cpp \ $(srcdir)/src/core/midi/midi_mapper.cpp \ $(srcdir)/src/core/midi/midi_oss.cpp \ $(srcdir)/src/core/midi/midi_port.cpp \ @@ -382,6 +384,7 @@ lmms_SOURCES = \ $(srcdir)/include/midi.h \ $(srcdir)/include/midi_alsa_raw.h \ $(srcdir)/include/midi_client.h \ + $(srcdir)/include/midi_controller.h \ $(srcdir)/include/midi_event_processor.h \ $(srcdir)/include/midi_oss.h \ $(srcdir)/include/midi_port.h \ diff --git a/include/controller.h b/include/controller.h index deae5369e..5e828080d 100644 --- a/include/controller.h +++ b/include/controller.h @@ -47,14 +47,14 @@ class controller : public model, public journallingObject public: enum ControllerTypes { - DummyController, + DummyController, LfoController, + MidiController, /* - MidiController, - XYController, + XYController, PeakController, */ - NumControllerTypes + NumControllerTypes } ; controller( ControllerTypes _type, model * _parent ); diff --git a/include/controller_connection.h b/include/controller_connection.h index 8afbcf381..66d5161ee 100644 --- a/include/controller_connection.h +++ b/include/controller_connection.h @@ -1,5 +1,5 @@ /* - * controller_connection.h - declaration of a controller connect, which + * controller_connection.h - declaration of a controller connect, which * provides a definition of the link between a controller and * model, also handles deferred creation of links while * loading project @@ -37,7 +37,7 @@ #include "mv_base.h" #include "journalling_object.h" -class controllerConnection; +class controllerConnection; typedef QVector controllerConnectionVector; @@ -51,26 +51,26 @@ public: virtual ~controllerConnection(); - inline controller * getController( void ) - { - return m_controller; - } + inline controller * getController( void ) + { + return m_controller; + } - inline void setController( controller * _controller ); + inline void setController( controller * _controller ); - inline void setController( int _controllerId ); + inline void setController( int _controllerId ); - float currentValue( int _offset ) - { - return m_controller->currentValue( _offset ); - } + float currentValue( int _offset ) + { + return m_controller->currentValue( _offset ); + } - inline bool isFinalized( void ) - { - return m_controllerId < 0; - } + inline bool isFinalized( void ) + { + return m_controllerId < 0; + } - static void finalizeConnections( void ); + static void finalizeConnections( void ); virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); virtual void loadSettings( const QDomElement & _this ); @@ -80,9 +80,10 @@ protected: //virtual controllerDialog * createDialog( QWidget * _parent ); controller * m_controller; - int m_controllerId; + int m_controllerId; + bool m_ownsController; - static controllerConnectionVector s_connections; + static controllerConnectionVector s_connections; signals: // The value changed while the mixer isn't running (i.e: MIDI CC) diff --git a/include/controller_connection_dialog.h b/include/controller_connection_dialog.h index fbdd0778e..1733e6e34 100644 --- a/include/controller_connection_dialog.h +++ b/include/controller_connection_dialog.h @@ -40,7 +40,9 @@ class QListView; class QScrollArea; class groupBox; class lcdSpinBox; +class ledCheckBox; class comboBox; +class autoDetectMidiController; @@ -59,13 +61,19 @@ public: public slots: // void setSelection( const effectKey & _selection ); void selectController( void ); - + void midiToggled( void ); + void userToggled( void ); + void autoDetectToggled( void ); + + void midiValueChanged( void ); + private: -// effectKey m_currentSelection; -// + groupBox * m_midiGroupBox; - lcdSpinBox * m_midiChannel; - lcdSpinBox * m_midiController; + lcdSpinBox * m_midiChannelSpinBox; + lcdSpinBox * m_midiControllerSpinBox; + ledCheckBox * m_midiAutoDetectCheckBox; + boolModel m_midiAutoDetect; groupBox * m_userGroupBox; comboBox * m_userController; @@ -74,53 +82,8 @@ private: controller * m_controller; + // Temporary midiController + autoDetectMidiController * m_midiController; } ; - -/* -class effectListWidget : public QWidget -{ - Q_OBJECT -public: - effectListWidget( QWidget * _parent ); - - virtual ~effectListWidget(); - - inline effectKey getSelected( void ) - { - return( m_currentSelection ); - } - - -signals: - void highlighted( const effectKey & _key ); - void addPlugin( const effectKey & _key ); - void doubleClicked( const effectKey & _key ); - - -protected: - virtual void resizeEvent( QResizeEvent * ); - - -protected slots: - void rowChanged( const QModelIndex &, const QModelIndex & ); - void onAddButtonReleased( void ); - void onDoubleClicked( const QModelIndex & ); - - -private: - QVector m_pluginDescriptors; - effectKeyList m_effectKeys; - effectKey m_currentSelection; - - QLineEdit * m_filterEdit; - QListView * m_pluginList; - QStandardItemModel m_sourceModel; - QSortFilterProxyModel m_model; - QScrollArea * m_scrollArea; - QWidget * m_descriptionWidget; - -} ; -*/ - #endif diff --git a/include/midi.h b/include/midi.h index 75f444f2e..b55216900 100644 --- a/include/midi.h +++ b/include/midi.h @@ -79,7 +79,8 @@ enum midiMetaEvents } ; -const Sint8 MIDI_CHANNEL_COUNT = 16; +const Uint8 MIDI_CHANNEL_COUNT = 16; +const Uint8 MIDI_CONTROLLER_COUNT = 128; struct midiEvent @@ -129,6 +130,7 @@ struct midiEvent union { Uint16 m_param[2]; // first/second parameter (key/velocity) + Uint8 m_bytes[4]; // raw bytes Uint32 m_sysExDataLen; // len of m_sysExData } m_data; diff --git a/include/midi_controller.h b/include/midi_controller.h new file mode 100644 index 000000000..ce3b4e62b --- /dev/null +++ b/include/midi_controller.h @@ -0,0 +1,97 @@ +/* + * midi_controller.h - A controller to receive MIDI control-changes + * + * Copyright (c) 2008 Paul Giblock + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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. + * + */ + +#ifndef _MIDI_CONTROLLER_H +#define _MIDI_CONTROLLER_H + +#include + +#include "mv_base.h" +#include "automatable_model.h" +#include "controller.h" +#include "controller_dialog.h" +#include "midi_event_processor.h" + + +class midiPort; + + +class midiController : public controller, public midiEventProcessor +{ + Q_OBJECT +public: + midiController( model * _parent ); + virtual ~midiController(); + + virtual QString publicName() const + { + return "MIDI Controller"; + } + + virtual void processInEvent( const midiEvent & _me, + const midiTime & _time, + bool _lock = TRUE ); + + virtual void processOutEvent( const midiEvent& _me, + const midiTime & _time) + { + // No output yet + } + + virtual void saveSettings( QDomDocument & _doc, QDomElement & _this ); + virtual void loadSettings( const QDomElement & _this ); + virtual QString nodeName( void ) const; + + virtual intModel * midiChannelModel( void ) + { + return &m_midiChannel; + } + + + virtual intModel * midiControllerModel( void ) + { + return &m_midiController; + } + + +public slots: + virtual controllerDialog * createDialog( QWidget * _parent ); + void updateMidiPort(); + +protected: + + // The internal per-controller get-value function + virtual float value( int _offset ); + + intModel m_midiChannel; + intModel m_midiController; + + midiPort * m_midiPort; + + float m_lastValue; + +}; + + +#endif diff --git a/src/core/automatable_model.cpp b/src/core/automatable_model.cpp index 40f3fda90..3f4cef66b 100644 --- a/src/core/automatable_model.cpp +++ b/src/core/automatable_model.cpp @@ -77,6 +77,11 @@ automatableModel::~automatableModel() m_linkedModels.last()->unlinkModel( this ); m_linkedModels.erase( m_linkedModels.end() - 1 ); } + + if( m_controllerConnection ) + { + delete m_controllerConnection; + } } diff --git a/src/core/controller.cpp b/src/core/controller.cpp index a5383d5f7..20e4cf57a 100644 --- a/src/core/controller.cpp +++ b/src/core/controller.cpp @@ -48,7 +48,7 @@ controller::controller( ControllerTypes _type, model * _parent ) : journallingObject(), m_type( _type ) { - if( _type != DummyController ) + if( _type != DummyController && _type != MidiController ) { s_controllers.append( this ); m_name = QString( tr( "Controller %1" ) ) @@ -60,7 +60,11 @@ controller::controller( ControllerTypes _type, model * _parent ) : controller::~controller() { - s_controllers.remove( s_controllers.indexOf( this ) ); + int idx = s_controllers.indexOf( this ); + if( idx >= 0 ) + { + s_controllers.remove( idx ); + } if( engine::getSong() ) { diff --git a/src/core/controller_connection.cpp b/src/core/controller_connection.cpp index e983703f5..28ce7574e 100644 --- a/src/core/controller_connection.cpp +++ b/src/core/controller_connection.cpp @@ -41,7 +41,8 @@ controllerConnectionVector controllerConnection::s_connections; controllerConnection::controllerConnection( controller * _controller ) : - m_controllerId( -1 ) + m_controllerId( -1 ), + m_ownsController( FALSE ) { if( _controller != NULL ) { @@ -58,7 +59,8 @@ controllerConnection::controllerConnection( controller * _controller ) : controllerConnection::controllerConnection( int _controllerId ) : m_controller( controller::create( controller::DummyController, NULL ) ), - m_controllerId( _controllerId ) + m_controllerId( _controllerId ), + m_ownsController( FALSE ) { s_connections.append( this ); } @@ -68,6 +70,10 @@ controllerConnection::controllerConnection( int _controllerId ) : controllerConnection::~controllerConnection() { s_connections.remove( s_connections.indexOf( this ) ); + if( m_ownsController ) + { + delete m_controller; + } } @@ -80,13 +86,22 @@ void controllerConnection::setController( int _controllerId ) void controllerConnection::setController( controller * _controller ) { + if( m_ownsController && m_controller ) + { + delete m_controller; + } + m_controller = _controller; m_controllerId = -1; - if( _controller->type() != controller::DummyController ) { + if( _controller->type() != controller::DummyController ) + { QObject::connect( _controller, SIGNAL( valueChanged() ), this, SIGNAL( valueChanged() ) ); } + + m_ownsController = + ( _controller->type() == controller::MidiController ); } diff --git a/src/core/midi/midi_client.cpp b/src/core/midi/midi_client.cpp index 14138e596..f1d006567 100644 --- a/src/core/midi/midi_client.cpp +++ b/src/core/midi/midi_client.cpp @@ -245,13 +245,17 @@ void midiClientRaw::parseData( const Uint8 _c ) case NOTE_OFF: case NOTE_ON: case KEY_PRESSURE: - case CONTROL_CHANGE: case PROGRAM_CHANGE: case CHANNEL_PRESSURE: m_midiParseData.m_midiEvent.m_data.m_param[0] = m_midiParseData.m_buffer[0] - KeysPerOctave; m_midiParseData.m_midiEvent.m_data.m_param[1] = m_midiParseData.m_buffer[1]; + case CONTROL_CHANGE: + m_midiParseData.m_midiEvent.m_data.m_param[0] = + m_midiParseData.m_buffer[0] - KeysPerOctave; + m_midiParseData.m_midiEvent.m_data.m_param[1] = + m_midiParseData.m_buffer[1]; break; case PITCH_BEND: diff --git a/src/core/midi/midi_controller.cpp b/src/core/midi/midi_controller.cpp new file mode 100644 index 000000000..a2efc8990 --- /dev/null +++ b/src/core/midi/midi_controller.cpp @@ -0,0 +1,159 @@ +#ifndef SINGLE_SOURCE_COMPILE + +/* + * midi_controller.cpp - implementation of class midi-controller which handles + * MIDI control change messages + * + * Copyright (c) 2008 Paul Giblock + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 +#include +#include + + +#include "song.h" +#include "engine.h" +#include "mixer.h" +#include "midi_client.h" +#include "midi_port.h" +#include "midi_controller.h" + + + +midiController::midiController( model * _parent ) : + controller( MidiController, _parent ), + midiEventProcessor(), + m_midiChannel( 0, 0, MIDI_CHANNEL_COUNT, this ), + m_midiController( 0, 0, MIDI_CONTROLLER_COUNT, this ), + m_midiPort( engine::getMixer()->getMIDIClient()->addPort( + this, tr( "unnamed_channel" ) ) ), + m_lastValue( 0.0f ) +{ + m_midiPort->setMode( midiPort::Input ); + connect( &m_midiChannel, SIGNAL( dataChanged() ), + this, SLOT( updateMidiPort() ) ); + connect( &m_midiController, SIGNAL( dataChanged() ), + this, SLOT( updateMidiPort() ) ); +} + + + +midiController::~midiController() +{ + m_midiChannel.disconnect( this ); + m_midiController.disconnect( this ); + + engine::getMixer()->getMIDIClient()->removePort( m_midiPort ); +} + + + + +float midiController::value( int _offset ) +{ + return m_lastValue; +} + + + + +void midiController::updateMidiPort( void ) +{ + m_midiPort->setInputChannel( m_midiChannel.value() - 1 ); +} + + + + +void midiController::processInEvent( const midiEvent & _me, + const midiTime & _time, bool _lock ) +{ + Uint8 controllerNum; + const Uint8 * bytes; + switch( _me.m_type ) + { + case CONTROL_CHANGE: + bytes = _me.m_data.m_bytes; + controllerNum = _me.m_data.m_bytes[0] & 0x7F; + + if( m_midiController.value() == controllerNum + 1 && + ( m_midiChannel.value() == _me.m_channel + 1 || + m_midiChannel.value() == 0 ) ) + { + Uint8 val = _me.m_data.m_bytes[2] & 0x7F; + m_lastValue = (float)( val ) / 127.0f; + emit valueChanged(); + } + break; + + default: + // Don't care - maybe add special cases for pitch and mod later + break; + } +} + + + + +void midiController::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ + controller::saveSettings( _doc, _this ); + + m_midiChannel.saveSettings( _doc, _this, "channel" ); + m_midiController.saveSettings( _doc, _this, "controller" ); +} + + + + +void midiController::loadSettings( const QDomElement & _this ) +{ + controller::loadSettings( _this ); + + m_midiChannel.loadSettings( _this, "channel" ); + m_midiController.loadSettings( _this, "controller" ); + + updateMidiPort(); +} + + + + +QString midiController::nodeName( void ) const +{ + return( "midicontroller" ); +} + + + + +controllerDialog * midiController::createDialog( QWidget * _parent ) +{ + return NULL; +} + + +#include "midi_controller.moc" + + +#endif + diff --git a/src/core/track.cpp b/src/core/track.cpp index 63b9e95d7..510789d5b 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -409,8 +409,8 @@ void trackContentObjectView::mousePressEvent( QMouseEvent * _me ) s_textFloat->setTitle( tr( "Current position" ) ); delete m_hint; m_hint = textFloat::displayMessage( tr( "Hint" ), - tr( "Press for free " - "positioning." ), + tr( "Press and drag to make " + "a copy." ), embed::getIconPixmap( "hint" ), 0 ); } else if( m_autoResize == FALSE ) diff --git a/src/gui/controller_connection_dialog.cpp b/src/gui/controller_connection_dialog.cpp index f16c0f4b3..c548b389a 100644 --- a/src/gui/controller_connection_dialog.cpp +++ b/src/gui/controller_connection_dialog.cpp @@ -33,18 +33,88 @@ #include "controller_connection_dialog.h" #include "lcd_spinbox.h" +#include "led_checkbox.h" #include "combobox.h" #include "group_box.h" +#include "midi_controller.h" +#include "midi.h" #include "song.h" #include "gui_templates.h" #include "embed.h" +class autoDetectMidiController : public midiController +{ +public: + autoDetectMidiController( model * _parent ) : + midiController( _parent ), + m_detectedMidiChannel( 0 ), + m_detectedMidiController( 0 ) + { + updateMidiPort(); + } + + + virtual ~autoDetectMidiController() + { + } + + + virtual void processInEvent( const midiEvent & _me, + const midiTime & _time, bool _lock ) + { + if( _me.m_type == CONTROL_CHANGE && + ( m_midiChannel.value() == _me.m_channel + 1 || + m_midiChannel.value() == 0 ) ) + { + m_detectedMidiChannel = _me.m_channel + 1; + m_detectedMidiController = ( _me.m_data.m_bytes[0] & 0x7F ) + 1; + + emit valueChanged(); + } + } + + + int m_detectedMidiChannel; + int m_detectedMidiController; + + // Would be a nice copy ctor, but too hard to add copy ctor because + // model has none. + midiController * copyToMidiController( model * _parent ) + { + midiController * c = new midiController( _parent ); + c->midiChannelModel()->setValue( m_midiChannel.value() ); + c->midiControllerModel()->setValue( m_midiController.value() ); + + return c; + } + + + void useDetected( void ) + { + m_midiChannel.setValue( m_detectedMidiChannel ); + m_midiController.setValue( m_detectedMidiController ); + } + + +public slots: + void reset( void ) + { + m_midiChannel.setValue( 0 ); + m_midiController.setValue( 0 ); + } + +}; + + + controllerConnectionDialog::controllerConnectionDialog( QWidget * _parent ) : QDialog( _parent ), - m_controller( NULL ) + m_controller( NULL ), + m_midiController( NULL ), + m_midiAutoDetect( FALSE ) { setWindowIcon( embed::getIconPixmap( "setup_audio" ) ); setWindowTitle( tr( "Connection Settings" ) ); @@ -54,11 +124,39 @@ controllerConnectionDialog::controllerConnectionDialog( QWidget * _parent vlayout->setSpacing( 10 ); vlayout->setMargin( 10 ); + // Midi stuff m_midiGroupBox = new groupBox( tr( "MIDI CONTROLLER" ), this ); m_midiGroupBox->setGeometry( 2, 2, 240, 64 ); + connect( m_midiGroupBox->model(), SIGNAL( dataChanged() ), + this, SLOT( midiToggled() ) ); + + m_midiChannelSpinBox = new lcdSpinBox( 2, m_midiGroupBox, + tr( "Input channel" ) ); + m_midiChannelSpinBox->addTextForValue( 0, "--" ); + m_midiChannelSpinBox->setLabel( tr( "CHANNEL" ) ); + m_midiChannelSpinBox->move( 8, 16 ); + m_midiControllerSpinBox = new lcdSpinBox( 3, m_midiGroupBox, + tr( "Input controller" ) ); + m_midiControllerSpinBox->addTextForValue( 0, "---" ); + m_midiControllerSpinBox->setLabel( tr( "CONTROLLER" ) ); + m_midiControllerSpinBox->move( 72, 16 ); + + + ledCheckBox * m_midiAutoDetectCheckBox = + new ledCheckBox( tr("Auto Detect"), + m_midiGroupBox, tr("Auto Detect") ); + m_midiAutoDetectCheckBox->setModel( &m_midiAutoDetect ); + m_midiAutoDetectCheckBox->move( 136, 20 ); + connect( &m_midiAutoDetect, SIGNAL( dataChanged() ), + this, SLOT( autoDetectToggled() ) ); + + + // User stuff m_userGroupBox = new groupBox( tr( "USER CONTROLLER" ), this ); m_userGroupBox->setGeometry( 2, 70, 240, 64 ); + connect( m_userGroupBox->model(), SIGNAL( dataChanged() ), + this, SLOT( userToggled() ) ); m_mappingFunction = new QLineEdit( this ); m_mappingFunction->setGeometry( 2, 140, 240, 16 ); @@ -66,7 +164,7 @@ controllerConnectionDialog::controllerConnectionDialog( QWidget * _parent QWidget * buttons = new QWidget( this ); buttons->setGeometry( 2, 160, 240, 32 ); - + resize( 256, 196 ); m_userController = new comboBox( m_userGroupBox, "Controller" ); @@ -113,201 +211,106 @@ controllerConnectionDialog::controllerConnectionDialog( QWidget * _parent controllerConnectionDialog::~controllerConnectionDialog() { + if( m_midiController ) + delete m_midiController; } -/* -void effectSelectDialog::setSelection( const effectKey & _selection ) -{ - m_currentSelection = _selection; -} -*/ + void controllerConnectionDialog::selectController( void ) { - if( m_userController->model()->value() >= 0 ) { - m_controller = engine::getSong()->controllers().at( - m_userController->model()->value() ); + if( m_midiGroupBox->model()->value() >= 0 ) + { + m_controller = m_midiController->copyToMidiController( + engine::getSong() ); + } + else + { + if( m_userController->model()->value() >= 0 ) + { + m_controller = engine::getSong()->controllers().at( + m_userController->model()->value() ); + } } accept(); } -/* - -effectListWidget::effectListWidget( QWidget * _parent ) : - QWidget( _parent ), - m_sourceModel(), - m_model(), - m_descriptionWidget( NULL ) +void controllerConnectionDialog::midiToggled( void ) { - plugin::getDescriptorsOfAvailPlugins( m_pluginDescriptors ); - - for( QVector::iterator it = - m_pluginDescriptors.begin(); - it != m_pluginDescriptors.end(); ++it ) + int enabled = m_midiGroupBox->model()->value(); + if( enabled != 0 ) { - if( it->type != plugin::Effect ) + if( m_userGroupBox->model()->value() != 0 ) { - continue; + m_userGroupBox->model()->setValue( 0 ); } - if( it->sub_plugin_features ) - { - it->sub_plugin_features->listSubPluginKeys( - // as iterators are always stated to be not - // equal with pointers, we dereference the - // iterator and take the address of the item, - // so we're on the safe side and the compiler - // likely will reduce that to just "it" - &( *it ), - m_effectKeys ); - } - else - { - m_effectKeys << effectKey( &( *it ), it->name ); + if( !m_midiController ) + { + m_midiController = new autoDetectMidiController( engine::getSong() ); + m_midiChannelSpinBox->setModel( + m_midiController->midiChannelModel() ); + m_midiControllerSpinBox->setModel( + m_midiController->midiControllerModel() ); + + connect( m_midiController, SIGNAL( valueChanged() ), + this, SLOT( midiValueChanged() ) ); } } - - QStringList plugin_names; - for( effectKeyList::const_iterator it = m_effectKeys.begin(); - it != m_effectKeys.end(); ++it ) + else { - plugin_names += QString( ( *it ).desc->public_name ) + - ( ( ( *it ).desc->sub_plugin_features != NULL ) ? - ": " + ( *it ).name - : - "" ); + m_midiAutoDetect.setValue( FALSE ); } + m_midiChannelSpinBox->setEnabled( enabled ); + m_midiControllerSpinBox->setEnabled( enabled ); + //m_midiAutoDetect->setEnabled( enabled ); +} - int row = 0; - for( QStringList::iterator it = plugin_names.begin(); - it != plugin_names.end(); ++it ) + + + +void controllerConnectionDialog::userToggled( void ) +{ + int enabled = m_userGroupBox->model()->value(); + if( enabled != 0 && m_midiGroupBox->model()->value() != 0 ) { - m_sourceModel.setItem( row, 0, new QStandardItem( *it ) ); - ++row; + m_midiGroupBox->model()->setValue( 0 ); } - m_model.setSourceModel( &m_sourceModel ); - m_model.setFilterCaseSensitivity( Qt::CaseInsensitive ); + m_userController->setEnabled( enabled ); +} - m_filterEdit = new QLineEdit( this ); - connect( m_filterEdit, SIGNAL( textChanged( const QString & ) ), - &m_model, SLOT( setFilterRegExp( const QString & ) ) ); - m_pluginList = new QListView( this ); - m_pluginList->setModel( &m_model ); - QItemSelectionModel * sm = new QItemSelectionModel( &m_model ); - m_pluginList->setSelectionModel( sm ); - m_pluginList->setSelectionBehavior( QAbstractItemView::SelectRows ); - m_pluginList->setSelectionMode( QAbstractItemView::SingleSelection ); - m_pluginList->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); - connect( sm, SIGNAL( currentRowChanged( const QModelIndex &, - const QModelIndex & ) ), - SLOT( rowChanged( const QModelIndex &, - const QModelIndex & ) ) ); - connect( m_pluginList, SIGNAL( doubleClicked( const QModelIndex & ) ), - SLOT( onDoubleClicked( const QModelIndex & ) ) ); - QGroupBox * groupbox = new QGroupBox( tr( "Description" ), this ); - groupbox->setFixedHeight( 200 ); - QVBoxLayout * gbl = new QVBoxLayout( groupbox ); - gbl->setMargin( 0 ); - gbl->setSpacing( 10 ); - - m_scrollArea = new QScrollArea( groupbox ); - m_scrollArea->setFrameStyle( 0 ); - - gbl->addWidget( m_scrollArea ); - - QVBoxLayout * vboxl = new QVBoxLayout( this ); - vboxl->setMargin( 0 ); - vboxl->setSpacing( 10 ); - vboxl->addWidget( m_filterEdit ); - vboxl->addWidget( m_pluginList ); - vboxl->addWidget( groupbox ); - - if( m_sourceModel.rowCount() > 0 ) +void controllerConnectionDialog::autoDetectToggled( void ) +{ + if( m_midiAutoDetect.value() ) { -// m_pluginList->setCurrentRow( 0 ); - //rowChanged( 0 ); + m_midiController->reset(); } } -effectListWidget::~effectListWidget() +void controllerConnectionDialog::midiValueChanged( void ) { -} - - - - -void effectListWidget::rowChanged( const QModelIndex & _idx, - const QModelIndex & ) -{ - delete m_descriptionWidget; - m_descriptionWidget = NULL; - - m_currentSelection = m_effectKeys[_idx.row()]; - if( m_currentSelection.desc && - m_currentSelection.desc->sub_plugin_features ) + if( m_midiAutoDetect.value() ) { - m_descriptionWidget = new QWidget; - QVBoxLayout * l = new QVBoxLayout( m_descriptionWidget ); - l->setMargin( 4 ); - l->setSpacing( 0 ); + m_midiController->useDetected(); - m_scrollArea->setWidget( m_descriptionWidget ); - - m_currentSelection.desc->sub_plugin_features-> - fillDescriptionWidget( m_descriptionWidget, - &m_currentSelection ); - foreach( QWidget * w, - m_descriptionWidget->findChildren() ) - { - if( w->parent() == m_descriptionWidget ) - { - l->addWidget( w ); - } - } - l->setSizeConstraint( QLayout::SetFixedSize ); - m_descriptionWidget->show(); + m_midiAutoDetect.setValue( FALSE ); } - emit( highlighted( m_currentSelection ) ); } -void effectListWidget::onDoubleClicked( const QModelIndex & ) -{ - emit( doubleClicked( m_currentSelection ) ); -} - - - - -void effectListWidget::onAddButtonReleased() -{ - emit( addPlugin( m_currentSelection ) ); -} - - - - -void effectListWidget::resizeEvent( QResizeEvent * ) -{ - //m_descriptionWidget->setFixedWidth( width() - 40 ); -} - -*/ - - #include "controller_connection_dialog.moc" #endif diff --git a/src/tracks/instrument_track.cpp b/src/tracks/instrument_track.cpp index 5039495d8..deb1b5674 100644 --- a/src/tracks/instrument_track.cpp +++ b/src/tracks/instrument_track.cpp @@ -291,6 +291,10 @@ void instrumentTrack::processInEvent( const midiEvent & _me, m_instrument->handleMidiEvent( _me, _time ); break; + case CONTROL_CHANGE: + // Ignore control changes + break; + default: printf( "instrument-track: unhandled MIDI-event %d\n", _me.m_type ); diff --git a/src/tracks/pattern.cpp b/src/tracks/pattern.cpp index be06caf93..7dc4c8da9 100644 --- a/src/tracks/pattern.cpp +++ b/src/tracks/pattern.cpp @@ -1151,7 +1151,7 @@ void patternView::paintEvent( QPaintEvent * ) p.drawLine( x_base + static_cast( ppt * tact_num ) - 1, - height() - ( 5 + 2 * + height() - ( 4 + 2 * TCO_BORDER_WIDTH ), x_base + static_cast( ppt * tact_num ) - 1,