2008-06-02 17:41:35 -04:00
/*
Copyright ( C ) 1998 - 2006 Paul Davis
2009-10-20 20:15:42 -04:00
2008-06-02 17:41:35 -04: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 .
*/
2009-12-30 07:41:10 -05:00
# include <stdint.h>
2010-01-01 13:14:32 -05:00
# include <cmath>
2008-06-02 17:41:35 -04:00
# include <climits>
2010-04-06 12:57:35 -04:00
# include <iostream>
2009-12-21 13:23:07 -05:00
2009-10-29 20:21:40 -04:00
# include "pbd/error.h"
# include "pbd/xml++.h"
2012-06-26 15:10:11 -04:00
# include "pbd/stacktrace.h"
2015-07-09 21:16:44 -04:00
# include "pbd/compose.h"
2009-12-21 13:23:07 -05:00
2013-09-05 04:50:58 -04:00
# include "midi++/types.h" // Added by JE - 06-01-2009. All instances of 'byte' changed to 'MIDI::byte' (for clarification)
2009-10-29 20:21:40 -04:00
# include "midi++/port.h"
# include "midi++/channel.h"
2009-12-21 13:23:07 -05:00
2013-08-07 22:22:11 -04:00
# include "ardour/async_midi_port.h"
2009-10-29 20:21:40 -04:00
# include "ardour/automation_control.h"
2016-05-16 11:08:32 -04:00
# include "ardour/controllable_descriptor.h"
2012-06-25 21:55:53 -04:00
# include "ardour/midi_ui.h"
2009-12-30 11:48:58 -05:00
# include "ardour/utils.h"
2015-07-09 21:16:44 -04:00
# include "ardour/debug.h"
2008-06-02 17:41:35 -04:00
# include "midicontrollable.h"
2012-03-06 20:11:22 -05:00
# include "generic_midi_control_protocol.h"
2008-06-02 17:41:35 -04:00
2009-12-10 22:18:17 -05:00
using namespace std ;
2008-06-02 17:41:35 -04:00
using namespace MIDI ;
using namespace PBD ;
using namespace ARDOUR ;
2013-08-07 22:22:11 -04:00
MIDIControllable : : MIDIControllable ( GenericMidiControlProtocol * s , MIDI : : Parser & p , bool m )
2012-03-06 20:11:22 -05:00
: _surface ( s )
, controllable ( 0 )
2009-12-31 18:43:47 -05:00
, _descriptor ( 0 )
2013-08-07 22:22:11 -04:00
, _parser ( p )
2010-01-01 13:14:32 -05:00
, _momentary ( m )
2009-12-10 21:00:22 -05:00
{
2009-12-30 07:41:10 -05:00
_learned = false ; /* from URI */
2015-07-24 20:34:22 -04:00
_encoder = No_enc ;
2009-12-30 07:41:10 -05:00
setting = false ;
last_value = 0 ; // got a better idea ?
2011-12-14 10:57:48 -05:00
last_controllable_value = 0.0f ;
2009-12-30 07:41:10 -05:00
control_type = none ;
2015-11-23 12:26:23 -05:00
control_rpn = - 1 ;
control_nrpn = - 1 ;
2009-12-30 07:41:10 -05:00
_control_description = " MIDI Control: none " ;
2013-09-05 04:50:58 -04:00
control_additional = ( MIDI : : byte ) - 1 ;
2009-12-10 21:00:22 -05:00
}
2013-08-07 22:22:11 -04:00
MIDIControllable : : MIDIControllable ( GenericMidiControlProtocol * s , MIDI : : Parser & p , Controllable & c , bool m )
2012-03-06 20:11:22 -05:00
: _surface ( s )
2009-12-31 18:43:47 -05:00
, _descriptor ( 0 )
2013-08-07 22:22:11 -04:00
, _parser ( p )
2010-01-01 13:14:32 -05:00
, _momentary ( m )
2009-12-10 21:00:22 -05:00
{
2012-06-28 11:38:07 -04:00
set_controllable ( & c ) ;
2015-10-05 10:17:49 -04:00
2009-12-30 07:41:10 -05:00
_learned = true ; /* from controllable */
2015-07-24 20:34:22 -04:00
_encoder = No_enc ;
2009-12-30 07:41:10 -05:00
setting = false ;
last_value = 0 ; // got a better idea ?
2011-12-14 10:57:48 -05:00
last_controllable_value = 0.0f ;
2009-12-30 07:41:10 -05:00
control_type = none ;
2015-11-23 12:26:23 -05:00
control_rpn = - 1 ;
control_nrpn = - 1 ;
2009-12-30 07:41:10 -05:00
_control_description = " MIDI Control: none " ;
2013-09-05 04:50:58 -04:00
control_additional = ( MIDI : : byte ) - 1 ;
2009-12-10 21:00:22 -05:00
}
MIDIControllable : : ~ MIDIControllable ( )
{
2012-06-26 15:10:11 -04:00
drop_external_control ( ) ;
2017-01-20 05:40:46 -05:00
delete _descriptor ;
_descriptor = 0 ;
2009-12-10 21:00:22 -05:00
}
2009-12-30 07:41:10 -05:00
int
MIDIControllable : : init ( const std : : string & s )
2008-06-02 17:41:35 -04:00
{
2009-12-30 07:41:10 -05:00
_current_uri = s ;
2009-12-31 18:43:47 -05:00
delete _descriptor ;
_descriptor = new ControllableDescriptor ;
return _descriptor - > set ( s ) ;
2008-06-02 17:41:35 -04:00
}
void
MIDIControllable : : midi_forget ( )
{
/* stop listening for incoming messages, but retain
our existing event + type information .
*/
2009-10-20 20:15:42 -04:00
2009-12-19 15:26:31 -05:00
midi_sense_connection [ 0 ] . disconnect ( ) ;
midi_sense_connection [ 1 ] . disconnect ( ) ;
midi_learn_connection . disconnect ( ) ;
}
2009-10-20 20:15:42 -04:00
2009-12-19 15:26:31 -05:00
void
MIDIControllable : : drop_external_control ( )
{
2009-12-30 07:41:10 -05:00
midi_forget ( ) ;
2015-11-23 12:26:23 -05:00
control_rpn = - 1 ;
control_nrpn = - 1 ;
2009-12-19 15:26:31 -05:00
control_type = none ;
2013-09-05 04:50:58 -04:00
control_additional = ( MIDI : : byte ) - 1 ;
2008-06-02 17:41:35 -04:00
}
2009-12-10 21:00:22 -05:00
void
2009-12-28 11:49:44 -05:00
MIDIControllable : : set_controllable ( Controllable * c )
2009-12-10 21:00:22 -05:00
{
2012-06-28 11:38:07 -04:00
if ( c = = controllable ) {
return ;
}
2015-10-05 10:17:49 -04:00
2012-06-28 11:38:07 -04:00
controllable_death_connection . disconnect ( ) ;
2009-12-28 11:49:44 -05:00
controllable = c ;
2012-06-28 11:38:07 -04:00
2013-01-21 08:20:43 -05:00
if ( controllable ) {
last_controllable_value = controllable - > get_value ( ) ;
} else {
last_controllable_value = 0.0f ; // is there a better value?
}
2013-01-17 09:48:17 -05:00
2012-06-28 11:38:07 -04:00
if ( controllable ) {
controllable - > Destroyed . connect ( controllable_death_connection , MISSING_INVALIDATOR ,
2016-02-03 07:23:55 -05:00
boost : : bind ( & MIDIControllable : : drop_controllable , this , _1 ) ,
2012-06-28 11:38:07 -04:00
MidiControlUI : : instance ( ) ) ;
}
2009-12-10 21:00:22 -05:00
}
2008-06-02 17:41:35 -04:00
void
MIDIControllable : : midi_rebind ( channel_t c )
{
if ( c > = 0 ) {
bind_midi ( c , control_type , control_additional ) ;
} else {
midi_forget ( ) ;
}
}
void
MIDIControllable : : learn_about_external_control ( )
{
drop_external_control ( ) ;
2013-08-07 22:22:11 -04:00
_parser . any . connect_same_thread ( midi_learn_connection , boost : : bind ( & MIDIControllable : : midi_receiver , this , _1 , _2 , _3 ) ) ;
2008-06-02 17:41:35 -04:00
}
void
MIDIControllable : : stop_learning ( )
{
midi_learn_connection . disconnect ( ) ;
}
2012-03-06 20:11:22 -05:00
int
2010-04-06 12:57:35 -04:00
MIDIControllable : : control_to_midi ( float val )
2009-02-18 17:30:06 -05:00
{
2016-07-10 11:20:05 -04:00
if ( controllable - > is_gain_like ( ) ) {
return gain_to_slider_position ( val ) * max_value_for_type ( ) ;
}
2010-04-06 12:57:35 -04:00
float control_min = controllable - > lower ( ) ;
float control_max = controllable - > upper ( ) ;
2014-03-23 13:59:24 -04:00
float control_range = control_max - control_min ;
2009-02-18 17:30:06 -05:00
2012-12-18 20:28:41 -05:00
if ( controllable - > is_toggle ( ) ) {
if ( val > = ( control_min + ( control_range / 2.0f ) ) ) {
return max_value_for_type ( ) ;
} else {
return 0 ;
}
2014-03-23 13:59:24 -04:00
} else {
AutomationControl * actl = dynamic_cast < AutomationControl * > ( controllable ) ;
if ( actl ) {
control_min = actl - > internal_to_interface ( control_min ) ;
control_max = actl - > internal_to_interface ( control_max ) ;
control_range = control_max - control_min ;
val = actl - > internal_to_interface ( val ) ;
}
2012-12-18 20:28:41 -05:00
}
2015-07-21 02:15:53 -04:00
// fiddle value of max so value doesn't jump from 125 to 127 for 1.0
// otherwise decrement won't work.
return ( val - control_min ) / control_range * ( max_value_for_type ( ) - 1 ) ;
2009-02-18 17:30:06 -05:00
}
float
2012-03-06 20:11:22 -05:00
MIDIControllable : : midi_to_control ( int val )
2009-02-18 17:30:06 -05:00
{
2015-12-13 18:53:24 -05:00
/* fiddle with MIDI value so that we get an odd number of integer steps
and can thus represent " middle " precisely as 0.5 . this maps to
the range 0. . + 1.0 ( 0 to 126 )
*/
2010-11-29 12:56:08 -05:00
2015-12-13 18:53:24 -05:00
float fv = ( val = = 0 ? 0 : float ( val - 1 ) / ( max_value_for_type ( ) - 1 ) ) ;
2009-12-30 14:33:52 -05:00
2015-12-13 18:53:24 -05:00
if ( controllable - > is_gain_like ( ) ) {
return controllable - > interface_to_internal ( fv ) ;
}
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " Raw value %1 float %2 \n " , val , fv ) ) ;
2009-02-18 17:30:06 -05:00
2010-04-06 12:57:35 -04:00
float control_min = controllable - > lower ( ) ;
float control_max = controllable - > upper ( ) ;
2014-03-23 13:59:24 -04:00
float control_range = control_max - control_min ;
2015-12-13 18:53:24 -05:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " Min %1 Max %2 Range %3 \n " , control_min , control_max , control_range ) ) ;
2014-03-23 13:59:24 -04:00
AutomationControl * actl = dynamic_cast < AutomationControl * > ( controllable ) ;
if ( actl ) {
if ( fv = = 0.f ) return control_min ;
if ( fv = = 1.f ) return control_max ;
control_min = actl - > internal_to_interface ( control_min ) ;
control_max = actl - > internal_to_interface ( control_max ) ;
control_range = control_max - control_min ;
return actl - > interface_to_internal ( ( fv * control_range ) + control_min ) ;
}
2012-03-06 20:11:22 -05:00
return ( fv * control_range ) + control_min ;
2009-02-18 17:30:06 -05:00
}
2009-10-20 20:15:42 -04:00
void
MIDIControllable : : midi_sense_note_on ( Parser & p , EventTwoBytes * tb )
2008-06-02 17:41:35 -04:00
{
midi_sense_note ( p , tb , true ) ;
}
2009-10-20 20:15:42 -04:00
void
MIDIControllable : : midi_sense_note_off ( Parser & p , EventTwoBytes * tb )
2008-06-02 17:41:35 -04:00
{
midi_sense_note ( p , tb , false ) ;
}
2012-06-25 08:33:13 -04:00
int
MIDIControllable : : lookup_controllable ( )
{
if ( ! _descriptor ) {
return - 1 ;
}
boost : : shared_ptr < Controllable > c = _surface - > lookup_controllable ( * _descriptor ) ;
if ( ! c ) {
return - 1 ;
}
2012-06-28 11:38:07 -04:00
set_controllable ( c . get ( ) ) ;
2012-06-25 08:33:13 -04:00
return 0 ;
}
2012-06-25 21:55:53 -04:00
void
2016-02-03 07:23:55 -05:00
MIDIControllable : : drop_controllable ( Controllable * c )
2012-06-25 21:55:53 -04:00
{
2016-02-03 07:23:55 -05:00
if ( c = = controllable ) {
set_controllable ( 0 ) ;
}
2012-06-25 21:55:53 -04:00
}
2008-06-02 17:41:35 -04:00
void
2010-09-02 13:01:36 -04:00
MIDIControllable : : midi_sense_note ( Parser & , EventTwoBytes * msg , bool /*is_on*/ )
2008-06-02 17:41:35 -04:00
{
2015-10-04 14:51:05 -04:00
if ( ! controllable ) {
2012-06-25 08:33:13 -04:00
if ( lookup_controllable ( ) ) {
return ;
}
2009-12-10 21:00:22 -05:00
}
2017-01-23 07:25:56 -05:00
_surface - > maybe_start_touch ( controllable ) ;
2010-01-01 13:14:32 -05:00
if ( ! controllable - > is_toggle ( ) ) {
2012-07-23 09:31:51 -04:00
if ( control_additional = = msg - > note_number ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( msg - > velocity ) , Controllable : : UseGroup ) ;
2015-07-09 21:16:44 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " Note %1 value %2 %3 \n " , ( int ) msg - > note_number , ( float ) midi_to_control ( msg - > velocity ) , current_uri ( ) ) ) ;
2012-07-23 09:31:51 -04:00
}
2008-06-02 17:41:35 -04:00
} else {
2010-01-01 13:14:32 -05:00
if ( control_additional = = msg - > note_number ) {
2015-07-09 21:16:44 -04:00
float new_value = controllable - > get_value ( ) > 0.5f ? 0.0f : 1.0f ;
2017-01-31 09:32:55 -05:00
controllable - > set_value ( new_value , Controllable : : UseGroup ) ;
2015-07-09 21:16:44 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " Note %1 Value %2 %3 \n " , ( int ) msg - > note_number , ( float ) new_value , current_uri ( ) ) ) ;
2008-06-02 17:41:35 -04:00
}
}
2009-12-10 21:00:22 -05:00
last_value = ( MIDI : : byte ) ( controllable - > get_value ( ) * 127.0 ) ; // to prevent feedback fights
2008-06-02 17:41:35 -04:00
}
void
MIDIControllable : : midi_sense_controller ( Parser & , EventTwoBytes * msg )
{
2015-10-04 14:51:05 -04:00
if ( ! controllable ) {
2012-06-25 08:33:13 -04:00
if ( lookup_controllable ( ) ) {
return ;
}
2009-12-10 21:00:22 -05:00
}
2012-06-26 16:49:52 -04:00
assert ( controllable ) ;
2017-01-23 07:25:56 -05:00
_surface - > maybe_start_touch ( controllable ) ;
2009-02-18 18:54:41 -05:00
2008-06-02 17:41:35 -04:00
if ( control_additional = = msg - > controller_number ) {
2010-01-01 13:14:32 -05:00
if ( ! controllable - > is_toggle ( ) ) {
2015-07-24 20:34:22 -04:00
if ( get_encoder ( ) = = No_enc ) {
2015-07-21 02:15:53 -04:00
float new_value = msg - > value ;
float max_value = max ( last_controllable_value , new_value ) ;
float min_value = min ( last_controllable_value , new_value ) ;
float range = max_value - min_value ;
float threshold = ( float ) _surface - > threshold ( ) ;
bool const in_sync = (
range < threshold & &
controllable - > get_value ( ) < = midi_to_control ( max_value ) & &
controllable - > get_value ( ) > = midi_to_control ( min_value )
) ;
/* If the surface is not motorised, we try to prevent jumps when
the MIDI controller and controllable are out of sync .
There might be a better way of doing this .
*/
if ( in_sync | | _surface - > motorised ( ) ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( new_value ) , Controllable : : UseGroup ) ;
2015-07-21 02:15:53 -04:00
}
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " MIDI CC %1 value %2 %3 \n " , ( int ) msg - > controller_number , ( float ) midi_to_control ( new_value ) , current_uri ( ) ) ) ;
last_controllable_value = new_value ;
} else {
int offset = ( msg - > value & 0x3f ) ;
2015-07-24 20:34:22 -04:00
switch ( get_encoder ( ) ) {
case Enc_L :
if ( msg - > value > 0x40 ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( last_value - offset + 1 ) , Controllable : : UseGroup ) ;
2015-07-24 20:34:22 -04:00
} else {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( last_value + offset + 1 ) , Controllable : : UseGroup ) ;
2015-07-24 20:34:22 -04:00
}
break ;
case Enc_R :
if ( msg - > value > 0x40 ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( last_value + offset + 1 ) , Controllable : : UseGroup ) ;
2015-07-24 20:34:22 -04:00
} else {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( last_value - offset + 1 ) , Controllable : : UseGroup ) ;
2015-07-24 20:34:22 -04:00
}
break ;
case Enc_2 :
if ( msg - > value > 0x40 ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( last_value - ( 0x7f - msg - > value ) + 1 ) , Controllable : : UseGroup ) ;
2015-07-24 20:34:22 -04:00
} else {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( last_value + offset + 1 ) , Controllable : : UseGroup ) ;
2015-07-24 20:34:22 -04:00
}
break ;
case Enc_B :
if ( msg - > value > 0x40 ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( last_value + offset + 1 ) , Controllable : : UseGroup ) ;
2015-07-24 20:34:22 -04:00
} else {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( last_value - ( 0x40 - offset ) ) , Controllable : : UseGroup ) ;
2015-07-24 20:34:22 -04:00
}
break ;
default :
break ;
2015-07-21 02:15:53 -04:00
}
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " MIDI CC %1 value %2 %3 \n " , ( int ) msg - > controller_number , ( int ) last_value , current_uri ( ) ) ) ;
2013-01-17 09:48:17 -05:00
2011-12-14 10:57:48 -05:00
}
2008-06-02 17:41:35 -04:00
} else {
2016-02-02 22:22:20 -05:00
/* toggle control: make the toggle flip only if the
* incoming control value exceeds 0.5 ( 0x40 ) , so that
* the typical button which sends " CC N=0x7f " on press
* and " CC N=0x0 " on release can be used to drive
* toggles on press .
*
* No other arrangement really makes sense for a toggle
* controllable . Acting on the press + release makes the
* action momentary , which is almost never
* desirable . If the physical button only sends a
* message on press ( or release ) , then it will be
* expected to send a controller value > = 0.5
* ( 0x40 ) . It is hard to imagine why anyone would make
* a MIDI controller button that sent 0x0 when pressed .
*/
if ( msg - > value > = 0x40 ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( controllable - > get_value ( ) > = 0.5 ? 0.0 : 1.0 , Controllable : : UseGroup ) ;
2015-07-09 21:16:44 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " Midi CC %1 value 1 %2 \n " , ( int ) msg - > controller_number , current_uri ( ) ) ) ;
2008-06-02 17:41:35 -04:00
}
}
2009-12-10 21:00:22 -05:00
last_value = ( MIDI : : byte ) ( control_to_midi ( controllable - > get_value ( ) ) ) ; // to prevent feedback fights
2008-06-02 17:41:35 -04:00
}
}
void
2013-09-05 04:50:58 -04:00
MIDIControllable : : midi_sense_program_change ( Parser & , MIDI : : byte msg )
2008-06-02 17:41:35 -04:00
{
2015-10-04 14:51:05 -04:00
if ( ! controllable ) {
2012-06-25 08:33:13 -04:00
if ( lookup_controllable ( ) ) {
return ;
}
2009-12-10 21:00:22 -05:00
}
2017-01-23 07:25:56 -05:00
_surface - > maybe_start_touch ( controllable ) ;
2015-07-20 16:34:11 -04:00
if ( msg = = control_additional ) {
2008-06-02 17:41:35 -04:00
2015-07-20 16:34:11 -04:00
if ( ! controllable - > is_toggle ( ) ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( 1.0 , Controllable : : UseGroup ) ;
2015-07-20 16:34:11 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " MIDI program %1 value 1.0 %3 \n " , ( int ) msg , current_uri ( ) ) ) ;
} else {
float new_value = controllable - > get_value ( ) > 0.5f ? 0.0f : 1.0f ;
2017-01-31 09:32:55 -05:00
controllable - > set_value ( new_value , Controllable : : UseGroup ) ;
2015-07-20 16:34:11 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " MIDI program %1 value %2 %3 \n " , ( int ) msg , ( float ) new_value , current_uri ( ) ) ) ;
}
2009-10-20 20:15:42 -04:00
}
2010-01-01 13:14:32 -05:00
last_value = ( MIDI : : byte ) ( controllable - > get_value ( ) * 127.0 ) ; // to prevent feedback fights
2008-06-02 17:41:35 -04:00
}
void
2009-07-21 11:55:17 -04:00
MIDIControllable : : midi_sense_pitchbend ( Parser & , pitchbend_t pb )
2008-06-02 17:41:35 -04:00
{
2015-10-04 14:51:05 -04:00
if ( ! controllable ) {
2012-06-25 08:33:13 -04:00
if ( lookup_controllable ( ) ) {
return ;
}
2009-12-10 21:00:22 -05:00
}
2017-01-23 07:25:56 -05:00
_surface - > maybe_start_touch ( controllable ) ;
2010-01-01 13:14:32 -05:00
if ( ! controllable - > is_toggle ( ) ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( midi_to_control ( pb ) , Controllable : : UseGroup ) ;
2015-07-09 21:16:44 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " MIDI pitchbend %1 value %2 %3 \n " , ( int ) control_channel , ( float ) midi_to_control ( pb ) , current_uri ( ) ) ) ;
2010-01-01 13:14:32 -05:00
} else {
2015-07-09 21:27:08 -04:00
if ( pb > 8065.0f ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( 1 , Controllable : : UseGroup ) ;
2015-07-09 21:27:08 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " Midi pitchbend %1 value 1 %2 \n " , ( int ) control_channel , current_uri ( ) ) ) ;
} else {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( 0 , Controllable : : UseGroup ) ;
2015-07-09 21:27:08 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " Midi pitchbend %1 value 0 %2 \n " , ( int ) control_channel , current_uri ( ) ) ) ;
}
2010-01-01 13:14:32 -05:00
}
2008-06-02 17:41:35 -04:00
2012-03-06 10:08:17 -05:00
last_value = control_to_midi ( controllable - > get_value ( ) ) ;
2009-10-20 20:15:42 -04:00
}
2008-06-02 17:41:35 -04:00
void
2013-09-05 04:50:58 -04:00
MIDIControllable : : midi_receiver ( Parser & , MIDI : : byte * msg , size_t /*len*/ )
2008-06-02 17:41:35 -04:00
{
/* we only respond to channel messages */
if ( ( msg [ 0 ] & 0xF0 ) < 0x80 | | ( msg [ 0 ] & 0xF0 ) > 0xE0 ) {
return ;
}
2015-07-20 15:37:53 -04:00
_surface - > check_used_event ( msg [ 0 ] , msg [ 1 ] ) ;
2008-06-02 17:41:35 -04:00
bind_midi ( ( channel_t ) ( msg [ 0 ] & 0xf ) , eventType ( msg [ 0 ] & 0xF0 ) , msg [ 1 ] ) ;
2012-06-25 08:33:13 -04:00
if ( controllable ) {
controllable - > LearningFinished ( ) ;
}
2008-06-02 17:41:35 -04:00
}
2015-11-23 12:26:23 -05:00
void
MIDIControllable : : rpn_value_change ( Parser & , uint16_t rpn , float val )
{
if ( control_rpn = = rpn ) {
if ( controllable ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( val , Controllable : : UseGroup ) ;
2015-11-23 12:26:23 -05:00
}
}
}
void
MIDIControllable : : nrpn_value_change ( Parser & , uint16_t nrpn , float val )
{
if ( control_nrpn = = nrpn ) {
if ( controllable ) {
2017-01-31 09:32:55 -05:00
controllable - > set_value ( val , Controllable : : UseGroup ) ;
2015-11-23 12:26:23 -05:00
}
}
}
void
MIDIControllable : : rpn_change ( Parser & , uint16_t rpn , int dir )
{
if ( control_rpn = = rpn ) {
if ( controllable ) {
/* XXX how to increment/decrement ? */
// controllable->set_value (val);
}
}
}
void
MIDIControllable : : nrpn_change ( Parser & , uint16_t nrpn , int dir )
{
if ( control_nrpn = = nrpn ) {
if ( controllable ) {
/* XXX how to increment/decrement ? */
// controllable->set_value (val);
}
}
}
void
MIDIControllable : : bind_rpn_value ( channel_t chn , uint16_t rpn )
{
int chn_i = chn ;
drop_external_control ( ) ;
control_rpn = rpn ;
control_channel = chn ;
_parser . channel_rpn [ chn_i ] . connect_same_thread ( midi_sense_connection [ 0 ] , boost : : bind ( & MIDIControllable : : rpn_value_change , this , _1 , _2 , _3 ) ) ;
}
void
MIDIControllable : : bind_nrpn_value ( channel_t chn , uint16_t nrpn )
{
int chn_i = chn ;
drop_external_control ( ) ;
control_nrpn = nrpn ;
control_channel = chn ;
_parser . channel_nrpn [ chn_i ] . connect_same_thread ( midi_sense_connection [ 0 ] , boost : : bind ( & MIDIControllable : : rpn_value_change , this , _1 , _2 , _3 ) ) ;
}
void
MIDIControllable : : bind_nrpn_change ( channel_t chn , uint16_t nrpn )
{
int chn_i = chn ;
drop_external_control ( ) ;
control_nrpn = nrpn ;
control_channel = chn ;
_parser . channel_nrpn_change [ chn_i ] . connect_same_thread ( midi_sense_connection [ 0 ] , boost : : bind ( & MIDIControllable : : rpn_change , this , _1 , _2 , _3 ) ) ;
}
void
MIDIControllable : : bind_rpn_change ( channel_t chn , uint16_t rpn )
{
int chn_i = chn ;
drop_external_control ( ) ;
control_rpn = rpn ;
control_channel = chn ;
_parser . channel_rpn_change [ chn_i ] . connect_same_thread ( midi_sense_connection [ 0 ] , boost : : bind ( & MIDIControllable : : nrpn_change , this , _1 , _2 , _3 ) ) ;
}
2008-06-02 17:41:35 -04:00
void
MIDIControllable : : bind_midi ( channel_t chn , eventType ev , MIDI : : byte additional )
{
char buf [ 64 ] ;
drop_external_control ( ) ;
control_type = ev ;
control_channel = chn ;
control_additional = additional ;
int chn_i = chn ;
switch ( ev ) {
case MIDI : : off :
2013-08-07 22:22:11 -04:00
_parser . channel_note_off [ chn_i ] . connect_same_thread ( midi_sense_connection [ 0 ] , boost : : bind ( & MIDIControllable : : midi_sense_note_off , this , _1 , _2 ) ) ;
2008-06-02 17:41:35 -04:00
2010-01-01 13:14:32 -05:00
/* if this is a togglee, connect to noteOn as well,
2008-06-02 17:41:35 -04:00
and we ' ll toggle back and forth between the two .
*/
2010-01-01 13:14:32 -05:00
if ( _momentary ) {
2013-08-07 22:22:11 -04:00
_parser . channel_note_on [ chn_i ] . connect_same_thread ( midi_sense_connection [ 1 ] , boost : : bind ( & MIDIControllable : : midi_sense_note_on , this , _1 , _2 ) ) ;
2015-10-04 14:51:05 -04:00
}
2009-12-19 15:26:31 -05:00
2008-06-02 17:41:35 -04:00
_control_description = " MIDI control: NoteOff " ;
break ;
case MIDI : : on :
2013-08-07 22:22:11 -04:00
_parser . channel_note_on [ chn_i ] . connect_same_thread ( midi_sense_connection [ 0 ] , boost : : bind ( & MIDIControllable : : midi_sense_note_on , this , _1 , _2 ) ) ;
2010-01-01 13:14:32 -05:00
if ( _momentary ) {
2013-08-07 22:22:11 -04:00
_parser . channel_note_off [ chn_i ] . connect_same_thread ( midi_sense_connection [ 1 ] , boost : : bind ( & MIDIControllable : : midi_sense_note_off , this , _1 , _2 ) ) ;
2008-06-02 17:41:35 -04:00
}
_control_description = " MIDI control: NoteOn " ;
break ;
2015-10-05 10:17:49 -04:00
2008-06-02 17:41:35 -04:00
case MIDI : : controller :
2013-08-07 22:22:11 -04:00
_parser . channel_controller [ chn_i ] . connect_same_thread ( midi_sense_connection [ 0 ] , boost : : bind ( & MIDIControllable : : midi_sense_controller , this , _1 , _2 ) ) ;
2008-06-02 17:41:35 -04:00
snprintf ( buf , sizeof ( buf ) , " MIDI control: Controller %d " , control_additional ) ;
_control_description = buf ;
break ;
case MIDI : : program :
2013-08-07 22:22:11 -04:00
_parser . channel_program_change [ chn_i ] . connect_same_thread ( midi_sense_connection [ 0 ] , boost : : bind ( & MIDIControllable : : midi_sense_program_change , this , _1 , _2 ) ) ;
2010-01-01 13:14:32 -05:00
_control_description = " MIDI control: ProgramChange " ;
2008-06-02 17:41:35 -04:00
break ;
case MIDI : : pitchbend :
2013-08-07 22:22:11 -04:00
_parser . channel_pitchbend [ chn_i ] . connect_same_thread ( midi_sense_connection [ 0 ] , boost : : bind ( & MIDIControllable : : midi_sense_pitchbend , this , _1 , _2 ) ) ;
2010-01-01 13:14:32 -05:00
_control_description = " MIDI control: Pitchbend " ;
2008-06-02 17:41:35 -04:00
break ;
default :
break ;
}
2015-07-09 21:16:44 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " Controlable: bind_midi: %1 on Channel %2 value %3 \n " , _control_description , chn_i + 1 , ( int ) additional ) ) ;
2008-06-02 17:41:35 -04:00
}
MIDI : : byte *
2009-07-21 11:55:17 -04:00
MIDIControllable : : write_feedback ( MIDI : : byte * buf , int32_t & bufsize , bool /*force*/ )
2008-06-02 17:41:35 -04:00
{
2016-12-30 22:35:41 -05:00
if ( ! controllable | | ! _surface - > get_feedback ( ) ) {
2015-11-23 12:26:23 -05:00
return buf ;
}
float val = controllable - > get_value ( ) ;
/* Note that when sending RPN/NPRN we do two things:
*
* always send MSB first , then LSB
* null / reset the parameter ID after sending .
*
* this follows recommendations found online , eg . http : //www.philrees.co.uk/nrpnq.htm
*/
if ( control_rpn > = 0 ) {
if ( bufsize < 13 ) {
return buf ;
}
int rpn_val = ( int ) lrintf ( val * 16384.0 ) ;
if ( last_value = = rpn_val ) {
return buf ;
}
* buf + + = ( 0xb0 ) | control_channel ;
* buf + + = 0x62 ;
* buf + + = ( int ) ( ( control_rpn ) > > 7 ) ;
* buf + + = 0x63 ;
* buf + + = ( int ) ( control_rpn & 0x7f ) ;
* buf + + = 0x06 ;
* buf + + = ( int ) ( rpn_val > > 7 ) ;
* buf + + = 0x26 ;
* buf + + = ( int ) ( rpn_val & 0x7f ) ;
* buf + + = 0x62 ;
* buf + + = 0x7f ;
* buf + + = 0x63 ;
* buf + + = 0x7f ;
bufsize - = 13 ;
last_value = rpn_val ;
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " MIDI out: RPN %1 Channel %2 Value %3 \n " , control_rpn , ( int ) control_channel , val ) ) ;
return buf ;
}
if ( control_nrpn > = 0 ) {
int rpn_val = ( int ) lrintf ( val * 16384.0 ) ;
if ( last_value = = rpn_val ) {
return buf ;
}
* buf + + = ( 0xb0 ) | control_channel ;
* buf + + = 0x64 ;
* buf + + = ( int ) ( ( control_rpn ) > > 7 ) ;
* buf + + = 0x65 ;
* buf + + = ( int ) ( control_rpn & 0x7f ) ;
* buf + + = 0x06 ;
* buf + + = ( int ) ( rpn_val > > 7 ) ;
* buf + + = 0x26 ;
* buf + + = ( int ) ( rpn_val & 0x7f ) ;
* buf + + = 0x64 ;
* buf + + = 0x7f ;
* buf + + = 0x65 ;
* buf + + = 0x7f ;
last_value = rpn_val ;
bufsize - = 13 ;
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " MIDI out: NRPN %1 Channel %2 Value %3 \n " , control_nrpn , ( int ) control_channel , val ) ) ;
return buf ;
}
if ( control_type = = none | | bufsize < = 2 ) {
2012-03-06 10:08:17 -05:00
return buf ;
}
2015-10-05 10:17:49 -04:00
2015-11-23 12:26:23 -05:00
int const gm = control_to_midi ( val ) ;
2010-01-01 13:14:32 -05:00
2012-03-06 10:08:17 -05:00
if ( gm = = last_value ) {
return buf ;
}
2009-10-20 20:15:42 -04:00
2015-07-09 21:16:44 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " Feedback: %1 %2 \n " , control_description ( ) , current_uri ( ) ) ) ;
2012-03-06 10:08:17 -05:00
* buf + + = ( 0xF0 & control_type ) | ( 0xF & control_channel ) ;
2015-07-09 21:23:14 -04:00
int ev_size = 3 ;
2012-03-06 10:08:17 -05:00
switch ( control_type ) {
case MIDI : : pitchbend :
* buf + + = int ( gm ) & 127 ;
* buf + + = ( int ( gm ) > > 7 ) & 127 ;
break ;
2015-07-09 21:23:14 -04:00
case MIDI : : program :
* buf + + = control_additional ; /* program number */
ev_size = 2 ;
break ;
2012-03-06 10:08:17 -05:00
default :
* buf + + = control_additional ; /* controller number */
* buf + + = gm ;
break ;
2008-06-02 17:41:35 -04:00
}
2015-07-09 21:16:44 -04:00
DEBUG_TRACE ( DEBUG : : GenericMidi , string_compose ( " MIDI out: Type %1 Channel %2 Bytes %3 %4 \n " , ( int ) control_type , ( int ) control_channel , ( int ) * ( buf - 2 ) , ( int ) * ( buf - 1 ) ) ) ;
2009-10-20 20:15:42 -04:00
2012-03-06 10:08:17 -05:00
last_value = gm ;
2015-07-09 21:23:14 -04:00
bufsize - = ev_size ;
2012-03-06 10:08:17 -05:00
2008-06-02 17:41:35 -04:00
return buf ;
}
2009-10-20 20:15:42 -04:00
int
MIDIControllable : : set_state ( const XMLNode & node , int /*version*/ )
2008-06-02 17:41:35 -04:00
{
const XMLProperty * prop ;
int xx ;
if ( ( prop = node . property ( " event " ) ) ! = 0 ) {
sscanf ( prop - > value ( ) . c_str ( ) , " 0x%x " , & xx ) ;
control_type = ( MIDI : : eventType ) xx ;
} else {
return - 1 ;
}
if ( ( prop = node . property ( " channel " ) ) ! = 0 ) {
sscanf ( prop - > value ( ) . c_str ( ) , " %d " , & xx ) ;
control_channel = ( MIDI : : channel_t ) xx ;
} else {
return - 1 ;
}
if ( ( prop = node . property ( " additional " ) ) ! = 0 ) {
sscanf ( prop - > value ( ) . c_str ( ) , " 0x%x " , & xx ) ;
control_additional = ( MIDI : : byte ) xx ;
} else {
return - 1 ;
}
bind_midi ( control_channel , control_type , control_additional ) ;
2009-10-20 20:15:42 -04:00
2008-06-02 17:41:35 -04:00
return 0 ;
}
XMLNode &
MIDIControllable : : get_state ( )
{
char buf [ 32 ] ;
2009-12-10 22:18:17 -05:00
XMLNode * node = new XMLNode ( " MIDIControllable " ) ;
2010-11-27 12:43:32 -05:00
if ( _current_uri . empty ( ) ) {
node - > add_property ( " id " , controllable - > id ( ) . to_s ( ) ) ;
} else {
2009-12-30 11:48:58 -05:00
node - > add_property ( " uri " , _current_uri ) ;
2010-11-27 12:43:32 -05:00
}
2009-12-30 11:48:58 -05:00
2009-12-10 22:18:17 -05:00
if ( controllable ) {
snprintf ( buf , sizeof ( buf ) , " 0x%x " , ( int ) control_type ) ;
node - > add_property ( " event " , buf ) ;
snprintf ( buf , sizeof ( buf ) , " %d " , ( int ) control_channel ) ;
node - > add_property ( " channel " , buf ) ;
snprintf ( buf , sizeof ( buf ) , " 0x%x " , ( int ) control_additional ) ;
node - > add_property ( " additional " , buf ) ;
}
2008-06-02 17:41:35 -04:00
2009-12-10 22:18:17 -05:00
return * node ;
2008-06-02 17:41:35 -04:00
}
2012-03-06 10:08:17 -05:00
/** @return the maximum value for a control value transmitted
* using a given MIDI : : eventType .
*/
int
MIDIControllable : : max_value_for_type ( ) const
{
/* XXX: this is not complete */
2015-10-05 10:17:49 -04:00
2012-03-06 10:08:17 -05:00
if ( control_type = = MIDI : : pitchbend ) {
return 16383 ;
}
return 127 ;
}