diff --git a/include/engine.h b/include/engine.h index c3da8429b..0817da100 100644 --- a/include/engine.h +++ b/include/engine.h @@ -50,6 +50,7 @@ class song; class songEditor; class ladspa2LMMS; class controllerRackView; +class MidiControlListener; class EXPORT engine @@ -195,6 +196,7 @@ private: static projectJournal * s_projectJournal; static dummyTrackContainer * s_dummyTC; static controllerRackView * s_controllerRackView; + static MidiControlListener * s_midiControlListener; // GUI static mainWindow * s_mainWindow; diff --git a/include/midi_control_listener.h b/include/midi_control_listener.h new file mode 100644 index 000000000..50a2c1868 --- /dev/null +++ b/include/midi_control_listener.h @@ -0,0 +1,72 @@ +/* + * midi_control_listener.h - listens to MIDI source(s) for commands that + * start/stops LMMS' transportation, + * or toggles loop + * + * 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 _MIDI_CONTROL_LISTENER_H +#define _MIDI_CONTROL_LISTENER_H + +#include "midi_event_processor.h" +#include "midi_port.h" +#include "note.h" + +class MidiControlListener : public midiEventProcessor +{ +public: + typedef enum + { + ActionNone = 0, + ActionPlay, + ActionStop + } EventAction; + typedef QMap ActionMap; + + MidiControlListener(); + virtual ~MidiControlListener(); + + virtual void processInEvent( const midiEvent & _me, + const midiTime & _time ); + virtual void processOutEvent( const midiEvent & _me, + const midiTime & _time ) + { + } + +private: + void act( EventAction _action ); + + + midiPort m_port; + + bool m_controlKeyPressed; // flag, whether the control key is pressed + + // configuration + bool m_useControlKey; // true: use control key (two key sequence); false: single key sequence + int m_controlKey; // number of the control key (0 - NumKeys) + int m_controlChannel; // number of channel (0 - 15) or -1 for all channels + ActionMap m_actionMapKeys; + ActionMap m_actionMapControllers; +} ; + +#endif + diff --git a/src/core/engine.cpp b/src/core/engine.cpp index 77fc2c2a5..8cbd31a8e 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -45,6 +45,7 @@ #include "project_notes.h" #include "song_editor.h" #include "song.h" +#include "midi_control_listener.h" #include "resources_db.h" #include "local_resources_provider.h" @@ -72,6 +73,7 @@ projectJournal * engine::s_projectJournal = NULL; ladspa2LMMS * engine::s_ladspaManager = NULL; dummyTrackContainer * engine::s_dummyTC = NULL; controllerRackView * engine::s_controllerRackView = NULL; +MidiControlListener * engine::s_midiControlListener = NULL; QMap engine::s_pluginFileHandling; LmmsStyle * engine::s_lmmsStyle = NULL; @@ -117,6 +119,8 @@ void engine::init( const bool _has_gui ) s_mixer->initDevices(); + s_midiControlListener = new MidiControlListener(); + if( s_hasGUI ) { s_mainWindow = new mainWindow; diff --git a/src/core/midi/midi_control_listener.cpp b/src/core/midi/midi_control_listener.cpp new file mode 100644 index 000000000..bcd41bb66 --- /dev/null +++ b/src/core/midi/midi_control_listener.cpp @@ -0,0 +1,163 @@ +/* + * midi_control_listener.cpp - implementation of the MIDI listener that + * controls LMMS' transportation and other things + * + * 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 "midi_control_listener.h" +#include "mixer.h" +#include "midi_client.h" +#include "midi_port.h" +#include "engine.h" +#include "note.h" +#include "song.h" + + +MidiControlListener::MidiControlListener() : + m_port( "unnamed_midi_controller", + engine::getMixer()->getMidiClient(), this, NULL, + midiPort::Input ), + m_controlKeyPressed( false ) +{ + // default settings + m_useControlKey = true; // use control key + m_controlKey = 60; // C5 + m_controlChannel = -1; // listen on all channels + +#warning TODO replace hard-coded defaults + // test config + m_port.subscribeReadablePort( "24:0", true ); + m_actionMapKeys[57] = ActionPlay; + m_actionMapKeys[59] = ActionStop; + m_actionMapControllers[24] = ActionPlay; + m_actionMapControllers[23] = ActionStop; +} + + + + +MidiControlListener::~MidiControlListener() +{ +} + + + + +void MidiControlListener::processInEvent( const midiEvent & _me, + const midiTime & _time ) +{ + // pre-check whether this MIDI packet suits our configuration + switch( _me.m_type ) + { + case MidiNoteOn: + case MidiNoteOff: + case MidiControlChange: + // ignore commands for other channels + if( m_controlChannel != -1 && + m_controlChannel != _me.channel() ) + { + return; + } + break; + default: + // ignore commands other than note on/off and + // control change + return; + } + + // check MIDI packet type and act upon + switch( _me.m_type ) + { + case MidiNoteOn: + if( _me.key() == m_controlKey) + { + if( _me.velocity() == 0 ) + { + // special case: key press with velocity 0 + // means key release + m_controlKeyPressed = false; + break; + } + m_controlKeyPressed = true; + break; + } + else if( !m_useControlKey || m_controlKeyPressed ) + { + if( _me.velocity() > 0 && + m_actionMapKeys.contains( _me.key() ) ) + { + act( m_actionMapKeys.value( _me.key(), + ActionNone ) ); + } + } + break; + + case MidiNoteOff: + if( _me.key() == m_controlKey ) + { + m_controlKeyPressed = false; + } + break; + + case MidiControlChange: + // controller changed to a value other than zero + if( _me.m_data.m_param[1] > 0 ) + { + switch( m_actionMapControllers.value( + _me.m_data.m_param[0], ActionNone ) ) + { + case ActionNone: + break; + case ActionPlay: + engine::getSong()->play(); + break; + case ActionStop: + engine::getSong()->stop(); + break; + } + } + break; + default: + // nop + break; + } +} + + + + +void MidiControlListener::act( EventAction _action ) +{ + switch( _action ) + { + case ActionNone: + break; + case ActionPlay: + engine::getSong()->play(); + break; + case ActionStop: + engine::getSong()->stop(); + break; + } +} +