2015-11-24 18:00:11 -05:00
/*
2015-11-24 22:32:40 -05:00
Copyright ( C ) 2015 Paul Davis
2015-11-24 18:00:11 -05:00
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 ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2015-11-24 21:10:22 -05:00
# include <cstdlib>
2015-11-24 18:00:11 -05:00
# include <sstream>
# include <algorithm>
2015-11-24 21:10:22 -05:00
# include <stdint.h>
2015-11-24 18:00:11 -05:00
# include <glibmm/fileutils.h>
# include <glibmm/miscutils.h>
# include "pbd/controllable_descriptor.h"
# include "pbd/error.h"
# include "pbd/failed_constructor.h"
# include "pbd/file_utils.h"
2015-11-24 21:41:44 -05:00
# include "pbd/pthread_utils.h"
2015-11-24 18:00:11 -05:00
# include "pbd/compose.h"
2015-11-24 21:41:44 -05:00
# include "pbd/xml++.h"
2015-11-24 18:00:11 -05:00
# include "midi++/port.h"
2015-11-25 12:37:29 -05:00
# include "ardour/async_midi_port.h"
2015-11-24 18:00:11 -05:00
# include "ardour/audioengine.h"
2015-11-25 14:52:58 -06:00
# include "ardour/amp.h"
2015-12-03 12:44:21 -05:00
# include "ardour/bundle.h"
2015-11-25 12:37:29 -05:00
# include "ardour/debug.h"
2015-11-24 18:00:11 -05:00
# include "ardour/filesystem_paths.h"
# include "ardour/midi_port.h"
# include "ardour/midiport_manager.h"
2015-11-25 17:20:00 -05:00
# include "ardour/monitor_processor.h"
2015-11-27 16:34:01 -05:00
# include "ardour/profile.h"
2015-11-25 12:37:29 -05:00
# include "ardour/rc_configuration.h"
# include "ardour/route.h"
# include "ardour/session.h"
2015-12-01 18:45:43 -05:00
# include "ardour/session_configuration.h"
2015-11-25 12:37:29 -05:00
# include "ardour/track.h"
2015-11-24 18:00:11 -05:00
# include "faderport.h"
using namespace ARDOUR ;
2015-11-24 20:12:01 -05:00
using namespace ArdourSurface ;
2015-11-24 18:00:11 -05:00
using namespace PBD ;
using namespace Glib ;
using namespace std ;
# include "i18n.h"
2015-11-24 21:41:44 -05:00
# include "pbd/abstract_ui.cc" // instantiate template
2015-11-24 18:00:11 -05:00
FaderPort : : FaderPort ( Session & s )
: ControlProtocol ( s , _ ( " Faderport " ) )
2015-12-28 10:14:17 -05:00
, AbstractUI < FaderPortRequest > ( name ( ) )
2015-11-24 18:00:11 -05:00
, gui ( 0 )
, connection_state ( ConnectionState ( 0 ) )
, _device_active ( false )
, fader_msb ( 0 )
, fader_lsb ( 0 )
2015-11-25 13:22:35 -05:00
, fader_is_touched ( false )
2015-11-24 22:32:40 -05:00
, button_state ( ButtonState ( 0 ) )
2015-11-24 23:06:19 -05:00
, blink_state ( false )
2015-11-24 18:00:11 -05:00
{
2015-11-25 14:52:58 -06:00
last_encoder_time = 0 ;
2015-11-25 16:34:11 -05:00
2015-11-24 18:00:11 -05:00
boost : : shared_ptr < ARDOUR : : Port > inp ;
boost : : shared_ptr < ARDOUR : : Port > outp ;
inp = AudioEngine : : instance ( ) - > register_input_port ( DataType : : MIDI , " Faderport Recv " , true ) ;
outp = AudioEngine : : instance ( ) - > register_output_port ( DataType : : MIDI , " Faderport Send " , true ) ;
_input_port = boost : : dynamic_pointer_cast < AsyncMIDIPort > ( inp ) ;
_output_port = boost : : dynamic_pointer_cast < AsyncMIDIPort > ( outp ) ;
if ( _input_port = = 0 | | _output_port = = 0 ) {
throw failed_constructor ( ) ;
}
2015-12-03 12:44:21 -05:00
_input_bundle . reset ( new ARDOUR : : Bundle ( _ ( " Faderport Support (Receive) " ) , true ) ) ;
_output_bundle . reset ( new ARDOUR : : Bundle ( _ ( " Faderport Support (Send) " ) , false ) ) ;
_input_bundle - > add_channel (
inp - > name ( ) ,
ARDOUR : : DataType : : MIDI ,
session - > engine ( ) . make_port_name_non_relative ( inp - > name ( ) )
) ;
_output_bundle - > add_channel (
outp - > name ( ) ,
ARDOUR : : DataType : : MIDI ,
session - > engine ( ) . make_port_name_non_relative ( outp - > name ( ) )
) ;
2015-11-25 12:37:29 -05:00
TrackSelectionChanged . connect ( selection_connection , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : gui_track_selection_changed , this , _1 ) , this ) ;
2015-11-24 18:00:11 -05:00
/* Catch port connections and disconnections */
2015-11-24 21:41:44 -05:00
ARDOUR : : AudioEngine : : instance ( ) - > PortConnectedOrDisconnected . connect ( port_connection , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : connection_handler , this , _1 , _2 , _3 , _4 , _5 ) , this ) ;
2015-11-24 18:00:11 -05:00
2015-11-30 12:51:18 -05:00
buttons . insert ( std : : make_pair ( Mute , Button ( * this , _ ( " Mute " ) , Mute , 21 ) ) ) ;
buttons . insert ( std : : make_pair ( Solo , Button ( * this , _ ( " Solo " ) , Solo , 22 ) ) ) ;
buttons . insert ( std : : make_pair ( Rec , Button ( * this , _ ( " Rec " ) , Rec , 23 ) ) ) ;
buttons . insert ( std : : make_pair ( Left , Button ( * this , _ ( " Left " ) , Left , 20 ) ) ) ;
buttons . insert ( std : : make_pair ( Bank , Button ( * this , _ ( " Bank " ) , Bank , 19 ) ) ) ;
buttons . insert ( std : : make_pair ( Right , Button ( * this , _ ( " Right " ) , Right , 18 ) ) ) ;
buttons . insert ( std : : make_pair ( Output , Button ( * this , _ ( " Output " ) , Output , 17 ) ) ) ;
buttons . insert ( std : : make_pair ( FP_Read , Button ( * this , _ ( " Read " ) , FP_Read , 13 ) ) ) ;
buttons . insert ( std : : make_pair ( FP_Write , Button ( * this , _ ( " Write " ) , FP_Write , 14 ) ) ) ;
buttons . insert ( std : : make_pair ( FP_Touch , Button ( * this , _ ( " Touch " ) , FP_Touch , 15 ) ) ) ;
buttons . insert ( std : : make_pair ( FP_Off , Button ( * this , _ ( " Off " ) , FP_Off , 16 ) ) ) ;
buttons . insert ( std : : make_pair ( Mix , Button ( * this , _ ( " Mix " ) , Mix , 12 ) ) ) ;
buttons . insert ( std : : make_pair ( Proj , Button ( * this , _ ( " Proj " ) , Proj , 11 ) ) ) ;
buttons . insert ( std : : make_pair ( Trns , Button ( * this , _ ( " Trns " ) , Trns , 10 ) ) ) ;
buttons . insert ( std : : make_pair ( Undo , Button ( * this , _ ( " Undo " ) , Undo , 9 ) ) ) ;
buttons . insert ( std : : make_pair ( Shift , Button ( * this , _ ( " Shift " ) , Shift , 5 ) ) ) ;
buttons . insert ( std : : make_pair ( Punch , Button ( * this , _ ( " Punch " ) , Punch , 6 ) ) ) ;
buttons . insert ( std : : make_pair ( User , Button ( * this , _ ( " User " ) , User , 7 ) ) ) ;
buttons . insert ( std : : make_pair ( Loop , Button ( * this , _ ( " Loop " ) , Loop , 8 ) ) ) ;
buttons . insert ( std : : make_pair ( Rewind , Button ( * this , _ ( " Rewind " ) , Rewind , 4 ) ) ) ;
buttons . insert ( std : : make_pair ( Ffwd , Button ( * this , _ ( " Ffwd " ) , Ffwd , 3 ) ) ) ;
buttons . insert ( std : : make_pair ( Stop , Button ( * this , _ ( " Stop " ) , Stop , 2 ) ) ) ;
buttons . insert ( std : : make_pair ( Play , Button ( * this , _ ( " Play " ) , Play , 1 ) ) ) ;
buttons . insert ( std : : make_pair ( RecEnable , Button ( * this , _ ( " RecEnable " ) , RecEnable , 0 ) ) ) ;
buttons . insert ( std : : make_pair ( FaderTouch , Button ( * this , _ ( " Fader (touch) " ) , FaderTouch , - 1 ) ) ) ;
2015-12-01 13:15:38 -05:00
get_button ( Shift ) . set_flash ( true ) ;
get_button ( Mix ) . set_flash ( true ) ;
get_button ( Proj ) . set_flash ( true ) ;
get_button ( Trns ) . set_flash ( true ) ;
get_button ( User ) . set_flash ( true ) ;
2015-11-30 12:51:18 -05:00
get_button ( Left ) . set_action ( boost : : bind ( & FaderPort : : left , this ) , true ) ;
get_button ( Right ) . set_action ( boost : : bind ( & FaderPort : : right , this ) , true ) ;
get_button ( Undo ) . set_action ( boost : : bind ( & FaderPort : : undo , this ) , true ) ;
get_button ( Undo ) . set_action ( boost : : bind ( & FaderPort : : redo , this ) , true , ShiftDown ) ;
get_button ( Undo ) . set_flash ( true ) ;
get_button ( FP_Read ) . set_action ( boost : : bind ( & FaderPort : : read , this ) , true ) ;
2015-12-14 14:42:12 -05:00
get_button ( FP_Read ) . set_action ( boost : : bind ( & FaderPort : : off , this ) , false , LongPress ) ;
2015-11-30 12:51:18 -05:00
get_button ( FP_Write ) . set_action ( boost : : bind ( & FaderPort : : write , this ) , true ) ;
2015-12-14 14:42:12 -05:00
get_button ( FP_Write ) . set_action ( boost : : bind ( & FaderPort : : off , this ) , false , LongPress ) ;
2015-11-30 12:51:18 -05:00
get_button ( FP_Touch ) . set_action ( boost : : bind ( & FaderPort : : touch , this ) , true ) ;
2015-12-14 14:42:12 -05:00
get_button ( FP_Touch ) . set_action ( boost : : bind ( & FaderPort : : off , this ) , false , LongPress ) ;
2015-11-30 12:51:18 -05:00
get_button ( FP_Off ) . set_action ( boost : : bind ( & FaderPort : : off , this ) , true ) ;
get_button ( Play ) . set_action ( boost : : bind ( & BasicUI : : transport_play , this , true ) , true ) ;
get_button ( RecEnable ) . set_action ( boost : : bind ( & BasicUI : : rec_enable_toggle , this ) , true ) ;
2015-11-24 23:06:19 -05:00
/* Stop is a modifier, so we have to use its own button state to get
the default action ( since StopDown will be set when looking for the
action to invoke .
*/
2015-11-30 12:51:18 -05:00
get_button ( Stop ) . set_action ( boost : : bind ( & BasicUI : : transport_stop , this ) , true , StopDown ) ;
get_button ( Ffwd ) . set_action ( boost : : bind ( & BasicUI : : ffwd , this ) , true ) ;
2015-11-24 23:06:19 -05:00
/* See comments about Stop above .. */
2015-11-30 12:51:18 -05:00
get_button ( Rewind ) . set_action ( boost : : bind ( & BasicUI : : rewind , this ) , true , RewindDown ) ;
get_button ( Rewind ) . set_action ( boost : : bind ( & BasicUI : : goto_zero , this ) , true , ButtonState ( RewindDown | StopDown ) ) ;
get_button ( Rewind ) . set_action ( boost : : bind ( & BasicUI : : goto_start , this ) , true , ButtonState ( RewindDown | ShiftDown ) ) ;
2015-11-24 23:41:10 -05:00
2015-11-30 12:51:18 -05:00
get_button ( Ffwd ) . set_action ( boost : : bind ( & BasicUI : : ffwd , this ) , true ) ;
get_button ( Ffwd ) . set_action ( boost : : bind ( & BasicUI : : goto_end , this ) , true , ShiftDown ) ;
2015-11-24 23:27:55 -05:00
2015-12-01 10:35:30 -05:00
get_button ( Punch ) . set_action ( boost : : bind ( & FaderPort : : punch , this ) , true ) ;
2015-11-30 12:51:18 -05:00
get_button ( Loop ) . set_action ( boost : : bind ( & BasicUI : : loop_toggle , this ) , true ) ;
get_button ( Loop ) . set_action ( boost : : bind ( & BasicUI : : add_marker , this , string ( ) ) , true , ShiftDown ) ;
2015-11-24 23:27:55 -05:00
2015-11-30 12:51:18 -05:00
get_button ( Punch ) . set_action ( boost : : bind ( & BasicUI : : prev_marker , this ) , true , ShiftDown ) ;
2016-01-10 23:32:15 -05:00
get_button ( User ) . set_action ( boost : : bind ( & BasicUI : : next_marker , this ) , true , ButtonState ( ShiftDown | UserDown ) ) ;
2015-11-24 23:27:55 -05:00
2015-11-30 12:51:18 -05:00
get_button ( Mute ) . set_action ( boost : : bind ( & FaderPort : : mute , this ) , true ) ;
get_button ( Solo ) . set_action ( boost : : bind ( & FaderPort : : solo , this ) , true ) ;
get_button ( Rec ) . set_action ( boost : : bind ( & FaderPort : : rec_enable , this ) , true ) ;
2015-11-25 16:34:11 -05:00
2015-11-30 12:51:18 -05:00
get_button ( Output ) . set_action ( boost : : bind ( & FaderPort : : use_master , this ) , true ) ;
get_button ( Output ) . set_action ( boost : : bind ( & FaderPort : : use_monitor , this ) , true , ShiftDown ) ;
2015-11-24 18:00:11 -05:00
}
FaderPort : : ~ FaderPort ( )
{
if ( _input_port ) {
2015-11-24 23:20:39 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " unregistering input port %1 \n " , boost : : shared_ptr < ARDOUR : : Port > ( _input_port ) - > name ( ) ) ) ;
2015-11-24 18:00:11 -05:00
AudioEngine : : instance ( ) - > unregister_port ( _input_port ) ;
_input_port . reset ( ) ;
}
if ( _output_port ) {
// _output_port->drain (10000); //ToDo: is this necessary? It hangs the shutdown, for me
2015-11-24 23:20:39 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " unregistering output port %1 \n " , boost : : shared_ptr < ARDOUR : : Port > ( _output_port ) - > name ( ) ) ) ;
2015-11-24 18:00:11 -05:00
AudioEngine : : instance ( ) - > unregister_port ( _output_port ) ;
_output_port . reset ( ) ;
}
tear_down_gui ( ) ;
}
2015-12-28 10:14:17 -05:00
void *
FaderPort : : request_factory ( uint32_t num_requests )
{
/* AbstractUI<T>::request_buffer_factory() is a template method only
instantiated in this source module . To provide something visible for
use in the interface / descriptor , we have this static method that is
template - free .
*/
return request_buffer_factory ( num_requests ) ;
}
2015-11-24 21:41:44 -05:00
void
FaderPort : : start_midi_handling ( )
{
/* handle device inquiry response */
_input_port - > parser ( ) - > sysex . connect_same_thread ( midi_connections , boost : : bind ( & FaderPort : : sysex_handler , this , _1 , _2 , _3 ) ) ;
2015-11-30 12:51:18 -05:00
/* handle buttons */
_input_port - > parser ( ) - > poly_pressure . connect_same_thread ( midi_connections , boost : : bind ( & FaderPort : : button_handler , this , _1 , _2 ) ) ;
2015-11-24 21:41:44 -05:00
/* handle encoder */
_input_port - > parser ( ) - > pitchbend . connect_same_thread ( midi_connections , boost : : bind ( & FaderPort : : encoder_handler , this , _1 , _2 ) ) ;
/* handle fader */
_input_port - > parser ( ) - > controller . connect_same_thread ( midi_connections , boost : : bind ( & FaderPort : : fader_handler , this , _1 , _2 ) ) ;
/* This connection means that whenever data is ready from the input
* port , the relevant thread will invoke our : : midi_input_handler ( )
* method , which will read the data , and invoke the parser .
*/
_input_port - > xthread ( ) . set_receive_handler ( sigc : : bind ( sigc : : mem_fun ( this , & FaderPort : : midi_input_handler ) , _input_port ) ) ;
_input_port - > xthread ( ) . attach ( main_loop ( ) - > get_context ( ) ) ;
}
void
FaderPort : : stop_midi_handling ( )
{
midi_connections . drop_connections ( ) ;
/* Note: the input handler is still active at this point, but we're no
* longer connected to any of the parser signals
*/
}
void
FaderPort : : do_request ( FaderPortRequest * req )
{
if ( req - > type = = CallSlot ) {
call_slot ( MISSING_INVALIDATOR , req - > the_slot ) ;
} else if ( req - > type = = Quit ) {
stop ( ) ;
}
}
int
FaderPort : : stop ( )
{
BaseUI : : quit ( ) ;
return 0 ;
}
void
FaderPort : : thread_init ( )
{
struct sched_param rtparam ;
2015-12-28 10:14:17 -05:00
pthread_set_name ( event_loop_name ( ) . c_str ( ) ) ;
2015-11-24 21:41:44 -05:00
2015-12-28 10:14:17 -05:00
PBD : : notify_event_loops_about_thread_creation ( pthread_self ( ) , event_loop_name ( ) , 2048 ) ;
ARDOUR : : SessionEvent : : create_per_thread_pool ( event_loop_name ( ) , 128 ) ;
2015-11-24 21:41:44 -05:00
memset ( & rtparam , 0 , sizeof ( rtparam ) ) ;
rtparam . sched_priority = 9 ; /* XXX should be relative to audio (JACK) thread */
if ( pthread_setschedparam ( pthread_self ( ) , SCHED_FIFO , & rtparam ) ! = 0 ) {
// do we care? not particularly.
}
}
2015-11-24 21:10:22 -05:00
void
FaderPort : : all_lights_out ( )
{
for ( ButtonMap : : iterator b = buttons . begin ( ) ; b ! = buttons . end ( ) ; + + b ) {
2015-12-08 11:07:37 -05:00
b - > second . set_led_state ( _output_port , false ) ;
2015-11-24 21:10:22 -05:00
}
}
2015-11-30 12:51:18 -05:00
FaderPort : : Button &
FaderPort : : get_button ( ButtonID id ) const
2015-11-24 21:02:18 -05:00
{
2015-11-24 21:10:22 -05:00
ButtonMap : : const_iterator b = buttons . find ( id ) ;
2015-11-24 21:02:18 -05:00
assert ( b ! = buttons . end ( ) ) ;
2015-11-30 12:51:18 -05:00
return const_cast < Button & > ( b - > second ) ;
2015-11-24 21:02:18 -05:00
}
2015-12-01 13:15:38 -05:00
bool
FaderPort : : button_long_press_timeout ( ButtonID id )
{
if ( buttons_down . find ( id ) ! = buttons_down . end ( ) ) {
get_button ( id ) . invoke ( ButtonState ( LongPress | button_state ) , false ) ;
} else {
/* release happened and somehow we were not cancelled */
}
2015-12-03 18:38:09 -05:00
/* whichever button this was, we've used it ... don't invoke the
release action .
*/
consumed . insert ( id ) ;
2015-12-01 13:15:38 -05:00
return false ; /* don't get called again */
}
void
FaderPort : : start_press_timeout ( Button & button , ButtonID id )
{
Glib : : RefPtr < Glib : : TimeoutSource > timeout = Glib : : TimeoutSource : : create ( 500 ) ; // milliseconds
button . timeout_connection = timeout - > connect ( sigc : : bind ( sigc : : mem_fun ( * this , & FaderPort : : button_long_press_timeout ) , id ) ) ;
timeout - > attach ( main_loop ( ) - > get_context ( ) ) ;
}
2015-11-24 18:00:11 -05:00
void
2015-11-30 12:51:18 -05:00
FaderPort : : button_handler ( MIDI : : Parser & , MIDI : : EventTwoBytes * tb )
2015-11-24 18:00:11 -05:00
{
2015-11-24 22:32:40 -05:00
ButtonID id ( ButtonID ( tb - > controller_number ) ) ;
2015-11-30 12:51:18 -05:00
Button & button ( get_button ( id ) ) ;
2016-01-10 23:32:15 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " button event for ID %1 named %3, press ? %2 \n " , ( int ) tb - > controller_number , ( tb - > value ? " yes " : " no " ) , button . name ) ) ;
2016-01-07 16:40:14 -05:00
2015-12-01 13:15:38 -05:00
if ( tb - > value ) {
buttons_down . insert ( id ) ;
} else {
buttons_down . erase ( id ) ;
button . timeout_connection . disconnect ( ) ;
}
2015-11-24 22:32:40 -05:00
2015-12-01 16:19:16 -05:00
ButtonState bs ( ButtonState ( 0 ) ) ;
2015-11-24 22:32:40 -05:00
switch ( id ) {
case Shift :
2016-01-10 23:32:15 -05:00
bs = ShiftDown ;
2015-11-24 22:32:40 -05:00
break ;
case Stop :
2015-12-01 16:19:16 -05:00
bs = StopDown ;
2015-11-24 22:32:40 -05:00
break ;
case Rewind :
2015-12-01 16:19:16 -05:00
bs = RewindDown ;
2015-11-24 22:32:40 -05:00
break ;
2015-11-27 16:41:26 -05:00
case User :
2015-12-01 16:19:16 -05:00
bs = UserDown ;
2015-11-27 16:41:26 -05:00
break ;
2015-11-25 13:22:35 -05:00
case FaderTouch :
fader_is_touched = tb - > value ;
2015-11-27 10:22:01 -05:00
if ( _current_route ) {
boost : : shared_ptr < AutomationControl > gain = _current_route - > gain_control ( ) ;
if ( gain ) {
framepos_t now = session - > engine ( ) . sample_time ( ) ;
if ( tb - > value ) {
gain - > start_touch ( now ) ;
} else {
gain - > stop_touch ( true , now ) ;
}
}
}
2015-11-25 13:22:35 -05:00
break ;
2015-11-24 22:32:40 -05:00
default :
2015-12-01 13:15:38 -05:00
if ( tb - > value ) {
start_press_timeout ( button , id ) ;
}
2015-11-24 22:32:40 -05:00
break ;
}
2015-12-01 16:19:16 -05:00
if ( bs ) {
button_state = ( tb - > value ? ButtonState ( button_state | bs ) : ButtonState ( button_state & ~ bs ) ) ;
2016-01-10 23:32:15 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " reset button state to %1 using %2 \n " , button_state , ( int ) bs ) ) ;
2015-12-01 16:19:16 -05:00
}
2015-11-30 12:51:18 -05:00
if ( button . uses_flash ( ) ) {
button . set_led_state ( _output_port , ( int ) tb - > value ) ;
2015-11-24 21:41:44 -05:00
}
2015-11-24 22:32:40 -05:00
2015-12-03 18:38:09 -05:00
set < ButtonID > : : iterator c = consumed . find ( id ) ;
if ( c = = consumed . end ( ) ) {
button . invoke ( button_state , tb - > value ? true : false ) ;
} else {
2016-01-10 23:32:15 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , " button was consumed, ignored \n " ) ;
2015-12-03 18:38:09 -05:00
consumed . erase ( c ) ;
}
2015-11-24 18:00:11 -05:00
}
void
FaderPort : : encoder_handler ( MIDI : : Parser & , MIDI : : pitchbend_t pb )
{
2015-11-25 14:52:58 -06:00
int delta = 1 ;
2015-11-27 16:34:01 -05:00
if ( pb > = 8192 ) {
2015-11-25 14:52:58 -06:00
delta = - 1 ;
2015-11-24 18:00:11 -05:00
}
2015-11-25 14:52:58 -06:00
//knob debouncing and hysteresis. The presonus encoder often sends bursts of events, or goes the wrong direction
{
last_last_encoder_delta = last_encoder_delta ;
last_encoder_delta = delta ;
microseconds_t now = get_microseconds ( ) ;
if ( ( now - last_encoder_time ) < 10 * 1000 ) { //require at least 10ms interval between changes, because the device sometimes sends multiple deltas
return ;
}
if ( ( now - last_encoder_time ) < 100 * 1000 ) { //avoid directional changes while "spinning", 100ms window
if ( ( delta = = last_encoder_delta ) & & ( delta = = last_last_encoder_delta ) ) {
last_good_encoder_delta = delta ; //3 in a row, grudgingly accept this as the new direction
}
if ( delta ! = last_good_encoder_delta ) { //otherwise ensure we keep going the same way
delta = last_good_encoder_delta ;
}
} else { //we aren't yet in a spin window, just assume this move is really what we want
//NOTE: if you are worried about where these get initialized, here it is.
last_last_encoder_delta = delta ;
last_encoder_delta = delta ;
}
last_encoder_time = now ;
last_good_encoder_delta = delta ;
}
2015-11-25 16:34:11 -05:00
2015-11-25 14:52:58 -06:00
if ( _current_route ) {
2015-11-27 16:41:26 -05:00
ButtonState trim_modifier ;
ButtonState width_modifier ;
if ( Profile - > get_mixbus ( ) ) {
trim_modifier = ShiftDown ;
width_modifier = ButtonState ( 0 ) ;
} else {
trim_modifier = UserDown ;
width_modifier = ShiftDown ;
}
if ( ( button_state & trim_modifier ) = = trim_modifier ) { // mod+encoder = input trim
2015-12-03 18:38:09 -05:00
boost : : shared_ptr < AutomationControl > trim = _current_route - > trim ( ) - > gain_control ( ) ;
if ( trim ) {
float val = trim - > get_user ( ) ; //for gain elements, the "user" value is in dB
2015-11-25 14:52:58 -06:00
val + = delta ;
2015-12-03 18:38:09 -05:00
trim - > set_user ( val ) ;
2015-11-25 14:52:58 -06:00
}
2015-11-27 16:41:26 -05:00
} else if ( width_modifier & & ( ( button_state & width_modifier ) = = width_modifier ) ) {
ardour_pan_width ( delta ) ;
} else { // pan/balance
2015-11-27 16:34:01 -05:00
if ( ! Profile - > get_mixbus ( ) ) {
2015-11-27 16:41:26 -05:00
ardour_pan_azimuth ( delta ) ;
2015-11-27 16:34:01 -05:00
} else {
mixbus_pan ( delta ) ;
}
2015-11-25 14:52:58 -06:00
}
}
2015-12-03 18:38:09 -05:00
/* if the user button was pressed, mark it as consumed so that its
* release action has no effect .
*/
if ( ! Profile - > get_mixbus ( ) & & ( button_state & UserDown ) ) {
consumed . insert ( User ) ;
}
2015-11-24 18:00:11 -05:00
}
void
FaderPort : : fader_handler ( MIDI : : Parser & , MIDI : : EventTwoBytes * tb )
{
bool was_fader = false ;
if ( tb - > controller_number = = 0x0 ) {
fader_msb = tb - > value ;
was_fader = true ;
} else if ( tb - > controller_number = = 0x20 ) {
fader_lsb = tb - > value ;
was_fader = true ;
}
if ( was_fader ) {
2015-11-25 13:22:35 -05:00
if ( _current_route ) {
boost : : shared_ptr < AutomationControl > gain = _current_route - > gain_control ( ) ;
if ( gain ) {
int ival = ( fader_msb < < 7 ) | fader_lsb ;
float val = gain - > interface_to_internal ( ival / 16384.0 ) ;
_current_route - > set_gain ( val , this ) ;
}
}
2015-11-24 18:00:11 -05:00
}
}
void
FaderPort : : sysex_handler ( MIDI : : Parser & p , MIDI : : byte * buf , size_t sz )
{
2016-01-07 16:40:14 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " sysex message received, size = %1 \n " , sz ) ) ;
2015-11-24 18:00:11 -05:00
if ( sz < 17 ) {
return ;
}
2015-11-24 23:06:19 -05:00
if ( buf [ 2 ] ! = 0x7f | |
buf [ 3 ] ! = 0x06 | |
buf [ 4 ] ! = 0x02 | |
buf [ 5 ] ! = 0x0 | |
buf [ 6 ] ! = 0x1 | |
buf [ 7 ] ! = 0x06 | |
buf [ 8 ] ! = 0x02 | |
buf [ 9 ] ! = 0x0 | |
buf [ 10 ] ! = 0x01 | |
buf [ 11 ] ! = 0x0 ) {
return ;
}
2015-11-24 18:00:11 -05:00
2015-11-24 23:06:19 -05:00
_device_active = true ;
2015-11-24 18:00:11 -05:00
2015-11-30 20:13:49 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , " FaderPort identified via MIDI Device Inquiry response \n " ) ;
2015-11-24 18:00:11 -05:00
2015-11-24 23:06:19 -05:00
/* put it into native mode */
2015-11-24 18:00:11 -05:00
2015-11-24 23:06:19 -05:00
MIDI : : byte native [ 3 ] ;
native [ 0 ] = 0x91 ;
native [ 1 ] = 0x00 ;
native [ 2 ] = 0x64 ;
2015-11-24 21:10:22 -05:00
2015-11-24 23:06:19 -05:00
_output_port - > write ( native , 3 , 0 ) ;
all_lights_out ( ) ;
/* catch up on state */
2015-12-08 11:07:37 -05:00
map_transport_state ( ) ;
map_recenable_state ( ) ;
2015-11-24 18:00:11 -05:00
}
int
2015-11-24 21:41:44 -05:00
FaderPort : : set_active ( bool yn )
2015-11-24 18:00:11 -05:00
{
2015-12-14 11:48:09 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " Faderport::set_active init with yn: '%1' \n " , yn ) ) ;
2015-11-24 21:41:44 -05:00
if ( yn = = active ( ) ) {
return 0 ;
}
if ( yn ) {
/* start event loop */
BaseUI : : run ( ) ;
connect_session_signals ( ) ;
2015-11-24 23:06:19 -05:00
Glib : : RefPtr < Glib : : TimeoutSource > blink_timeout = Glib : : TimeoutSource : : create ( 200 ) ; // milliseconds
blink_connection = blink_timeout - > connect ( sigc : : mem_fun ( * this , & FaderPort : : blink ) ) ;
blink_timeout - > attach ( main_loop ( ) - > get_context ( ) ) ;
2015-12-14 13:28:24 -05:00
Glib : : RefPtr < Glib : : TimeoutSource > periodic_timeout = Glib : : TimeoutSource : : create ( 100 ) ; // milliseconds
2015-12-14 14:41:38 -05:00
periodic_connection = periodic_timeout - > connect ( sigc : : mem_fun ( * this , & FaderPort : : periodic ) ) ;
2015-12-14 13:28:24 -05:00
periodic_timeout - > attach ( main_loop ( ) - > get_context ( ) ) ;
2015-11-24 21:41:44 -05:00
} else {
BaseUI : : quit ( ) ;
close ( ) ;
}
ControlProtocol : : set_active ( yn ) ;
2015-12-14 11:48:09 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " Faderport::set_active done with yn: '%1' \n " , yn ) ) ;
2015-11-24 21:41:44 -05:00
2015-11-24 18:00:11 -05:00
return 0 ;
}
2015-12-14 13:28:24 -05:00
bool
FaderPort : : periodic ( )
{
if ( ! _current_route ) {
return true ;
}
ARDOUR : : AutoState gain_state = _current_route - > gain_control ( ) - > automation_state ( ) ;
if ( gain_state = = ARDOUR : : Touch | | gain_state = = ARDOUR : : Play ) {
map_gain ( ) ;
}
return true ;
}
2015-12-03 08:36:56 -05:00
void
FaderPort : : stop_blinking ( ButtonID id )
{
blinkers . remove ( id ) ;
get_button ( id ) . set_led_state ( _output_port , false ) ;
}
void
FaderPort : : start_blinking ( ButtonID id )
{
blinkers . push_back ( id ) ;
get_button ( id ) . set_led_state ( _output_port , true ) ;
}
2015-11-24 23:06:19 -05:00
bool
FaderPort : : blink ( )
{
blink_state = ! blink_state ;
for ( Blinkers : : iterator b = blinkers . begin ( ) ; b ! = blinkers . end ( ) ; b + + ) {
2015-11-30 12:51:18 -05:00
get_button ( * b ) . set_led_state ( _output_port , blink_state ) ;
2015-11-24 23:06:19 -05:00
}
return true ;
}
2015-11-24 21:41:44 -05:00
void
FaderPort : : close ( )
{
2015-11-24 23:20:39 -05:00
all_lights_out ( ) ;
2015-11-24 21:41:44 -05:00
stop_midi_handling ( ) ;
session_connections . drop_connections ( ) ;
2015-11-24 23:06:19 -05:00
port_connection . disconnect ( ) ;
blink_connection . disconnect ( ) ;
2015-11-25 12:37:29 -05:00
selection_connection . disconnect ( ) ;
route_connections . drop_connections ( ) ;
2015-11-24 23:06:19 -05:00
#if 0
2015-11-24 21:41:44 -05:00
route_connections . drop_connections ( ) ;
# endif
}
2015-11-24 23:06:19 -05:00
void
2015-12-08 11:07:37 -05:00
FaderPort : : map_recenable_state ( )
2015-11-24 23:06:19 -05:00
{
switch ( session - > record_status ( ) ) {
case Session : : Disabled :
2015-12-03 08:36:56 -05:00
stop_blinking ( RecEnable ) ;
2015-11-24 23:06:19 -05:00
break ;
case Session : : Enabled :
2015-12-03 08:36:56 -05:00
start_blinking ( RecEnable ) ;
2015-11-24 23:06:19 -05:00
break ;
case Session : : Recording :
2015-12-03 08:36:56 -05:00
stop_blinking ( RecEnable ) ;
2015-11-24 23:06:19 -05:00
break ;
}
}
void
2015-12-08 11:07:37 -05:00
FaderPort : : map_transport_state ( )
2015-11-24 23:06:19 -05:00
{
2015-11-30 12:51:18 -05:00
get_button ( Loop ) . set_led_state ( _output_port , session - > get_play_loop ( ) ) ;
2015-12-08 11:07:37 -05:00
float ts = session - > transport_speed ( ) ;
if ( ts = = 0 ) {
stop_blinking ( Play ) ;
} else if ( fabs ( ts ) = = 1.0 ) {
stop_blinking ( Play ) ;
get_button ( Play ) . set_led_state ( _output_port , true ) ;
} else {
start_blinking ( Play ) ;
}
2015-11-30 12:51:18 -05:00
get_button ( Stop ) . set_led_state ( _output_port , session - > transport_stopped ( ) ) ;
get_button ( Rewind ) . set_led_state ( _output_port , session - > transport_speed ( ) < 0.0 ) ;
get_button ( Ffwd ) . set_led_state ( _output_port , session - > transport_speed ( ) > 1.0 ) ;
2015-11-24 23:06:19 -05:00
}
2015-12-01 18:45:43 -05:00
void
FaderPort : : parameter_changed ( string what )
{
if ( what = = " punch-in " | | what = = " punch-out " ) {
bool in = session - > config . get_punch_in ( ) ;
bool out = session - > config . get_punch_out ( ) ;
if ( in & & out ) {
get_button ( Punch ) . set_led_state ( _output_port , true ) ;
blinkers . remove ( Punch ) ;
} else if ( in | | out ) {
2015-12-03 08:36:56 -05:00
start_blinking ( Punch ) ;
2015-12-01 18:45:43 -05:00
} else {
2015-12-03 08:36:56 -05:00
stop_blinking ( Punch ) ;
2015-12-01 18:45:43 -05:00
}
}
}
2015-11-24 21:41:44 -05:00
void
FaderPort : : connect_session_signals ( )
{
2015-12-08 11:07:37 -05:00
session - > RecordStateChanged . connect ( session_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : map_recenable_state , this ) , this ) ;
session - > TransportStateChange . connect ( session_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : map_transport_state , this ) , this ) ;
2015-12-01 18:45:43 -05:00
/* not session, but treat it similarly */
session - > config . ParameterChanged . connect ( session_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : parameter_changed , this , _1 ) , this ) ;
2015-11-24 21:41:44 -05:00
}
2015-11-24 18:00:11 -05:00
bool
FaderPort : : midi_input_handler ( Glib : : IOCondition ioc , boost : : shared_ptr < ARDOUR : : AsyncMIDIPort > port )
{
2015-11-24 23:20:39 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " something happend on %1 \n " , boost : : shared_ptr < MIDI : : Port > ( port ) - > name ( ) ) ) ;
2015-11-24 18:00:11 -05:00
if ( ioc & ~ IO_IN ) {
return false ;
}
if ( ioc & IO_IN ) {
2015-12-07 12:03:32 -05:00
port - > clear ( ) ;
2015-11-24 23:20:39 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " data available on %1 \n " , boost : : shared_ptr < MIDI : : Port > ( port ) - > name ( ) ) ) ;
2015-11-24 18:00:11 -05:00
framepos_t now = session - > engine ( ) . sample_time ( ) ;
port - > parse ( now ) ;
}
return true ;
}
XMLNode &
FaderPort : : get_state ( )
{
XMLNode & node ( ControlProtocol : : get_state ( ) ) ;
XMLNode * child ;
child = new XMLNode ( X_ ( " Input " ) ) ;
child - > add_child_nocopy ( boost : : shared_ptr < ARDOUR : : Port > ( _input_port ) - > get_state ( ) ) ;
node . add_child_nocopy ( * child ) ;
child = new XMLNode ( X_ ( " Output " ) ) ;
child - > add_child_nocopy ( boost : : shared_ptr < ARDOUR : : Port > ( _output_port ) - > get_state ( ) ) ;
node . add_child_nocopy ( * child ) ;
2015-11-30 12:51:18 -05:00
/* Save action state for Mix, Proj, Trns and User buttons, since these
* are user controlled . We can only save named - action operations , since
* internal functions are just pointers to functions and hard to
* serialize without enumerating them all somewhere .
*/
node . add_child_nocopy ( get_button ( Mix ) . get_state ( ) ) ;
node . add_child_nocopy ( get_button ( Proj ) . get_state ( ) ) ;
node . add_child_nocopy ( get_button ( Trns ) . get_state ( ) ) ;
node . add_child_nocopy ( get_button ( User ) . get_state ( ) ) ;
2015-11-24 18:00:11 -05:00
return node ;
}
int
FaderPort : : set_state ( const XMLNode & node , int version )
{
XMLNodeList nlist ;
XMLNodeConstIterator niter ;
XMLNode const * child ;
if ( ControlProtocol : : set_state ( node , version ) ) {
return - 1 ;
}
if ( ( child = node . child ( X_ ( " Input " ) ) ) ! = 0 ) {
XMLNode * portnode = child - > child ( Port : : state_node_name . c_str ( ) ) ;
if ( portnode ) {
boost : : shared_ptr < ARDOUR : : Port > ( _input_port ) - > set_state ( * portnode , version ) ;
}
}
if ( ( child = node . child ( X_ ( " Output " ) ) ) ! = 0 ) {
XMLNode * portnode = child - > child ( Port : : state_node_name . c_str ( ) ) ;
if ( portnode ) {
boost : : shared_ptr < ARDOUR : : Port > ( _output_port ) - > set_state ( * portnode , version ) ;
}
}
2015-11-30 12:51:18 -05:00
for ( XMLNodeList : : const_iterator n = node . children ( ) . begin ( ) ; n ! = node . children ( ) . end ( ) ; + + n ) {
if ( ( * n ) - > name ( ) = = X_ ( " Button " ) ) {
XMLProperty const * prop = ( * n ) - > property ( X_ ( " id " ) ) ;
if ( ! prop ) {
continue ;
}
int xid = atoi ( prop - > value ( ) ) ;
ButtonMap : : iterator b = buttons . find ( ButtonID ( xid ) ) ;
if ( b = = buttons . end ( ) ) {
continue ;
}
b - > second . set_state ( * * n ) ;
}
}
2015-11-24 18:00:11 -05:00
return 0 ;
}
bool
FaderPort : : connection_handler ( boost : : weak_ptr < ARDOUR : : Port > , std : : string name1 , boost : : weak_ptr < ARDOUR : : Port > , std : : string name2 , bool yn )
{
2015-12-04 18:11:05 -06:00
DEBUG_TRACE ( DEBUG : : FaderPort , " FaderPort::connection_handler start \n " ) ;
2015-11-24 18:00:11 -05:00
if ( ! _input_port | | ! _output_port ) {
return false ;
}
string ni = ARDOUR : : AudioEngine : : instance ( ) - > make_port_name_non_relative ( boost : : shared_ptr < ARDOUR : : Port > ( _input_port ) - > name ( ) ) ;
string no = ARDOUR : : AudioEngine : : instance ( ) - > make_port_name_non_relative ( boost : : shared_ptr < ARDOUR : : Port > ( _output_port ) - > name ( ) ) ;
if ( ni = = name1 | | ni = = name2 ) {
if ( yn ) {
connection_state | = InputConnected ;
} else {
connection_state & = ~ InputConnected ;
}
} else if ( no = = name1 | | no = = name2 ) {
if ( yn ) {
connection_state | = OutputConnected ;
} else {
connection_state & = ~ OutputConnected ;
}
} else {
2015-12-04 18:11:05 -06:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " Connections between %1 and %2 changed, but I ignored it \n " , name1 , name2 ) ) ;
2015-11-24 18:00:11 -05:00
/* not our ports */
return false ;
}
if ( ( connection_state & ( InputConnected | OutputConnected ) ) = = ( InputConnected | OutputConnected ) ) {
/* XXX this is a horrible hack. Without a short sleep here,
something prevents the device wakeup messages from being
sent and / or the responses from being received .
*/
g_usleep ( 100000 ) ;
2016-01-07 16:40:14 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , " device now connected for both input and output \n " ) ;
2015-11-24 18:00:11 -05:00
connected ( ) ;
} else {
2015-11-24 23:29:03 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , " Device disconnected (input or output or both) or not yet fully connected \n " ) ;
2015-11-24 18:00:11 -05:00
_device_active = false ;
}
2015-11-30 12:51:18 -05:00
ConnectionChange ( ) ; /* emit signal for our GUI */
2015-12-04 18:11:05 -06:00
DEBUG_TRACE ( DEBUG : : FaderPort , " FaderPort::connection_handler end \n " ) ;
2015-11-24 18:00:11 -05:00
return true ; /* connection status changed */
}
void
FaderPort : : connected ( )
{
2016-01-07 16:40:14 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , " sending device inquiry message... \n " ) ;
2015-11-24 18:00:11 -05:00
2015-11-24 21:41:44 -05:00
start_midi_handling ( ) ;
2015-11-24 18:00:11 -05:00
/* send device inquiry */
MIDI : : byte buf [ 6 ] ;
buf [ 0 ] = 0xf0 ;
buf [ 1 ] = 0x7e ;
buf [ 2 ] = 0x7f ;
buf [ 3 ] = 0x06 ;
buf [ 4 ] = 0x01 ;
buf [ 5 ] = 0xf7 ;
_output_port - > write ( buf , 6 , 0 ) ;
}
2015-11-24 21:02:18 -05:00
void
2015-11-30 12:51:18 -05:00
FaderPort : : Button : : invoke ( FaderPort : : ButtonState bs , bool press )
2015-11-24 21:02:18 -05:00
{
2015-12-01 11:20:09 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " invoke button %1 for %2 state %3%4%5 \n " , id , ( press ? " press " : " release " ) , hex , bs , dec ) ) ;
2015-11-30 12:51:18 -05:00
ToDoMap : : iterator x ;
if ( press ) {
if ( ( x = on_press . find ( bs ) ) = = on_press . end ( ) ) {
2016-01-10 23:32:15 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " no press action for button %1 state %2 @ %3 in %4 \n " , id , bs , this , & on_press ) ) ;
2015-11-30 12:51:18 -05:00
return ;
}
} else {
2015-11-30 15:05:30 -05:00
if ( ( x = on_release . find ( bs ) ) = = on_release . end ( ) ) {
2016-01-10 23:32:15 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " no release action for button %1 state %2 @%3 in %4 \n " , id , bs , this , & on_release ) ) ;
2015-11-30 12:51:18 -05:00
return ;
}
}
switch ( x - > second . type ) {
2015-11-24 21:02:18 -05:00
case NamedAction :
2015-11-30 12:51:18 -05:00
if ( ! x - > second . action_name . empty ( ) ) {
fp . access_action ( x - > second . action_name ) ;
2015-11-24 21:02:18 -05:00
}
2015-11-30 20:13:49 -05:00
break ;
2015-11-24 21:02:18 -05:00
case InternalFunction :
2015-11-30 12:51:18 -05:00
if ( x - > second . function ) {
x - > second . function ( ) ;
}
}
}
2015-11-24 21:02:18 -05:00
void
2015-11-30 12:51:18 -05:00
FaderPort : : Button : : set_action ( string const & name , bool when_pressed , FaderPort : : ButtonState bs )
2015-11-24 21:02:18 -05:00
{
2015-11-24 22:32:40 -05:00
ToDo todo ;
2015-11-30 12:51:18 -05:00
todo . type = NamedAction ;
2015-11-24 22:32:40 -05:00
2015-11-24 21:02:18 -05:00
if ( when_pressed ) {
2015-11-30 12:51:18 -05:00
if ( name . empty ( ) ) {
on_press . erase ( bs ) ;
} else {
2015-11-30 20:54:23 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " set button %1 to action %2 on press + %3%4%5 \n " , id , name , bs ) ) ;
2015-11-30 12:51:18 -05:00
todo . action_name = name ;
on_press [ bs ] = todo ;
}
2015-11-24 21:02:18 -05:00
} else {
2015-11-30 12:51:18 -05:00
if ( name . empty ( ) ) {
on_release . erase ( bs ) ;
} else {
2015-11-30 20:54:23 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " set button %1 to action %2 on release + %3%4%5 \n " , id , name , bs ) ) ;
2015-11-30 12:51:18 -05:00
todo . action_name = name ;
on_release [ bs ] = todo ;
}
2015-11-24 21:02:18 -05:00
}
}
2015-11-30 13:50:33 -05:00
string
FaderPort : : Button : : get_action ( bool press , FaderPort : : ButtonState bs )
{
ToDoMap : : iterator x ;
if ( press ) {
if ( ( x = on_press . find ( bs ) ) = = on_press . end ( ) ) {
return string ( ) ;
}
if ( x - > second . type ! = NamedAction ) {
return string ( ) ;
}
return x - > second . action_name ;
} else {
if ( ( x = on_release . find ( bs ) ) = = on_release . end ( ) ) {
return string ( ) ;
}
if ( x - > second . type ! = NamedAction ) {
return string ( ) ;
}
return x - > second . action_name ;
}
}
2015-11-24 21:02:18 -05:00
void
2015-11-30 12:51:18 -05:00
FaderPort : : Button : : set_action ( boost : : function < void ( ) > f , bool when_pressed , FaderPort : : ButtonState bs )
2015-11-24 21:02:18 -05:00
{
2015-11-24 22:32:40 -05:00
ToDo todo ;
2015-11-30 12:51:18 -05:00
todo . type = InternalFunction ;
2015-11-24 22:32:40 -05:00
2015-11-24 21:02:18 -05:00
if ( when_pressed ) {
2016-01-10 23:32:15 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " set button %1 (%2) @ %5 to some functor on press + %3 in %4 \n " , id , name , bs , & on_press , this ) ) ;
2015-11-24 22:32:40 -05:00
todo . function = f ;
on_press [ bs ] = todo ;
2015-11-24 21:02:18 -05:00
} else {
2016-01-10 23:32:15 -05:00
DEBUG_TRACE ( DEBUG : : FaderPort , string_compose ( " set button %1 (%2) @ %5 to some functor on release + %3 \n " , id , name , bs , this ) ) ;
2015-11-24 22:32:40 -05:00
todo . function = f ;
on_release [ bs ] = todo ;
2015-11-24 21:02:18 -05:00
}
}
void
2015-12-08 11:07:37 -05:00
FaderPort : : Button : : set_led_state ( boost : : shared_ptr < MIDI : : Port > port , bool onoff )
2015-11-24 21:02:18 -05:00
{
2015-11-24 21:10:22 -05:00
if ( out < 0 ) {
/* fader button ID - no LED */
return ;
}
2015-11-24 21:02:18 -05:00
MIDI : : byte buf [ 3 ] ;
buf [ 0 ] = 0xa0 ;
buf [ 1 ] = out ;
buf [ 2 ] = onoff ? 1 : 0 ;
port - > write ( buf , 3 , 0 ) ;
}
2015-11-25 12:37:29 -05:00
2015-11-30 12:51:18 -05:00
int
FaderPort : : Button : : set_state ( XMLNode const & node )
{
const XMLProperty * prop = node . property ( " id " ) ;
if ( ! prop ) {
return - 1 ;
}
int xid = atoi ( prop - > value ( ) ) ;
if ( xid ! = id ) {
return - 1 ;
}
typedef pair < string , FaderPort : : ButtonState > state_pair_t ;
vector < state_pair_t > state_pairs ;
state_pairs . push_back ( make_pair ( string ( " plain " ) , ButtonState ( 0 ) ) ) ;
state_pairs . push_back ( make_pair ( string ( " shift " ) , ShiftDown ) ) ;
state_pairs . push_back ( make_pair ( string ( " long " ) , LongPress ) ) ;
for ( vector < state_pair_t > : : const_iterator sp = state_pairs . begin ( ) ; sp ! = state_pairs . end ( ) ; + + sp ) {
string propname ;
propname = sp - > first + X_ ( " -press " ) ;
2015-11-30 20:54:23 -05:00
if ( ( prop = node . property ( propname ) ) ! = 0 ) {
set_action ( prop - > value ( ) , true , sp - > second ) ;
2015-11-30 12:51:18 -05:00
}
propname = sp - > first + X_ ( " -release " ) ;
2015-11-30 20:54:23 -05:00
if ( ( prop = node . property ( propname ) ) ! = 0 ) {
set_action ( prop - > value ( ) , false , sp - > second ) ;
2015-11-30 12:51:18 -05:00
}
}
return 0 ;
}
XMLNode &
FaderPort : : Button : : get_state ( ) const
{
XMLNode * node = new XMLNode ( X_ ( " Button " ) ) ;
char buf [ 16 ] ;
snprintf ( buf , sizeof ( buf ) , " %d " , id ) ;
node - > add_property ( X_ ( " id " ) , buf ) ;
ToDoMap : : const_iterator x ;
ToDo null ;
null . type = NamedAction ;
typedef pair < string , FaderPort : : ButtonState > state_pair_t ;
vector < state_pair_t > state_pairs ;
state_pairs . push_back ( make_pair ( string ( " plain " ) , ButtonState ( 0 ) ) ) ;
state_pairs . push_back ( make_pair ( string ( " shift " ) , ShiftDown ) ) ;
state_pairs . push_back ( make_pair ( string ( " long " ) , LongPress ) ) ;
for ( vector < state_pair_t > : : const_iterator sp = state_pairs . begin ( ) ; sp ! = state_pairs . end ( ) ; + + sp ) {
if ( ( x = on_press . find ( sp - > second ) ) ! = on_press . end ( ) ) {
if ( x - > second . type = = NamedAction ) {
node - > add_property ( string ( sp - > first + X_ ( " -press " ) ) . c_str ( ) , x - > second . action_name ) ;
}
}
if ( ( x = on_release . find ( sp - > second ) ) ! = on_release . end ( ) ) {
if ( x - > second . type = = NamedAction ) {
node - > add_property ( string ( sp - > first + X_ ( " -release " ) ) . c_str ( ) , x - > second . action_name ) ;
}
}
}
return * node ;
}
2015-11-25 12:37:29 -05:00
void
FaderPort : : gui_track_selection_changed ( RouteNotificationListPtr routes )
{
2015-11-25 16:34:11 -05:00
boost : : shared_ptr < Route > r ;
if ( ! routes - > empty ( ) ) {
r = routes - > front ( ) . lock ( ) ;
2015-11-25 12:37:29 -05:00
}
2015-11-25 16:34:11 -05:00
set_current_route ( r ) ;
}
void
FaderPort : : drop_current_route ( )
{
if ( _current_route ) {
if ( _current_route = = session - > monitor_out ( ) ) {
set_current_route ( session - > master_out ( ) ) ;
} else {
set_current_route ( boost : : shared_ptr < Route > ( ) ) ;
}
}
}
void
FaderPort : : set_current_route ( boost : : shared_ptr < Route > r )
{
2015-11-25 12:37:29 -05:00
route_connections . drop_connections ( ) ;
2015-11-25 16:34:11 -05:00
_current_route = r ;
2015-11-25 17:56:22 -05:00
/* turn this off. It will be turned on back on in use_master() or
use_monitor ( ) as appropriate .
*/
2015-11-30 12:51:18 -05:00
get_button ( Output ) . set_led_state ( _output_port , false ) ;
2015-11-25 17:56:22 -05:00
2015-11-25 12:37:29 -05:00
if ( _current_route ) {
2015-11-25 16:34:11 -05:00
_current_route - > DropReferences . connect ( route_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : drop_current_route , this ) , this ) ;
2015-11-25 12:37:29 -05:00
_current_route - > mute_changed . connect ( route_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : map_mute , this , _1 ) , this ) ;
_current_route - > solo_changed . connect ( route_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : map_solo , this , _1 , _2 , _3 ) , this ) ;
_current_route - > listen_changed . connect ( route_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : map_listen , this , _1 , _2 ) , this ) ;
2015-11-25 13:22:35 -05:00
2015-11-25 12:37:29 -05:00
boost : : shared_ptr < Track > t = boost : : dynamic_pointer_cast < Track > ( _current_route ) ;
if ( t ) {
t - > RecordEnableChanged . connect ( route_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : map_recenable , this ) , this ) ;
}
2015-11-25 13:22:35 -05:00
boost : : shared_ptr < AutomationControl > control = _current_route - > gain_control ( ) ;
if ( control ) {
control - > Changed . connect ( route_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : map_gain , this ) , this ) ;
2015-12-02 20:06:29 -06:00
control - > alist ( ) - > automation_state_changed . connect ( route_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : map_auto , this ) , this ) ;
2015-11-25 13:22:35 -05:00
}
2015-11-25 17:20:00 -05:00
boost : : shared_ptr < MonitorProcessor > mp = _current_route - > monitor_control ( ) ;
if ( mp ) {
mp - > cut_control ( ) - > Changed . connect ( route_connections , MISSING_INVALIDATOR , boost : : bind ( & FaderPort : : map_cut , this ) , this ) ;
}
2015-11-25 12:37:29 -05:00
}
2015-11-27 16:41:26 -05:00
2015-11-25 17:33:42 -06:00
//ToDo: subscribe to the fader automation modes so we can light the LEDs
2015-11-25 12:37:29 -05:00
map_route_state ( ) ;
}
2015-12-02 20:06:29 -06:00
void
FaderPort : : map_auto ( )
{
2015-12-14 14:42:12 -05:00
/* Under no circumstances send a message to "enable" the LED state of
* the Off button , because this will disable the fader .
*/
2015-12-14 13:27:50 -05:00
2015-12-02 20:06:29 -06:00
boost : : shared_ptr < AutomationControl > control = _current_route - > gain_control ( ) ;
const AutoState as = control - > automation_state ( ) ;
switch ( as ) {
case ARDOUR : : Play :
get_button ( FP_Read ) . set_led_state ( _output_port , true ) ;
get_button ( FP_Write ) . set_led_state ( _output_port , false ) ;
get_button ( FP_Touch ) . set_led_state ( _output_port , false ) ;
break ;
case ARDOUR : : Write :
get_button ( FP_Read ) . set_led_state ( _output_port , false ) ;
get_button ( FP_Write ) . set_led_state ( _output_port , true ) ;
get_button ( FP_Touch ) . set_led_state ( _output_port , false ) ;
break ;
case ARDOUR : : Touch :
get_button ( FP_Read ) . set_led_state ( _output_port , false ) ;
get_button ( FP_Write ) . set_led_state ( _output_port , false ) ;
get_button ( FP_Touch ) . set_led_state ( _output_port , true ) ;
break ;
case ARDOUR : : Off :
get_button ( FP_Read ) . set_led_state ( _output_port , false ) ;
get_button ( FP_Write ) . set_led_state ( _output_port , false ) ;
get_button ( FP_Touch ) . set_led_state ( _output_port , false ) ;
break ;
}
2015-12-03 12:44:21 -05:00
2015-12-02 20:06:29 -06:00
}
2015-11-25 17:20:00 -05:00
void
FaderPort : : map_cut ( )
{
boost : : shared_ptr < MonitorProcessor > mp = _current_route - > monitor_control ( ) ;
if ( mp ) {
bool yn = mp - > cut_all ( ) ;
if ( yn ) {
2015-12-03 08:36:56 -05:00
start_blinking ( Mute ) ;
2015-11-25 17:20:00 -05:00
} else {
2015-12-03 08:36:56 -05:00
stop_blinking ( Mute ) ;
2015-11-25 17:20:00 -05:00
}
} else {
2015-12-03 08:36:56 -05:00
stop_blinking ( Mute ) ;
2015-11-25 17:20:00 -05:00
}
}
2015-11-25 12:37:29 -05:00
void
FaderPort : : map_mute ( void * )
{
2015-12-08 11:07:37 -05:00
if ( _current_route ) {
if ( _current_route - > muted ( ) ) {
stop_blinking ( Mute ) ;
get_button ( Mute ) . set_led_state ( _output_port , true ) ;
} else if ( _current_route - > muted_by_others ( ) ) {
start_blinking ( Mute ) ;
} else {
stop_blinking ( Mute ) ;
}
} else {
stop_blinking ( Mute ) ;
}
2015-11-25 12:37:29 -05:00
}
void
FaderPort : : map_solo ( bool , void * , bool )
{
2015-12-08 11:07:37 -05:00
if ( _current_route ) {
get_button ( Solo ) . set_led_state ( _output_port , _current_route - > soloed ( ) | | _current_route - > listening_via_monitor ( ) ) ;
} else {
get_button ( Solo ) . set_led_state ( _output_port , false ) ;
}
2015-11-25 12:37:29 -05:00
}
void
FaderPort : : map_listen ( void * , bool )
{
2015-12-08 11:07:37 -05:00
if ( _current_route ) {
get_button ( Solo ) . set_led_state ( _output_port , _current_route - > listening_via_monitor ( ) ) ;
} else {
get_button ( Solo ) . set_led_state ( _output_port , false ) ;
}
2015-11-25 12:37:29 -05:00
}
void
FaderPort : : map_recenable ( )
{
boost : : shared_ptr < Track > t = boost : : dynamic_pointer_cast < Track > ( _current_route ) ;
if ( t ) {
2015-11-30 12:51:18 -05:00
get_button ( Rec ) . set_led_state ( _output_port , t - > record_enabled ( ) ) ;
2015-11-25 12:37:29 -05:00
} else {
2015-11-30 12:51:18 -05:00
get_button ( Rec ) . set_led_state ( _output_port , false ) ;
2015-11-25 12:37:29 -05:00
}
}
2015-11-25 13:22:35 -05:00
void
FaderPort : : map_gain ( )
{
if ( fader_is_touched ) {
/* Do not send fader moves while the user is touching the fader */
return ;
}
if ( ! _current_route ) {
return ;
}
boost : : shared_ptr < AutomationControl > control = _current_route - > gain_control ( ) ;
double val ;
if ( ! control ) {
val = 0.0 ;
} else {
val = control - > internal_to_interface ( control - > get_value ( ) ) ;
}
/* Faderport sends fader position with range 0..16384 (though some of
* the least - significant bits at the top end are missing - it may only
* get to 1636 X or so ) .
*
* But . . . position must be sent in the range 0. .1023 .
*
* Thanks , Obama .
*/
int ival = ( int ) lrintf ( val * 1023.0 ) ;
/* MIDI normalization requires that we send two separate messages here,
* not one single 6 byte one .
*/
MIDI : : byte buf [ 3 ] ;
buf [ 0 ] = 0xb0 ;
buf [ 1 ] = 0x0 ;
buf [ 2 ] = ival > > 7 ;
_output_port - > write ( buf , 3 , 0 ) ;
buf [ 1 ] = 0x20 ;
buf [ 2 ] = ival & 0x7f ;
_output_port - > write ( buf , 3 , 0 ) ;
}
2015-11-25 12:37:29 -05:00
void
FaderPort : : map_route_state ( )
{
if ( ! _current_route ) {
2015-12-03 08:36:56 -05:00
stop_blinking ( Mute ) ;
stop_blinking ( Solo ) ;
2015-11-30 12:51:18 -05:00
get_button ( Rec ) . set_led_state ( _output_port , false ) ;
2015-11-25 12:37:29 -05:00
} else {
/* arguments to these map_*() methods are all ignored */
map_solo ( false , 0 , false ) ;
map_recenable ( ) ;
2015-11-25 13:22:35 -05:00
map_gain ( ) ;
2015-12-02 20:06:29 -06:00
map_auto ( ) ;
2015-12-08 11:07:37 -05:00
if ( _current_route = = session - > monitor_out ( ) ) {
map_cut ( ) ;
} else {
map_mute ( 0 ) ;
}
2015-11-25 12:37:29 -05:00
}
}
2015-11-29 11:32:28 -05:00
2015-12-03 12:44:21 -05:00
list < boost : : shared_ptr < ARDOUR : : Bundle > >
FaderPort : : bundles ( )
{
list < boost : : shared_ptr < ARDOUR : : Bundle > > b ;
if ( _input_bundle ) {
b . push_back ( _input_bundle ) ;
b . push_back ( _output_bundle ) ;
}
return b ;
}
2015-11-29 11:32:28 -05:00
boost : : shared_ptr < Port >
FaderPort : : output_port ( )
{
return _output_port ;
}
boost : : shared_ptr < Port >
FaderPort : : input_port ( )
{
return _input_port ;
}
void
FaderPort : : set_action ( ButtonID id , std : : string const & action_name , bool on_press , ButtonState bs )
{
2015-11-30 12:51:18 -05:00
get_button ( id ) . set_action ( action_name , on_press , bs ) ;
2015-11-29 11:32:28 -05:00
}
2015-11-30 13:50:33 -05:00
string
FaderPort : : get_action ( ButtonID id , bool press , ButtonState bs )
{
return get_button ( id ) . get_action ( press , bs ) ;
}