diff --git a/include/setup_dialog.h b/include/setup_dialog.h index 4c8b700e8..db4496f2e 100644 --- a/include/setup_dialog.h +++ b/include/setup_dialog.h @@ -32,15 +32,18 @@ #include "lmmsconfig.h" #include "audio_device.h" #include "midi_client.h" +#include "midi_control_listener.h" + class QComboBox; class QLabel; class QLineEdit; class QSlider; - +class QTableWidget; class tabBar; - +class groupBox; +class setupDialogMCL; class setupDialog : public QDialog { @@ -57,7 +60,11 @@ public: setupDialog( ConfigTabs _tab_to_open = GeneralSettings ); virtual ~setupDialog(); - + + void mclAddKeyAction( int _key, + MidiControlListener::EventAction _action ); + void mclAddControllerAction( int _controller, + MidiControlListener::EventAction _action ); protected slots: virtual void accept( void ); @@ -106,8 +113,16 @@ private slots: void toggleDisableChActInd( bool _disabled ); void toggleManualChPiano( bool _enabled ); + void toggleMCLEnabled( bool _enabled ); + void toggleMCLControlKey( bool _enabled ); + + void mclNewAction( void ); + void mclDelAction( void ); private: + groupBox * setupMidiControlListener( QWidget * midi ); + void mclUpdateActionTable( void ); + tabBar * m_tabBar; QSlider * m_bufSizeSlider; @@ -162,7 +177,14 @@ private: mswMap m_midiIfaceSetupWidgets; trMap m_midiIfaceNames; - + bool m_mclEnabled; + int m_mclChannel; + bool m_mclUseControlKey; + MidiControlListener::ActionMap m_mclActionMapKeys; + MidiControlListener::ActionMap m_mclActionMapControllers; + + QList< QPair > m_mclActionTableMap; + QTableWidget * m_mclActionTable; } ; diff --git a/include/setup_dialog_mcl.h b/include/setup_dialog_mcl.h new file mode 100644 index 000000000..ff6629afe --- /dev/null +++ b/include/setup_dialog_mcl.h @@ -0,0 +1,61 @@ +/* + * setup_dialog_mcl.h - dialog for setting up MIDI Control Listener + * + * Copyright (c) 2009 Achim Settelmeier + * + * 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 _SETUP_DIALOG_MCL_H +#define _SETUP_DIALOG_MCL_H + +#include + +class setupDialog; + +class setupDialogMCL : public QDialog +{ + Q_OBJECT +public: + setupDialogMCL( setupDialog * _parent ); + virtual ~setupDialogMCL( void ); + + +protected slots: + virtual void accept( void ); + +private slots: + void clickedKeyBox( void ); + void clickedControllerBox( void ); + +private: + setupDialog * m_parent; + + bool m_keysActive; // true: configure key, false: configure controller + + groupBox * m_actionKey_gb; + groupBox * m_actionController_gb; + QComboBox * m_actionsKey_box; + QComboBox * m_actionsController_box; + lcdSpinBoxModel * m_controllerSbModel; +} ; + + +#endif diff --git a/src/gui/setup_dialog.cpp b/src/gui/setup_dialog.cpp index 50403ff6e..fc7571823 100644 --- a/src/gui/setup_dialog.cpp +++ b/src/gui/setup_dialog.cpp @@ -34,6 +34,9 @@ #include #include #include +#include +#include +#include #include "setup_dialog.h" @@ -49,7 +52,10 @@ #include "debug.h" #include "tooltip.h" #include "led_checkbox.h" +#include "group_box.h" #include "lcd_spinbox.h" +#include "midi_control_listener.h" +#include "setup_dialog_mcl.h" // platform-specific audio-interface-classes @@ -114,7 +120,12 @@ setupDialog::setupDialog( ConfigTabs _tab_to_open ) : m_disableChActInd( configManager::inst()->value( "ui", "disablechannelactivityindicators" ).toInt() ), m_manualChPiano( configManager::inst()->value( "ui", - "manualchannelpiano" ).toInt() ) + "manualchannelpiano" ).toInt() ), + m_mclEnabled( engine::getMidiControlListener()->getEnabled() ), + m_mclChannel( engine::getMidiControlListener()->getChannel() ), + m_mclUseControlKey( engine::getMidiControlListener()->getUseControlKey() ), + m_mclActionMapKeys( engine::getMidiControlListener()->getActionMapKeys() ), + m_mclActionMapControllers( engine::getMidiControlListener()->getActionMapControllers() ) { setWindowIcon( embed::getIconPixmap( "setup_general" ) ); setWindowTitle( tr( "Setup LMMS" ) ); @@ -637,13 +648,15 @@ setupDialog::setupDialog( ConfigTabs _tab_to_open ) : connect( m_midiInterfaces, SIGNAL( activated( const QString & ) ), this, SLOT( midiInterfaceChanged( const QString & ) ) ); - + groupBox * midicl_gb = setupMidiControlListener( midi ); + midi_layout->addWidget( midiiface_tw ); midi_layout->addSpacing( 20 ); midi_layout->addWidget( msw ); + midi_layout->addSpacing( 20 ); + midi_layout->addWidget( midicl_gb ); midi_layout->addStretch(); - m_tabBar->addTab( general, tr( "General settings" ), 0, FALSE, TRUE )->setIcon( embed::getIconPixmap( "setup_general" ) ); m_tabBar->addTab( paths, tr( "Paths" ), 1, FALSE, TRUE @@ -709,6 +722,141 @@ setupDialog::~setupDialog() +groupBox * setupDialog::setupMidiControlListener( QWidget * midi ) +{ + // MIDI control listener + groupBox * gb = new groupBox( tr( "MIDI REMOTE CONTROL" ), + midi ); + gb->setFixedHeight( 235 ); + gb->ledButton()->setChecked( m_mclEnabled ); + + connect( gb->ledButton(), SIGNAL( toggled( bool ) ), + this, SLOT( toggleMCLEnabled( bool ) ) ); + + // channel + lcdSpinBoxModel * channelSbModel = new lcdSpinBoxModel( /* this */ ); + channelSbModel->setRange( 0, 16 ); + channelSbModel->setStep( 1 ); + channelSbModel->setValue( m_mclChannel + 1 ); + lcdSpinBox * channelSb = new lcdSpinBox( 3, gb ); + channelSb->setModel( channelSbModel ); + channelSb->addTextForValue( 0, "---" ); + channelSb->setLabel( tr( "CHANNEL" ) ); + channelSb->move( 20, 20 ); + + // device + QToolButton * devicesBtn = new QToolButton( gb ); + devicesBtn->setText( tr( "MIDI-device to receive " + "remote control events from" ) ); + devicesBtn->setIcon( embed::getIconPixmap( "piano" ) ); + devicesBtn->setGeometry( 100, 20, 32, 32 ); + devicesBtn->setPopupMode( QToolButton::InstantPopup ); + + // use control key + ledCheckBox * controlKeyCb = new ledCheckBox( + tr( "Use control key" ), + gb ); + controlKeyCb->move( 20, 60 ); + controlKeyCb->setChecked( m_mclUseControlKey ); + connect( controlKeyCb, SIGNAL( toggled( bool ) ), + this, SLOT( toggleMCLControlKey( bool ) ) ); + + m_mclActionTable = new QTableWidget( gb ); + mclUpdateActionTable(); + + QWidget * buttons = new QWidget( gb ); + QVBoxLayout * btn_layout = new QVBoxLayout( buttons ); + btn_layout->setSpacing( 0 ); + btn_layout->setMargin( 0 ); + QPushButton * new_btn = new QPushButton( tr( "New" ), buttons ); + connect( new_btn, SIGNAL( clicked() ), this, SLOT( mclNewAction() ) ); + QPushButton * del_btn = new QPushButton( tr( "Del" ), buttons ); + connect( del_btn, SIGNAL( clicked() ), this, SLOT( mclDelAction() ) ); + + btn_layout->addWidget( new_btn ); + btn_layout->addSpacing( 5 ); + btn_layout->addWidget( del_btn ); + btn_layout->addStretch(); + buttons->move( 275, 80 ); + + return gb; +} + + + + +void setupDialog::mclUpdateActionTable( void ) +{ + m_mclActionTableMap.clear(); + + QTableWidget * table = m_mclActionTable; + table->setColumnCount( 2 ); + table->setRowCount( m_mclActionMapKeys.count() + + m_mclActionMapControllers.count() ); + table->setGeometry(20, 80, 250, 145 ); + QStringList headers; + headers << "Key/Ctrl" << "Action"; + table->setHorizontalHeaderLabels( headers ); + int row = 0; + QString key2NameMap[] = + { + "C", "C#", "D", "D#", "E", "F", + "F#", "G", "G#", "A", "A#", "B" + }; + for( MidiControlListener::ActionMap::const_iterator it = m_mclActionMapKeys.begin(); + it != m_mclActionMapKeys.end(); ++it, ++row ) + { + int keyNr = it.key(); + QString key = "Key "; + key += key2NameMap[ keyNr % 12 ]; + key += QString::number( int( keyNr / 12 ) ); + QTableWidgetItem * item = new QTableWidgetItem( key ); + item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); + table->setItem( row, 0, item ); + + QString actionName = MidiControlListener::action2ActionNameMap( it.value() ).name; + item = new QTableWidgetItem( actionName ); + item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); + table->setItem( row, 1, item ); + + table->setRowHeight( row, 20 ); + + m_mclActionTableMap.append( qMakePair( 'k', keyNr ) ); + } + + for( MidiControlListener::ActionMap::const_iterator it = m_mclActionMapControllers.begin(); + it != m_mclActionMapControllers.end(); ++it, ++row ) + { + QString controller = "Controller #"; + controller += QString::number( it.key() ); + QTableWidgetItem * item = new QTableWidgetItem( controller ); + item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); + table->setItem( row, 0, item ); + + QString actionName = MidiControlListener::action2ActionNameMap( it.value() ).name; + item = new QTableWidgetItem( actionName ); + item->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled ); + table->setItem( row, 1, item ); + + table->setRowHeight( row, 20 ); + + m_mclActionTableMap.append( qMakePair( 'c', it.key() ) ); + } + + //table->setColumnWidth( 0, 135 ); + //table->setColumnWidth( 1, 135 ); + table->setEnabled( true ); + table->setShowGrid( false ); + table->setSortingEnabled( false ); + table->setSelectionBehavior( QTableWidget::SelectRows ); + table->verticalHeader()->hide(); + table->setAlternatingRowColors( true ); + +} + + + + void setupDialog::accept( void ) { configManager::inst()->setValue( "mixer", "framesperaudiobuffer", @@ -758,6 +906,14 @@ void setupDialog::accept( void ) { it.value()->saveSettings(); } + + // MIDI control listener + MidiControlListener * listener = engine::getMidiControlListener(); + listener->setEnabled( m_mclEnabled ); + listener->setChannel( m_mclChannel ); + listener->setUseControlKey( m_mclUseControlKey ); + listener->setActionMapKeys( m_mclActionMapKeys ); + listener->setActionMapControllers( m_mclActionMapControllers ); configManager::inst()->saveConfigFile(); @@ -1161,6 +1317,75 @@ void setupDialog::displayMIDIHelp( void ) +void setupDialog::toggleMCLEnabled( bool _enabled ) +{ + m_mclEnabled = _enabled; +} + + + + +void setupDialog::toggleMCLControlKey( bool _enabled ) +{ + m_mclUseControlKey = _enabled; +} + + + + +void setupDialog::mclNewAction( void ) +{ + setupDialogMCL sdMcl( this ); + sdMcl.exec(); +} + + + + +void setupDialog::mclDelAction( void ) +{ + + int row = m_mclActionTable->currentRow(); + if( row < 0 ) + { + return; // sanity check: no row selected + } + QPair entry = m_mclActionTableMap[ row ]; + if( entry.first == 'k' ) + { + m_mclActionMapKeys.remove( entry.second ); + } + else if( entry.first == 'c' ) + { + m_mclActionMapControllers.remove( entry.second ); + } + + mclUpdateActionTable(); +} + + + + +void setupDialog::mclAddKeyAction( int _key, + MidiControlListener::EventAction _action ) +{ + m_mclActionMapKeys[ _key ] = _action; + mclUpdateActionTable(); +} + + + + +void setupDialog::mclAddControllerAction( int _controller, + MidiControlListener::EventAction _action ) +{ + m_mclActionMapControllers[ _controller ] = _action; + mclUpdateActionTable(); +} + + + + #include "moc_setup_dialog.cxx" diff --git a/src/gui/setup_dialog_mcl.cpp b/src/gui/setup_dialog_mcl.cpp new file mode 100644 index 000000000..3e8dce242 --- /dev/null +++ b/src/gui/setup_dialog_mcl.cpp @@ -0,0 +1,199 @@ +#ifndef SINGLE_SOURCE_COMPILE + +/* + * setup_dialog_mcl.cpp - dialog for setting up MIDI Control Listener + * + * Copyright (c) 2009 Achim Settelmeier + * + * 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 "embed.h" +#include "group_box.h" +#include "lcd_spinbox.h" + +#include "setup_dialog.h" +#include "setup_dialog_mcl.h" + + +setupDialogMCL::setupDialogMCL( setupDialog * _parent ) : + m_parent( _parent ), + m_keysActive( true ) +{ + + setWindowTitle( tr( "New action" ) ); + setModal( true ); + + QWidget * buttons = new QWidget( this ); + QHBoxLayout * btn_layout = new QHBoxLayout( buttons ); + btn_layout->setSpacing( 0 ); + btn_layout->setMargin( 0 ); + QPushButton * ok_btn = new QPushButton( embed::getIconPixmap( "apply" ), + tr( "OK" ), buttons ); + connect( ok_btn, SIGNAL( clicked() ), this, SLOT( accept() ) ); + + QPushButton * cancel_btn = new QPushButton( embed::getIconPixmap( + "cancel" ), + tr( "Cancel" ), + buttons ); + connect( cancel_btn, SIGNAL( clicked() ), this, SLOT( reject() ) ); + + btn_layout->addStretch(); + btn_layout->addSpacing( 10 ); + btn_layout->addWidget( ok_btn ); + btn_layout->addSpacing( 10 ); + btn_layout->addWidget( cancel_btn ); + btn_layout->addSpacing( 10 ); + + QWidget * settings = new QWidget( this ); + settings->setGeometry( 10, 10, 180, 100 ); + + QVBoxLayout * vlayout = new QVBoxLayout( this ); + vlayout->setSpacing( 0 ); + vlayout->setMargin( 0 ); + vlayout->addWidget( settings ); + vlayout->addSpacing( 10 ); + vlayout->addWidget( buttons ); + vlayout->addSpacing( 10 ); + vlayout->addStretch(); + + + m_actionKey_gb = new groupBox( tr( "MIDI KEYBOARD" ), + settings ); + m_actionKey_gb->setFixedHeight( 60 ); + m_actionKey_gb->ledButton()->setChecked( m_keysActive ); + connect( m_actionKey_gb->ledButton(), SIGNAL( clicked() ), + this, SLOT( clickedKeyBox( ) ) ); + + m_actionController_gb = new groupBox( tr( "MIDI CONTROLLER" ), + settings ); + m_actionController_gb->setFixedHeight( 100 ); + m_actionController_gb->ledButton()->setChecked( ! m_keysActive ); + connect( m_actionController_gb->ledButton(), SIGNAL( clicked() ), + this, SLOT( clickedControllerBox( ) ) ); + + + QVBoxLayout * settings_vl = new QVBoxLayout( settings ); + settings_vl->setSpacing( 0 ); + settings_vl->setMargin( 0 ); + settings_vl->addWidget( m_actionController_gb ); + settings_vl->addSpacing( 10 ); + settings_vl->addWidget( m_actionKey_gb ); + settings_vl->addSpacing( 10 ); + settings_vl->addStretch(); + + m_actionsKey_box = new QComboBox( m_actionKey_gb ); + m_actionsKey_box->setGeometry( 10, 20, 150, 22 ); + for( int i = 0; i < MidiControlListener::numActions; ++i ) + { + MidiControlListener::ActionNameMap action = MidiControlListener::action2ActionNameMap( (MidiControlListener::EventAction) i ); + if( action.name != "" ) + { + m_actionsKey_box->addItem( action.name ); + } + } + + m_actionsController_box = new QComboBox( m_actionController_gb ); + m_actionsController_box->setGeometry( 10, 30, 150, 22 ); + for( int i = 0; i < MidiControlListener::numActions; ++i ) + { + MidiControlListener::ActionNameMap action = MidiControlListener::action2ActionNameMap( (MidiControlListener::EventAction) i ); + if( action.name != "" && + action.action != MidiControlListener::ActionControl ) + { + m_actionsController_box->addItem( action.name ); + } + } + + m_controllerSbModel = new lcdSpinBoxModel( /* this */ ); + m_controllerSbModel->setRange( 0, 127 ); + m_controllerSbModel->setStep( 1 ); + m_controllerSbModel->setValue( 63 ); + lcdSpinBox * controllerSb = new lcdSpinBox( 3, m_actionController_gb ); + controllerSb->setModel( m_controllerSbModel ); + controllerSb->setLabel( tr( "CONTROLLER" ) ); + controllerSb->move( 20, 60 ); + + show(); +} + + + + +setupDialogMCL::~setupDialogMCL( void ) +{ +} + + + + +void setupDialogMCL::accept( void ) +{ + if( m_keysActive ) + { + MidiControlListener::ActionNameMap action = + MidiControlListener::actionName2ActionNameMap( + m_actionsKey_box->currentText() ); + + m_parent->mclAddKeyAction( 40, action.action ); + } + else + { + MidiControlListener::ActionNameMap action = + MidiControlListener::actionName2ActionNameMap( + m_actionsController_box->currentText() ); + + m_parent->mclAddControllerAction( m_controllerSbModel->value(), + action.action ); + } + QDialog::accept(); +} + + + + +void setupDialogMCL::clickedKeyBox( void ) +{ + m_keysActive = true; + m_actionKey_gb->ledButton()->setChecked( true ); + m_actionController_gb->ledButton()->setChecked( false ); +} + + + + +void setupDialogMCL::clickedControllerBox( void ) +{ + m_keysActive = false; + m_actionKey_gb->ledButton()->setChecked( false ); + m_actionController_gb->ledButton()->setChecked( true ); +} + + + + +#include "moc_setup_dialog_mcl.cxx" + + +#endif