mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-05 22:34:56 +01:00
Compare commits
17 commits
5ef94b0511
...
7635707ac2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7635707ac2 | ||
|
|
fca85e01c9 | ||
|
|
cf6eff4d9f | ||
|
|
c5c04f38cd | ||
|
|
04a1ed3c48 | ||
|
|
21b2985c47 | ||
|
|
5833fc08f2 | ||
|
|
34850e514d | ||
|
|
2db87934dd | ||
|
|
e39eebee57 | ||
|
|
669e689f8c | ||
|
|
f71b519c56 | ||
|
|
3e2c73258c | ||
|
|
4db08ba34f | ||
|
|
293a359d10 | ||
|
|
f996808962 | ||
|
|
2aadc53a44 |
22 changed files with 385 additions and 50 deletions
|
|
@ -702,7 +702,7 @@ AudioClipEditor::set_overlay_text (std::string const & str)
|
|||
EC_LOCAL_TEMPO_SCOPE;
|
||||
|
||||
if (!overlay_text) {
|
||||
overlay_text = new ArdourCanvas::Text (data_group);
|
||||
overlay_text = new ArdourCanvas::Text (no_scroll_group);
|
||||
Pango::FontDescription font ("Sans 200");
|
||||
overlay_text->set_font_description (font);
|
||||
overlay_text->set_color (0xff000088);
|
||||
|
|
@ -894,9 +894,12 @@ AudioClipEditor::snap_mode_chosen (Editing::SnapMode)
|
|||
void
|
||||
AudioClipEditor::grid_type_chosen (Editing::GridType gt)
|
||||
{
|
||||
EC_LOCAL_TEMPO_SCOPE;
|
||||
|
||||
if (gt != Editing::GridTypeMinSec && grid_actions[gt] && grid_actions[gt]->get_active()) {
|
||||
assert (grid_actions[Editing::GridTypeMinSec]);
|
||||
grid_actions[Editing::GridTypeMinSec]->set_active (false);
|
||||
grid_actions[Editing::GridTypeMinSec]->set_active (true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -707,6 +707,7 @@ CueEditor::rec_enable_change ()
|
|||
break;
|
||||
case Disabled:
|
||||
rec_enable_button.set_active_state (Gtkmm2ext::Off);
|
||||
hide_count_in ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1447,6 +1448,7 @@ CueEditor::maybe_set_count_in ()
|
|||
}
|
||||
|
||||
if (ref.box()->record_enabled() == Disabled) {
|
||||
hide_count_in ();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -558,7 +558,6 @@ Pianoroll::maybe_update ()
|
|||
}
|
||||
|
||||
if (_track->triggerbox()->record_enabled() == Recording) {
|
||||
|
||||
_playhead_cursor->set_position (data_capture_duration);
|
||||
}
|
||||
|
||||
|
|
@ -1870,6 +1869,8 @@ Pianoroll::map_transport_state ()
|
|||
} else {
|
||||
loop_button.set_active (false);
|
||||
}
|
||||
|
||||
hide_count_in ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ PianorollMidiView::PianorollMidiView (std::shared_ptr<ARDOUR::MidiTrack> mt,
|
|||
MidiViewBackground& bg,
|
||||
uint32_t basic_color)
|
||||
: MidiView (mt, parent, ec, bg, basic_color)
|
||||
, _noscroll_parent (&noscroll_parent)
|
||||
, overlay_text (nullptr)
|
||||
, active_automation (nullptr)
|
||||
, velocity_display (nullptr)
|
||||
|
|
@ -748,7 +749,7 @@ void
|
|||
PianorollMidiView::set_overlay_text (std::string const & str)
|
||||
{
|
||||
if (!overlay_text) {
|
||||
overlay_text = new ArdourCanvas::Text (_note_group->parent());
|
||||
overlay_text = new ArdourCanvas::Text (_noscroll_parent);
|
||||
Pango::FontDescription font ("Sans 200");
|
||||
overlay_text->set_font_description (font);
|
||||
overlay_text->set_color (0xff000088);
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ class PianorollMidiView : public MidiView
|
|||
protected:
|
||||
bool scroll (GdkEventScroll* ev);
|
||||
|
||||
ArdourCanvas::Item* _noscroll_parent;
|
||||
ArdourCanvas::Rectangle* automation_group;
|
||||
ArdourCanvas::Text* overlay_text;
|
||||
|
||||
|
|
|
|||
|
|
@ -425,10 +425,29 @@ StripImportDialog::refill_import_table ()
|
|||
_strip_table.attach (*manage (new ArdourHSpacer (1.0)), 0, 4, 1, 2, EXPAND | FILL, SHRINK, 4, 8);
|
||||
/* clang-format on */
|
||||
|
||||
const bool show_all_local_tracks = _show_all_toggle->get_active ();
|
||||
|
||||
std::vector<std::pair<PBD::ID, PBD::ID>> sorted_map;
|
||||
for (auto const& i : _import_map) {
|
||||
sorted_map.push_back (i);
|
||||
|
||||
if (show_all_local_tracks) {
|
||||
for (auto const& r : _route_map) {
|
||||
PBD::ID d (0);
|
||||
try {
|
||||
d = _import_map.at (r.first);
|
||||
} catch (...) {}
|
||||
sorted_map.push_back (make_pair (r.first, d));
|
||||
}
|
||||
for (auto const& i : _import_map) {
|
||||
if (_route_map.find (i.first) == _route_map.end ()) {
|
||||
sorted_map.push_back (i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto const& i : _import_map) {
|
||||
sorted_map.push_back (i);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort (sorted_map.begin (), sorted_map.end (), [=] (auto& a, auto& b) {
|
||||
try {
|
||||
return _route_map.at (a.first).pi.order () < _route_map.at (b.first).pi.order ();
|
||||
|
|
@ -440,31 +459,47 @@ StripImportDialog::refill_import_table ()
|
|||
/* Refill table */
|
||||
int r = 1;
|
||||
for (auto& [rid, eid] : sorted_map /*_import_map*/) {
|
||||
++r;
|
||||
if (_route_map.find (rid) != _route_map.end ()) {
|
||||
bool is_new = _route_map.find (rid) == _route_map.end ();
|
||||
|
||||
if (!is_new) {
|
||||
l = manage (new Label (_route_map.at (rid).name, 0, 0.5));
|
||||
} else {
|
||||
l = manage (new Label (_("<i>New Track</i>"), 0, 0.5));
|
||||
l->set_use_markup ();
|
||||
}
|
||||
|
||||
++r;
|
||||
_strip_table.attach (*l, 0, 1, r, r + 1, EXPAND | FILL, SHRINK);
|
||||
|
||||
#if 0
|
||||
l = manage (new Label (_extern_map[eid], 1.0, 0.5));
|
||||
_strip_table.attach (*l, 2, 3, r, r + 1, EXPAND | FILL, SHRINK);
|
||||
#else
|
||||
using namespace Menu_Helpers;
|
||||
ArdourDropdown* dd = manage (new ArdourDropdown ());
|
||||
if (show_all_local_tracks) {
|
||||
dd->add_menu_elem (MenuElem ("---", sigc::bind (sigc::mem_fun (*this, &StripImportDialog::change_mapping), dd, rid, PBD::ID (0), "---")));
|
||||
}
|
||||
for (auto& [eid, einfo] : _extern_map) {
|
||||
dd->add_menu_elem (MenuElem (Gtkmm2ext::markup_escape_text (einfo.name), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::change_mapping), dd, rid, eid, einfo.name)));
|
||||
}
|
||||
dd->set_text (_extern_map.at (eid).name);
|
||||
assert (show_all_local_tracks || _extern_map.find (eid) != _extern_map.end ());
|
||||
try {
|
||||
dd->set_text (_extern_map.at (eid).name);
|
||||
} catch (std::out_of_range const&) {
|
||||
dd->set_text ("---");
|
||||
}
|
||||
_strip_table.attach (*dd, 2, 3, r, r + 1, EXPAND | FILL, SHRINK);
|
||||
#endif
|
||||
|
||||
if (show_all_local_tracks && !is_new) {
|
||||
continue;
|
||||
}
|
||||
ArdourButton* rm = manage (new ArdourButton ());
|
||||
rm->set_icon (ArdourIcon::CloseCross);
|
||||
rm->set_tweaks (ArdourButton::TrackHeader);
|
||||
rm->signal_clicked.connect (sigc::bind (sigc::mem_fun (*this, &StripImportDialog::remove_mapping), rid));
|
||||
_strip_table.attach (*rm, 3, 4, r, r + 1, Gtk::SHRINK, Gtk::SHRINK, 4, 2);
|
||||
_strip_table.attach (*rm, 3, 4, r, r + 1, Gtk::SHRINK, Gtk::SHRINK, 4, 0);
|
||||
}
|
||||
|
||||
if (r > 1) {
|
||||
|
|
@ -497,12 +532,14 @@ StripImportDialog::refill_import_table ()
|
|||
_add_rid_dropdown->add_menu_elem (MenuElem (_(" -- New Track -- "), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::prepare_mapping), false, next_new, _("New Track"))));
|
||||
sizing_texts.push_back (_(" -- New Track -- "));
|
||||
|
||||
for (auto& [rid, rinfo] : _route_map) {
|
||||
if (_import_map.find (rid) != _import_map.end ()) {
|
||||
continue;
|
||||
if (!show_all_local_tracks) {
|
||||
for (auto& [rid, rinfo] : _route_map) {
|
||||
if (_import_map.find (rid) != _import_map.end ()) {
|
||||
continue;
|
||||
}
|
||||
_add_rid_dropdown->add_menu_elem (MenuElem (Gtkmm2ext::markup_escape_text (rinfo.name), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::prepare_mapping), false, rid, rinfo.name)));
|
||||
sizing_texts.push_back (rinfo.name);
|
||||
}
|
||||
_add_rid_dropdown->add_menu_elem (MenuElem (Gtkmm2ext::markup_escape_text (rinfo.name), sigc::bind (sigc::mem_fun (*this, &StripImportDialog::prepare_mapping), false, rid, rinfo.name)));
|
||||
sizing_texts.push_back (rinfo.name);
|
||||
}
|
||||
|
||||
_add_eid_dropdown = manage (new ArdourWidgets::ArdourDropdown ());
|
||||
|
|
@ -518,12 +555,13 @@ StripImportDialog::refill_import_table ()
|
|||
|
||||
_add_new_mapping = manage (new ArdourButton ());
|
||||
_add_new_mapping->set_icon (ArdourIcon::PlusSign);
|
||||
_add_new_mapping->set_tweaks (ArdourButton::TrackHeader);
|
||||
_add_new_mapping->signal_clicked.connect (sigc::mem_fun (*this, &StripImportDialog::add_mapping));
|
||||
|
||||
/* clang-format off */
|
||||
_strip_table.attach (*_add_rid_dropdown, 0, 1, r, r + 1, EXPAND | FILL, SHRINK);
|
||||
_strip_table.attach (*_add_eid_dropdown, 2, 3, r, r + 1, EXPAND | FILL, SHRINK);
|
||||
_strip_table.attach (*_add_new_mapping, 3, 4, r, r + 1, Gtk::SHRINK, SHRINK);
|
||||
_strip_table.attach (*_add_new_mapping, 3, 4, r, r + 1, Gtk::SHRINK, SHRINK, 4, 0);
|
||||
/* clang-format on */
|
||||
|
||||
bool can_add = !_add_rid_dropdown->items ().empty () && !_add_eid_dropdown->items ().empty ();
|
||||
|
|
@ -546,8 +584,16 @@ StripImportDialog::idle_refill_import_table ()
|
|||
void
|
||||
StripImportDialog::change_mapping (ArdourDropdown* dd, PBD::ID const& rid, PBD::ID const& eid, std::string const& name)
|
||||
{
|
||||
if (eid == PBD::ID (0)) {
|
||||
_import_map.erase (rid);
|
||||
} else {
|
||||
_import_map[rid] = eid;
|
||||
}
|
||||
dd->set_text (name);
|
||||
_import_map[rid] = eid;
|
||||
|
||||
if (_show_all_toggle->get_active ()) {
|
||||
idle_refill_import_table ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -570,7 +616,6 @@ StripImportDialog::add_mapping ()
|
|||
assert (_add_rid != PBD::ID (0));
|
||||
assert (_add_eid != PBD::ID (0));
|
||||
|
||||
_default_mapping = false;
|
||||
_import_map[_add_rid] = _add_eid;
|
||||
|
||||
idle_refill_import_table ();
|
||||
|
|
@ -580,7 +625,6 @@ void
|
|||
StripImportDialog::remove_mapping (PBD::ID const& id)
|
||||
{
|
||||
if (1 == _import_map.erase (id)) {
|
||||
_default_mapping = false;
|
||||
idle_refill_import_table ();
|
||||
}
|
||||
}
|
||||
|
|
@ -588,7 +632,6 @@ StripImportDialog::remove_mapping (PBD::ID const& id)
|
|||
void
|
||||
StripImportDialog::clear_mapping ()
|
||||
{
|
||||
_default_mapping = false;
|
||||
_import_map.clear ();
|
||||
idle_refill_import_table ();
|
||||
}
|
||||
|
|
@ -596,11 +639,18 @@ StripImportDialog::clear_mapping ()
|
|||
void
|
||||
StripImportDialog::import_all_strips ()
|
||||
{
|
||||
_default_mapping = false;
|
||||
_import_map.clear ();
|
||||
|
||||
int64_t next_id = std::numeric_limits<uint64_t>::max () - 1 - _extern_map.size ();
|
||||
for (auto& [eid, einfo] : _extern_map) {
|
||||
if (einfo.pi.special () || einfo.pi.hidden ()) {
|
||||
continue;
|
||||
}
|
||||
#ifdef MIXBUS
|
||||
if (einfo.mixbus > 0) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
PBD::ID next_new = PBD::ID (next_id++);
|
||||
_import_map[next_new] = eid;
|
||||
}
|
||||
|
|
@ -612,7 +662,6 @@ void
|
|||
StripImportDialog::set_default_mapping (bool and_idle_update)
|
||||
{
|
||||
_import_map.clear ();
|
||||
_default_mapping = true;
|
||||
|
||||
if (_match_pbd_id) {
|
||||
/* try a 1:1 mapping */
|
||||
|
|
@ -651,29 +700,28 @@ StripImportDialog::setup_strip_import_page ()
|
|||
|
||||
for (auto const& r : *_session->get_routes ()) {
|
||||
#ifdef MIXBUS
|
||||
_route_map.emplace (r->id (), Session::RouteImportInfo (r->name (), r->presentation_info (), c->mixbus ()));
|
||||
_route_map.emplace (r->id (), Session::RouteImportInfo (r->name (), r->presentation_info (), r->mixbus ()));
|
||||
#else
|
||||
_route_map.emplace (r->id (), Session::RouteImportInfo (r->name (), r->presentation_info (), 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
set_default_mapping (false);
|
||||
using namespace Menu_Helpers;
|
||||
_action = manage (new ArdourWidgets::ArdourDropdown ());
|
||||
_action->add_menu_elem (MenuElem (_("Clear Mapping"), sigc::mem_fun (*this, &StripImportDialog::clear_mapping)));
|
||||
_action->add_menu_elem (MenuElem (_("Import all as new tracks"), sigc::mem_fun (*this, &StripImportDialog::import_all_strips)));
|
||||
_action->add_menu_elem (MenuElem (_match_pbd_id ? _("Reset - auto-map by ID") : _("Reset - auto-map by name"), sigc::bind (mem_fun (*this, &StripImportDialog::set_default_mapping), true)));
|
||||
_action->set_text (_("Actions"));
|
||||
|
||||
refill_import_table ();
|
||||
|
||||
_clear_mapping = new ArdourButton (_("Clear Mapping"));
|
||||
_reset_mapping = new ArdourButton (_match_pbd_id ? _("Reset - auto-map by ID") : _("Reset - auto-map by name"));
|
||||
_import_strips = new ArdourButton (_("Import all as new tracks"));
|
||||
|
||||
_clear_mapping->signal_clicked.connect (mem_fun (*this, &StripImportDialog::clear_mapping));
|
||||
_import_strips->signal_clicked.connect (mem_fun (*this, &StripImportDialog::import_all_strips));
|
||||
_reset_mapping->signal_clicked.connect (sigc::bind (mem_fun (*this, &StripImportDialog::set_default_mapping), true));
|
||||
_show_all_toggle = new ArdourButton (_("Show all local tracks"), ArdourButton::led_default_elements, true);
|
||||
_show_all_toggle->set_led_left (true);
|
||||
_show_all_toggle->set_can_focus (true);
|
||||
_show_all_toggle->signal_clicked.connect (mem_fun (*this, &StripImportDialog::refill_import_table));
|
||||
|
||||
HBox* hbox = manage (new HBox ());
|
||||
hbox->set_spacing (4);
|
||||
hbox->pack_start (*_clear_mapping, true, false);
|
||||
hbox->pack_start (*_import_strips, true, false);
|
||||
hbox->pack_start (*_reset_mapping, true, false);
|
||||
hbox->pack_start (*_action, true, false);
|
||||
hbox->pack_start (*_show_all_toggle, true, false);
|
||||
|
||||
VBox* vbox = manage (new VBox ());
|
||||
vbox->pack_start (_strip_table, false, false, 4);
|
||||
|
|
@ -686,7 +734,10 @@ StripImportDialog::setup_strip_import_page ()
|
|||
_page_strip.pack_end (*hbox, false, false, 4);
|
||||
_page_strip.show_all ();
|
||||
|
||||
_ok_button->set_sensitive (true); // XXX
|
||||
_ok_button->set_sensitive (true);
|
||||
|
||||
set_default_mapping (false);
|
||||
refill_import_table ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -119,9 +119,8 @@ private:
|
|||
ArdourWidgets::ArdourDropdown* _add_rid_dropdown;
|
||||
ArdourWidgets::ArdourDropdown* _add_eid_dropdown;
|
||||
ArdourWidgets::ArdourButton* _add_new_mapping;
|
||||
ArdourWidgets::ArdourButton* _clear_mapping;
|
||||
ArdourWidgets::ArdourButton* _reset_mapping;
|
||||
ArdourWidgets::ArdourButton* _import_strips;
|
||||
ArdourWidgets::ArdourDropdown* _action;
|
||||
ArdourWidgets::ArdourButton* _show_all_toggle;
|
||||
|
||||
bool _match_pbd_id;
|
||||
std::string _path;
|
||||
|
|
@ -132,7 +131,6 @@ private:
|
|||
|
||||
PBD::ID _add_rid;
|
||||
PBD::ID _add_eid;
|
||||
bool _default_mapping;
|
||||
|
||||
sigc::connection _notebook_connection;
|
||||
sigc::connection _chooser_connection;
|
||||
|
|
|
|||
|
|
@ -729,7 +729,7 @@ class LIBARDOUR_API MIDITrigger : public Trigger {
|
|||
struct MIDIPendingSwap : public PendingSwap {
|
||||
RTMidiBufferBeats* rt_midibuffer;
|
||||
|
||||
MIDIPendingSwap() : rt_midibuffer (nullptr) {}
|
||||
MIDIPendingSwap();
|
||||
~MIDIPendingSwap() { delete rt_midibuffer; }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1274,12 +1274,7 @@ Session::parse_route_state (const string& path, bool& match_pbd_id)
|
|||
continue;
|
||||
}
|
||||
|
||||
int mixbus = 0;
|
||||
#ifdef MIXBUS
|
||||
rxml->get_property (X_("mixbus-num"), mixbus)
|
||||
#endif
|
||||
|
||||
rv.emplace (id, RouteImportInfo (name, pi, mixbus));
|
||||
rv.emplace (id, RouteImportInfo (name, pi, 0));
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
|
|
|
|||
|
|
@ -3180,15 +3180,20 @@ MIDITrigger::load_pending_data (PendingSwap& ps)
|
|||
{
|
||||
MIDIPendingSwap* mps (dynamic_cast<MIDIPendingSwap*> (&ps));
|
||||
assert (mps);
|
||||
assert (mps->rt_midibuffer);
|
||||
_model->render (_model->read_lock(), *mps->rt_midibuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MIDITrigger::MIDIPendingSwap::MIDIPendingSwap ()
|
||||
: rt_midibuffer (new RTMidiBufferBeats)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
MIDITrigger::model_contents_changed ()
|
||||
{
|
||||
MIDIPendingSwap* pending = new MIDIPendingSwap;
|
||||
pending->rt_midibuffer = new RTMidiBufferBeats;
|
||||
|
||||
pending->play_start = _play_start;
|
||||
pending->play_end = _play_end;
|
||||
|
|
|
|||
|
|
@ -366,6 +366,18 @@ DeviceInfo::set_state (const XMLNode& node, int /* version */)
|
|||
_is_platformMp = false;
|
||||
}
|
||||
|
||||
if ((child = node.child ("IsP1M")) != 0) {
|
||||
child->get_property ("value", _is_p1m);
|
||||
} else {
|
||||
_is_p1m = false;
|
||||
}
|
||||
|
||||
if ((child = node.child ("IsP1Nano")) != 0) {
|
||||
child->get_property ("value", _is_p1nano);
|
||||
} else {
|
||||
_is_p1nano = false;
|
||||
}
|
||||
|
||||
if ((child = node.child ("IsProG2")) != 0) {
|
||||
child->get_property ("value", _is_proG2);
|
||||
} else {
|
||||
|
|
@ -543,6 +555,16 @@ bool DeviceInfo::is_platformMp () const
|
|||
return _is_platformMp;
|
||||
}
|
||||
|
||||
bool DeviceInfo::is_p1m () const
|
||||
{
|
||||
return _is_p1m;
|
||||
}
|
||||
|
||||
bool DeviceInfo::is_p1nano () const
|
||||
{
|
||||
return _is_p1nano;
|
||||
}
|
||||
|
||||
bool DeviceInfo::is_proG2 () const
|
||||
{
|
||||
return _is_proG2;
|
||||
|
|
|
|||
|
|
@ -82,6 +82,8 @@ class DeviceInfo
|
|||
bool is_qcon() const;
|
||||
bool is_v1m() const;
|
||||
bool is_platformMp() const;
|
||||
bool is_p1m() const;
|
||||
bool is_p1nano() const;
|
||||
bool is_proG2() const;
|
||||
bool is_xtouch() const;
|
||||
bool has_qcon_second_lcd() const;
|
||||
|
|
@ -119,6 +121,8 @@ class DeviceInfo
|
|||
bool _is_qcon;
|
||||
bool _is_v1m;
|
||||
bool _is_platformMp;
|
||||
bool _is_p1m;
|
||||
bool _is_p1nano;
|
||||
bool _is_proG2;
|
||||
bool _is_xtouch;
|
||||
bool _has_qcon_second_lcd;
|
||||
|
|
|
|||
|
|
@ -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_p1m() || _device_info.is_p1nano()) {
|
||||
(*si)->force_icon_rgb_update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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_p1m (false)
|
||||
, is_p1nano (false)
|
||||
, input_source (0)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::MackieControl, "Surface::Surface init\n");
|
||||
|
|
@ -131,6 +134,22 @@ 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_p1m = _mcp.device_info().is_p1m(); // || device_name.find("P1-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_p1m |= device_name.find("P1-M") != std::string::npos;
|
||||
is_p1nano |= device_name.find("P1-NANO") != std::string::npos;
|
||||
|
||||
_solid_icon_rgb.fill(0);
|
||||
_current_icon_rgb.fill(0);
|
||||
_pending_icon_rgb.fill(0);
|
||||
_blink_state = false;
|
||||
_last_blink_toggle = 0;
|
||||
|
||||
/* only the first Surface object has global controls */
|
||||
/* lets use master_position instead */
|
||||
uint32_t mp = _mcp.device_info().master_position();
|
||||
|
|
@ -140,6 +159,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 +1182,68 @@ 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_p1m || is_p1nano) {
|
||||
std::array<uint8_t, 24> pending_rgb{};
|
||||
|
||||
// 1-second blink cycle (500 ms on / 500 ms off)
|
||||
uint64_t now = g_get_monotonic_time();
|
||||
if (now - _last_blink_toggle >= 500000) { // 500000 µs = 500 ms
|
||||
_blink_state = !_blink_state;
|
||||
_last_blink_toggle = now;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// Save solid color for blinking reference
|
||||
_solid_icon_rgb[o+0] = r;
|
||||
_solid_icon_rgb[o+1] = g;
|
||||
_solid_icon_rgb[o+2] = b;
|
||||
|
||||
// If this strip is selected → apply blink
|
||||
if (sp->is_selected()) {
|
||||
if (!_blink_state) {
|
||||
// Blink OFF phase: dim to ~20% or full black (choose one)
|
||||
pending_rgb[o+0] = r * 0.2f;
|
||||
pending_rgb[o+1] = g * 0.2f;
|
||||
pending_rgb[o+2] = b * 0.2f;
|
||||
// For full black instead, use:
|
||||
// pending_rgb[o+0] = pending_rgb[o+1] = pending_rgb[o+2] = 0;
|
||||
} else {
|
||||
// Blink ON phase: full solid color
|
||||
pending_rgb[o+0] = r;
|
||||
pending_rgb[o+1] = g;
|
||||
pending_rgb[o+2] = b;
|
||||
}
|
||||
} else {
|
||||
// Not selected → always solid
|
||||
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 +1725,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<uint8_t, 24>& 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 +1762,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;
|
||||
|
|
|
|||
|
|
@ -205,6 +205,12 @@ public:
|
|||
|
||||
bool get_qcon_flag() { return is_qcon; }
|
||||
|
||||
bool get_v1_flag() { return is_v1m; }
|
||||
bool get_p1m_flag() { return is_p1m; }
|
||||
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<uint8_t, 24> _pending_icon_rgb{};
|
||||
std::array<uint8_t, 24> _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,17 @@ 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_p1m;
|
||||
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<uint8_t, 24>& rgb_values) const;
|
||||
std::array<uint8_t, 24> _solid_icon_rgb{}; // stores the real solid colors
|
||||
bool _blink_state = false; // true = full brightness, false = dim/off
|
||||
uint64_t _last_blink_toggle = 0;
|
||||
|
||||
public:
|
||||
/* IP MIDI devices need to keep a handle on this and destroy it */
|
||||
GSource* input_source;
|
||||
|
|
|
|||
20
share/mcp/p1-m+p1-x.device
Normal file
20
share/mcp/p1-m+p1-x.device
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MackieProtocolDevice>
|
||||
<Name value="iCON Platform M+ with Platform X+ on right"/>
|
||||
<Strips value="8"/>
|
||||
<Extenders value="1"/>
|
||||
<MasterPosition value="1"/>
|
||||
<MasterFader value="yes"/>
|
||||
<TimecodeDisplay value="yes"/>
|
||||
<TwoCharacterDisplay value="no"/>
|
||||
<HasSeparateMeters value="yes"/>
|
||||
<GlobalControls value="yes"/>
|
||||
<JogWheel value="yes"/>
|
||||
<TouchSenseFaders value="yes"/>
|
||||
<LogicControlButtons value="yes"/>
|
||||
<usesIPMIDI value="no"/>
|
||||
<NoHandShake value="yes"/>
|
||||
<IsPlatformMp value="yes"/>
|
||||
<HasQConSecondLCD value="yes"/>
|
||||
<HasQConMasterMeters value="yes"/>
|
||||
</MackieProtocolDevice>
|
||||
20
share/mcp/p1-m.device
Normal file
20
share/mcp/p1-m.device
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MackieProtocolDevice>
|
||||
<Name value="iCON Platform M+"/>
|
||||
<Strips value="8"/>
|
||||
<Extenders value="0"/>
|
||||
<MasterPosition value="0"/>
|
||||
<MasterFader value="yes"/>
|
||||
<TimecodeDisplay value="yes"/>
|
||||
<TwoCharacterDisplay value="no"/>
|
||||
<HasSeparateMeters value="yes"/>
|
||||
<GlobalControls value="yes"/>
|
||||
<JogWheel value="yes"/>
|
||||
<TouchSenseFaders value="yes"/>
|
||||
<LogicControlButtons value="yes"/>
|
||||
<usesIPMIDI value="no"/>
|
||||
<NoHandShake value="yes"/>
|
||||
<IsPlatformMp value="yes"/>
|
||||
<HasQConSecondLCD value="yes"/>
|
||||
<HasQConMasterMeters value="yes"/>
|
||||
</MackieProtocolDevice>
|
||||
20
share/mcp/p1-x+p1-m.device
Normal file
20
share/mcp/p1-x+p1-m.device
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MackieProtocolDevice>
|
||||
<Name value="iCON Platform M+ with Platform X+ on left"/>
|
||||
<Strips value="8"/>
|
||||
<Extenders value="1"/>
|
||||
<MasterPosition value="2"/>
|
||||
<MasterFader value="yes"/>
|
||||
<TimecodeDisplay value="yes"/>
|
||||
<TwoCharacterDisplay value="no"/>
|
||||
<HasSeparateMeters value="yes"/>
|
||||
<GlobalControls value="yes"/>
|
||||
<JogWheel value="yes"/>
|
||||
<TouchSenseFaders value="yes"/>
|
||||
<LogicControlButtons value="yes"/>
|
||||
<usesIPMIDI value="no"/>
|
||||
<NoHandShake value="yes"/>
|
||||
<IsPlatformMp value="yes"/>
|
||||
<HasQConSecondLCD value="yes"/>
|
||||
<HasQConMasterMeters value="yes"/>
|
||||
</MackieProtocolDevice>
|
||||
20
share/mcp/p1_nano+p1-x.device
Normal file
20
share/mcp/p1_nano+p1-x.device
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MackieProtocolDevice>
|
||||
<Name value="iCON P1-NANO with P1-X on right"/>
|
||||
<Strips value="8"/>
|
||||
<Extenders value="1"/>
|
||||
<MasterPosition value="1"/>
|
||||
<MasterFader value="yes"/>
|
||||
<TimecodeDisplay value="yes"/>
|
||||
<TwoCharacterDisplay value="no"/>
|
||||
<HasSeparateMeters value="yes"/>
|
||||
<GlobalControls value="yes"/>
|
||||
<JogWheel value="yes"/>
|
||||
<TouchSenseFaders value="yes"/>
|
||||
<LogicControlButtons value="yes"/>
|
||||
<usesIPMIDI value="no"/>
|
||||
<NoHandShake value="yes"/>
|
||||
<IsP1Nano value="yes"/>
|
||||
<HasQConSecondLCD value="yes"/>
|
||||
<HasQConMasterMeters value="yes"/>
|
||||
</MackieProtocolDevice>
|
||||
20
share/mcp/p1_nano.device
Normal file
20
share/mcp/p1_nano.device
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MackieProtocolDevice>
|
||||
<Name value="iCON P1-NANO"/>
|
||||
<Strips value="8"/>
|
||||
<Extenders value="0"/>
|
||||
<MasterPosition value="0"/>
|
||||
<MasterFader value="yes"/>
|
||||
<TimecodeDisplay value="yes"/>
|
||||
<TwoCharacterDisplay value="no"/>
|
||||
<HasSeparateMeters value="yes"/>
|
||||
<GlobalControls value="yes"/>
|
||||
<JogWheel value="yes"/>
|
||||
<TouchSenseFaders value="yes"/>
|
||||
<LogicControlButtons value="yes"/>
|
||||
<usesIPMIDI value="no"/>
|
||||
<NoHandShake value="yes"/>
|
||||
<IsP1Nano value="yes"/>
|
||||
<HasQConSecondLCD value="yes"/>
|
||||
<HasQConMasterMeters value="yes"/>
|
||||
</MackieProtocolDevice>
|
||||
20
share/mcp/p1_x+p1_nano.device
Normal file
20
share/mcp/p1_x+p1_nano.device
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MackieProtocolDevice>
|
||||
<Name value="iCON P1-NANO with P1-X on left"/>
|
||||
<Strips value="8"/>
|
||||
<Extenders value="1"/>
|
||||
<MasterPosition value="2"/>
|
||||
<MasterFader value="yes"/>
|
||||
<TimecodeDisplay value="yes"/>
|
||||
<TwoCharacterDisplay value="no"/>
|
||||
<HasSeparateMeters value="yes"/>
|
||||
<GlobalControls value="yes"/>
|
||||
<JogWheel value="yes"/>
|
||||
<TouchSenseFaders value="yes"/>
|
||||
<LogicControlButtons value="yes"/>
|
||||
<usesIPMIDI value="no"/>
|
||||
<NoHandShake value="yes"/>
|
||||
<IsP1Nano value="yes"/>
|
||||
<HasQConSecondLCD value="yes"/>
|
||||
<HasQConMasterMeters value="yes"/>
|
||||
</MackieProtocolDevice>
|
||||
|
|
@ -58,7 +58,7 @@ function factory () return function ()
|
|||
|
||||
-- ..generate random offset..
|
||||
local tickdiff = math.floor (rv['rand']() * max_distance);
|
||||
print (old_pos:get_beats (), old_pos:get_ticks (), tickdiff)
|
||||
--print (old_pos:get_beats (), old_pos:get_ticks (), tickdiff)
|
||||
|
||||
-- .. and calculate new position.
|
||||
local new_pos = Temporal.Beats (old_pos:get_beats (), old_pos:get_ticks () + tickdiff)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue