diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index aa4438ed2c..3db64ae1e6 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -452,6 +452,11 @@ MackieControlProtocol::switch_banks (uint32_t initial, bool force) DEBUG_TRACE (DEBUG::MackieControl, string_compose ("give surface %1 stripables\n", stripables.size())); (*si)->map_stripables (stripables); + + // Force RGB update on next redisplay + if (_device_info.is_v1m() || _device_info.is_platformMp() || _device_info.is_p1nano()) { + (*si)->force_icon_rgb_update(); + } } } diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc index 7990ddd56c..80140aed5c 100644 --- a/libs/surfaces/mackie/surface.cc +++ b/libs/surfaces/mackie/surface.cc @@ -118,6 +118,9 @@ Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, ui , _has_master_meter (false) , connection_state (0) , is_qcon (false) + , is_v1m (false) + , is_platformMp (false) + , is_p1nano (false) , input_source (0) { DEBUG_TRACE (DEBUG::MackieControl, "Surface::Surface init\n"); @@ -131,6 +134,19 @@ Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, ui //Store Qcon flag is_qcon = mcp.device_info().is_qcon(); + //Store iCON P1-M and V1-M flag + is_v1m = _mcp.device_info().is_v1m(); // || device_name.find("V1-M") != std::string::npos; + is_platformMp = _mcp.device_info().is_platformMp(); // || device_name.find("Platform M+") != std::string::npos; + is_p1nano = _mcp.device_info().is_p1nano(); + + /* extenders are not flagged by device_info() — detect by port name */ + is_v1m |= (device_name.find("V1-M") != std::string::npos); + is_platformMp |= device_name.find("Platform M+") != std::string::npos; + is_p1nano |= device_name.find("P1-NANO") != std::string::npos; + + _pending_icon_rgb.fill(0); + _current_icon_rgb.fill(0); + /* only the first Surface object has global controls */ /* lets use master_position instead */ uint32_t mp = _mcp.device_info().master_position(); @@ -140,6 +156,11 @@ Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, ui if ( is_qcon ) { _has_master_display = (mcp.device_info().has_master_fader() && mcp.device_info().has_qcon_second_lcd()); } + + if ( is_v1m ) { + _has_master_display = (mcp.device_info().has_master_fader() && mcp.device_info().has_qcon_second_lcd()); + } + _has_master_meter = mcp.device_info().has_qcon_master_meters(); if (_mcp.device_info().has_global_controls()) { @@ -1158,6 +1179,34 @@ Surface::redisplay (PBD::microseconds_t now, bool force) } } + /* iCON P1-M/P1-NANO/V1-M color update: full RGB SysEx for all 8 strips */ + if (is_v1m || is_platformMp || is_p1nano) { + std::array pending_rgb{}; + + for (size_t i = 0; i < 8 && i < strips.size(); ++i) { + if (auto sp = strips[i]->stripable()) { + uint32_t c = sp->presentation_info().color(); + uint8_t r = ((c >> 24) & 0xFF) >> 1; + uint8_t g = ((c >> 16) & 0xFF) >> 1; + uint8_t b = ((c >> 8) & 0xFF) >> 1; + + r = (r < 20) ? 0 : std::min(127, r + 20); + g = (g < 20) ? 0 : std::min(127, g + 20); + b = (b < 20) ? 0 : std::min(127, b + 20); + + const size_t o = i * 3; + pending_rgb[o+0] = r; + pending_rgb[o+1] = g; + pending_rgb[o+2] = b; + } + } + + if (force || pending_rgb != _current_icon_rgb) { + _current_icon_rgb = pending_rgb; + write(display_colors_on_p1m_v1m(pending_rgb)); + } + } + for (Strips::iterator s = strips.begin(); s != strips.end(); ++s) { (*s)->redisplay (now, force); } @@ -1639,6 +1688,26 @@ Surface::display_message_for (string const& msg, uint64_t msecs) (*s)->block_screen_display_for (msecs); } } + +/** display color_values on the 8 scribble strips of the iCON P1-M, P1-NANO and V1-M **/ +MidiByteArray +Surface::display_colors_on_p1m_v1m (const std::array& rgb_values) const +{ + /* Icon P1-M, P1-NANO and V1-M color SysEx: F0 00 02 4E 16 14 [8×(R G B)] F7 + * rgb_values: 24 bytes (8 strips × 3 RGB, each 0-127 / 0x00-0x7F) + */ + MidiByteArray midi_msg; + midi_msg << MIDI::sysex + << 0x00 << 0x02 << 0x4E // iCON manufacturer + << 0x16 << 0x14; // color command + + for (uint8_t b : rgb_values) { + midi_msg << b; + } + + midi_msg << MIDI::eox; + return midi_msg; +} /** display @p color_values on the 8 scribble strips of the X-Touch * @@ -1656,7 +1725,7 @@ Surface::display_colors_on_xtouch (const XTouchColors color_values[]) const for (uint8_t i = 0; i < displaycount; ++i) { midi_msg << color_values[i]; } - + midi_msg << MIDI::eox; return midi_msg; diff --git a/libs/surfaces/mackie/surface.h b/libs/surfaces/mackie/surface.h index 2d0a98f447..ba871a13a0 100644 --- a/libs/surfaces/mackie/surface.h +++ b/libs/surfaces/mackie/surface.h @@ -205,6 +205,12 @@ public: bool get_qcon_flag() { return is_qcon; } + bool get_v1_flag() { return is_v1m; } + bool get_platformMp_flag() { return is_platformMp; } + bool get_p1nano_flag() { return is_p1nano; } + + void force_icon_rgb_update() { _pending_icon_rgb.fill(0xFF); } + void toggle_master_monitor (); bool master_stripable_is_master_monitor (); @@ -227,6 +233,10 @@ public: std::string pending_display[2]; std::string current_display[2]; + // iCON P1-M / V1-M RGB — same pattern as master display + std::array _pending_icon_rgb{}; + std::array _current_icon_rgb{}; + void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count); MidiByteArray host_connection_query (MidiByteArray& bytes); MidiByteArray host_connection_confirmation (const MidiByteArray& bytes); @@ -256,6 +266,14 @@ public: MidiByteArray display_colors_on_xtouch (const XTouchColors color_values[]) const; uint8_t convert_color_to_xtouch_value (uint32_t color) const; + // iCON Flags + bool is_v1m; + bool is_platformMp; + bool is_p1nano; + + /** Send RGB colors to P1-M and V1-M scribble strips (iCON-specific SysEx) */ + MidiByteArray display_colors_on_p1m_v1m (const std::array& rgb_values) const; + public: /* IP MIDI devices need to keep a handle on this and destroy it */ GSource* input_source;