summaryrefslogtreecommitdiff
path: root/libs/surfaces/mackie/mackie_midi_builder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/surfaces/mackie/mackie_midi_builder.cc')
-rw-r--r--libs/surfaces/mackie/mackie_midi_builder.cc173
1 files changed, 173 insertions, 0 deletions
diff --git a/libs/surfaces/mackie/mackie_midi_builder.cc b/libs/surfaces/mackie/mackie_midi_builder.cc
new file mode 100644
index 0000000000..8ed98a5720
--- /dev/null
+++ b/libs/surfaces/mackie/mackie_midi_builder.cc
@@ -0,0 +1,173 @@
+/*
+ Copyright (C) 2006,2007 John Anderson
+
+ 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 02139, USA.
+*/
+#include "mackie_midi_builder.h"
+
+#include <typeinfo>
+#include <sstream>
+#include <iomanip>
+
+#include "controls.h"
+#include "midi_byte_array.h"
+
+using namespace Mackie;
+using namespace std;
+
+MIDI::byte MackieMidiBuilder::calculate_pot_value( midi_pot_mode mode, const ControlState & state )
+{
+ // TODO do an exact calc for 0.50? To allow manually re-centering the port.
+
+ // center on or off
+ MIDI::byte retval = ( state.pos > 0.45 && state.pos < 0.55 ? 1 : 0 ) << 6;
+
+ // mode
+ retval |= ( mode << 4 );
+
+ // value, but only if off hasn't explicitly been set
+ if ( state.led_state != off )
+ retval += ( int(state.pos * 10.0) + 1 ) & 0x0f; // 0b00001111
+
+ return retval;
+}
+
+MidiByteArray MackieMidiBuilder::build_led_ring( const Pot & pot, const ControlState & state )
+{
+ return build_led_ring( pot.led_ring(), state );
+}
+
+MidiByteArray MackieMidiBuilder::build_led_ring( const LedRing & led_ring, const ControlState & state )
+{
+ // The other way of doing this:
+ // 0x30 + pot/ring number (0-7)
+ //, 0x30 + led_ring.ordinal() - 1
+ return MidiByteArray ( 3
+ // the control type
+ , midi_pot_id
+ // the id
+ , 0x20 + led_ring.id()
+ // the value
+ , calculate_pot_value( midi_pot_mode_dot, state )
+ );
+}
+
+MidiByteArray MackieMidiBuilder::build_led( const Button & button, LedState ls )
+{
+ return build_led( button.led(), ls );
+}
+
+MidiByteArray MackieMidiBuilder::build_led( const Led & led, LedState ls )
+{
+ MIDI::byte state = 0;
+ switch ( ls.state() )
+ {
+ case LedState::on: state = 0x7f; break;
+ case LedState::off: state = 0x00; break;
+ case LedState::none: state = 0x00; break; // actually, this should never happen.
+ case LedState::flashing: state = 0x01; break;
+ }
+
+ return MidiByteArray ( 3
+ , midi_button_id
+ , led.id()
+ , state
+ );
+}
+
+MidiByteArray MackieMidiBuilder::build_fader( const Fader & fader, float pos )
+{
+ int posi = int( 0x3fff * pos );
+
+ return MidiByteArray ( 3
+ , midi_fader_id | fader.id()
+ // lower-order bits
+ , posi & 0x7f
+ // higher-order bits
+ , ( posi >> 7 )
+ );
+}
+
+MidiByteArray MackieMidiBuilder::zero_strip( const Strip & strip )
+{
+ Group::Controls::const_iterator it = strip.controls().begin();
+ MidiByteArray retval;
+ for (; it != strip.controls().end(); ++it )
+ {
+ Control & control = **it;
+ if ( control.accepts_feedback() )
+ retval << zero_control( control );
+ }
+ return retval;
+}
+
+MidiByteArray MackieMidiBuilder::zero_control( const Control & control )
+{
+ switch( control.type() )
+ {
+ case Control::type_button:
+ return build_led( (Button&)control, off );
+
+ case Control::type_led:
+ return build_led( (Led&)control, off );
+
+ case Control::type_fader:
+ return build_fader( (Fader&)control, 0.0 );
+
+ case Control::type_pot:
+ return build_led_ring( dynamic_cast<const Pot&>( control ), off );
+
+ case Control::type_led_ring:
+ return build_led_ring( dynamic_cast<const LedRing&>( control ), off );
+
+ default:
+ ostringstream os;
+ os << "Unknown control type " << control << " in Strip::zero_control";
+ throw MackieControlException( os.str() );
+ }
+}
+
+char translate_seven_segment( char achar )
+{
+ achar = toupper( achar );
+ if ( achar >= 0x40 && achar <= 0x60 )
+ return achar - 0x40;
+ else if ( achar >= 0x21 && achar <= 0x3f )
+ return achar;
+ else
+ return 0x00;
+}
+
+MidiByteArray MackieMidiBuilder::two_char_display( const std::string & msg, const std::string & dots )
+{
+ if ( msg.length() != 2 ) throw MackieControlException( "MackieMidiBuilder::two_char_display: msg must be exactly 2 characters" );
+ if ( dots.length() != 2 ) throw MackieControlException( "MackieMidiBuilder::two_char_display: dots must be exactly 2 characters" );
+
+ MidiByteArray bytes( 5, 0xb0, 0x4a, 0x00, 0x4b, 0x00 );
+
+ // chars are understood by the surface in right-to-left order
+ // could also exchange the 0x4a and 0x4b, above
+ bytes[4] = translate_seven_segment( msg[0] ) + ( dots[0] == '.' ? 0x40 : 0x00 );
+ bytes[2] = translate_seven_segment( msg[1] ) + ( dots[1] == '.' ? 0x40 : 0x00 );
+
+ return bytes;
+}
+
+MidiByteArray MackieMidiBuilder::two_char_display( unsigned int value, const std::string & dots )
+{
+ ostringstream os;
+ os << setfill('0') << setw(2) << value % 100;
+ return two_char_display( os.str() );
+}