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
This commit is contained in:
34
ChangeLog
34
ChangeLog
@@ -1,3 +1,37 @@
|
||||
2008-06-02 Paul Giblock <drfaygo/at/gmail/dot/com>
|
||||
|
||||
* 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 <drfaygo/at/gmail/dot/com>
|
||||
|
||||
* src/tracks/pattern.cpp:
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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<controllerConnection *> 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)
|
||||
|
||||
@@ -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<plugin::descriptor> 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
97
include/midi_controller.h
Normal file
97
include/midi_controller.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* midi_controller.h - A controller to receive MIDI control-changes
|
||||
*
|
||||
* Copyright (c) 2008 Paul Giblock <drfaygo/at/gmail.com>
|
||||
*
|
||||
* 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 <QtGui/QWidget>
|
||||
|
||||
#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
|
||||
@@ -77,6 +77,11 @@ automatableModel::~automatableModel()
|
||||
m_linkedModels.last()->unlinkModel( this );
|
||||
m_linkedModels.erase( m_linkedModels.end() - 1 );
|
||||
}
|
||||
|
||||
if( m_controllerConnection )
|
||||
{
|
||||
delete m_controllerConnection;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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() )
|
||||
{
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
159
src/core/midi/midi_controller.cpp
Normal file
159
src/core/midi/midi_controller.cpp
Normal file
@@ -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 <drfaygo/at/gmail.com>
|
||||
*
|
||||
* 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 <Qt/QtXml>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QVector>
|
||||
|
||||
|
||||
#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
|
||||
|
||||
@@ -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 <Ctrl> for free "
|
||||
"positioning." ),
|
||||
tr( "Press <Ctrl> and drag to make "
|
||||
"a copy." ),
|
||||
embed::getIconPixmap( "hint" ), 0 );
|
||||
}
|
||||
else if( m_autoResize == FALSE )
|
||||
|
||||
@@ -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<plugin::descriptor>::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<QWidget *>() )
|
||||
{
|
||||
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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -1151,7 +1151,7 @@ void patternView::paintEvent( QPaintEvent * )
|
||||
p.drawLine(
|
||||
x_base + static_cast<int>(
|
||||
ppt * tact_num ) - 1,
|
||||
height() - ( 5 + 2 *
|
||||
height() - ( 4 + 2 *
|
||||
TCO_BORDER_WIDTH ),
|
||||
x_base + static_cast<int>(
|
||||
ppt * tact_num ) - 1,
|
||||
|
||||
Reference in New Issue
Block a user