significant refactoring of code used to build MIDI CC menus so that it can be re-used
This commit is contained in:
@@ -87,6 +87,7 @@
|
||||
#include "midi_streamview.h"
|
||||
#include "midi_region_view.h"
|
||||
#include "midi_time_axis.h"
|
||||
#include "midi_util.h"
|
||||
#include "patch_change_dialog.h"
|
||||
#include "patch_change_widget.h"
|
||||
#include "piano_roll_header.h"
|
||||
@@ -983,9 +984,9 @@ MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
|
||||
|
||||
/** Add a single menu item for a controller on one channel. */
|
||||
void
|
||||
MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
|
||||
int ctl,
|
||||
const std::string& name)
|
||||
MidiTimeAxisView::add_single_channel_controller_item (Menu_Helpers::MenuList& ctl_items,
|
||||
int ctl,
|
||||
const std::string& name)
|
||||
{
|
||||
using namespace Menu_Helpers;
|
||||
|
||||
@@ -1002,8 +1003,7 @@ MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl
|
||||
fully_qualified_param)));
|
||||
dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
|
||||
|
||||
std::shared_ptr<AutomationTimeAxisView> track = automation_child (
|
||||
fully_qualified_param);
|
||||
std::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
|
||||
|
||||
bool visible = false;
|
||||
if (track) {
|
||||
@@ -1090,137 +1090,12 @@ MidiTimeAxisView::build_controller_menu ()
|
||||
}
|
||||
|
||||
controller_menu = new Menu; // explicitly managed by us
|
||||
MenuList& items (controller_menu->items());
|
||||
|
||||
/* create several "top level" menu items for sets of controllers (16 at a
|
||||
* time), and populate each one with a submenu for each controller+channel
|
||||
* combination covering the currently selected channels for this track
|
||||
*/
|
||||
|
||||
size_t total_ctrls = _route->instrument_info().master_controller_count ();
|
||||
if (total_ctrls > 0) {
|
||||
/* Controllers names available in midnam file, generate fancy menu */
|
||||
using namespace MIDI::Name;
|
||||
|
||||
unsigned n_items = 0;
|
||||
unsigned n_groups = 0;
|
||||
|
||||
/* keep track of CC numbers that are added */
|
||||
uint16_t ctl_start = 1;
|
||||
uint16_t ctl_end = 1;
|
||||
|
||||
MasterDeviceNames::ControlNameLists const& ctllist (_route->instrument_info().master_device_names ()->controls ());
|
||||
|
||||
bool per_name_list = ctllist.size () > 1;
|
||||
bool to_top_level = total_ctrls < 32 && !per_name_list;
|
||||
|
||||
/* reverse lookup which "ChannelNameSet" has "UsesControlNameList <this list>"
|
||||
* then check for which channels it is valid "AvailableForChannels"
|
||||
*/
|
||||
|
||||
for (MasterDeviceNames::ControlNameLists::const_iterator l = ctllist.begin(); l != ctllist.end(); ++l) {
|
||||
|
||||
uint16_t channels = _route->instrument_info().channels_for_control_list (l->first);
|
||||
bool multi_channel = 0 != (channels & (channels - 1));
|
||||
|
||||
std::shared_ptr<ControlNameList> name_list = l->second;
|
||||
Menu* ctl_menu = NULL;
|
||||
|
||||
for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
|
||||
c != name_list->controls().end();) {
|
||||
|
||||
const uint16_t ctl = c->second->number();
|
||||
|
||||
/* Skip bank select controllers since they're handled specially */
|
||||
if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
|
||||
|
||||
if (to_top_level) {
|
||||
ctl_menu = controller_menu;
|
||||
} else if (!ctl_menu) {
|
||||
/* Create a new submenu */
|
||||
ctl_menu = manage (new Menu);
|
||||
ctl_start = ctl;
|
||||
}
|
||||
|
||||
MenuList& ctl_items (ctl_menu->items());
|
||||
if (multi_channel) {
|
||||
add_multi_channel_controller_item(ctl_items, channels, ctl, c->second->name());
|
||||
} else {
|
||||
add_single_channel_controller_item(ctl_items, ctl, c->second->name());
|
||||
}
|
||||
ctl_end = ctl;
|
||||
}
|
||||
|
||||
++c;
|
||||
|
||||
if (!ctl_menu || to_top_level) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (++n_items == 32 || ctl < ctl_start || c == name_list->controls().end()) {
|
||||
/* Submenu has 32 items or we're done, or a new name-list started:
|
||||
* add it to controller menu and reset */
|
||||
items.push_back (MenuElem (string_compose ("%1 %2-%3",
|
||||
(per_name_list ? l->first.c_str() : _("Controllers")),
|
||||
ctl_start, ctl_end), *ctl_menu));
|
||||
ctl_menu = NULL;
|
||||
n_items = 0;
|
||||
++n_groups;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* No controllers names, generate generic numeric menu */
|
||||
|
||||
const uint16_t selected_channels = midi_track()->get_playback_channel_mask();
|
||||
|
||||
/* count the number of selected channels because we will build a different menu
|
||||
* structure if there is more than 1 selected.
|
||||
*/
|
||||
|
||||
int chn_cnt = 0;
|
||||
for (uint8_t chn = 0; chn < 16; chn++) {
|
||||
if (selected_channels & (0x0001 << chn)) {
|
||||
if (++chn_cnt > 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 127; i += 32) {
|
||||
Menu* ctl_menu = manage (new Menu);
|
||||
MenuList& ctl_items (ctl_menu->items());
|
||||
|
||||
for (int ctl = i; ctl < i + 32; ++ctl) {
|
||||
if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
|
||||
/* Skip bank select controllers since they're handled specially */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chn_cnt > 1) {
|
||||
add_multi_channel_controller_item(
|
||||
ctl_items, selected_channels, ctl, string_compose(_("Controller %1"), ctl));
|
||||
} else {
|
||||
add_single_channel_controller_item(
|
||||
ctl_items, ctl, string_compose(_("Controller %1"), ctl));
|
||||
}
|
||||
}
|
||||
|
||||
/* Add submenu for this block of controllers to controller menu */
|
||||
switch (i) {
|
||||
case 0:
|
||||
case 32:
|
||||
/* skip 0x00 and 0x20 (bank-select) */
|
||||
items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i + 1, i + 31), *ctl_menu));
|
||||
break;
|
||||
default:
|
||||
items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i + 31), *ctl_menu));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
::build_controller_menu (*controller_menu, _route->instrument_info(), midi_track()->get_playback_channel_mask(),
|
||||
sigc::mem_fun (*this, &MidiTimeAxisView::add_single_channel_controller_item),
|
||||
sigc::mem_fun (*this, &MidiTimeAxisView::add_multi_channel_controller_item));
|
||||
}
|
||||
|
||||
|
||||
Gtk::Menu*
|
||||
MidiTimeAxisView::build_note_mode_menu()
|
||||
{
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace ARDOUR {
|
||||
class Processor;
|
||||
class Location;
|
||||
class MidiPlaylist;
|
||||
class InstrumentInfo;
|
||||
}
|
||||
|
||||
namespace Evoral {
|
||||
@@ -209,4 +210,3 @@ private:
|
||||
void mouse_mode_changed ();
|
||||
PBD::ScopedConnection mouse_mode_connection;
|
||||
};
|
||||
|
||||
|
||||
174
gtk2_ardour/midi_util.cc
Normal file
174
gtk2_ardour/midi_util.cc
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
|
||||
* Copyright (C) 2008-2012 Hans Baier <hansfbaier@googlemail.com>
|
||||
* Copyright (C) 2008-2017 Paul Davis <paul@linuxaudiosystems.com>
|
||||
* Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
|
||||
* Copyright (C) 2013-2014 John Emmas <john@creativepost.co.uk>
|
||||
* Copyright (C) 2013-2016 Tim Mayberry <mojofunk@gmail.com>
|
||||
* Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
|
||||
* Copyright (C) 2014-2017 Ben Loftis <ben@harrisonconsoles.com>
|
||||
* Copyright (C) 2015-2017 Nick Mainsbridge <mainsbridge@gmail.com>
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <sigc++/bind.h>
|
||||
|
||||
#include <ytkmm/menu.h>
|
||||
|
||||
#include "ardour/event_type_map.h"
|
||||
#include "ardour/instrument_info.h"
|
||||
#include "ardour/midi_patch_manager.h"
|
||||
|
||||
#include "midi++/events.h"
|
||||
|
||||
#include "midi_util.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace Gtk;
|
||||
using namespace std;
|
||||
|
||||
|
||||
void
|
||||
build_controller_menu (Gtk::Menu& menu, InstrumentInfo const & instrument_info, uint16_t channel_mask,
|
||||
std::function<void (Menu_Helpers::MenuList&, int, const std::string&)> add_single,
|
||||
std::function<void (Menu_Helpers::MenuList&, uint16_t, int, const std::string&)> add_multi)
|
||||
{
|
||||
using namespace Menu_Helpers;
|
||||
|
||||
/* create several "top level" menu items for sets of controllers (16 at a
|
||||
* time), and populate each one with a submenu for each controller+channel
|
||||
* combination covering the currently selected channels for this track
|
||||
*/
|
||||
|
||||
MenuList& items (menu.items());
|
||||
|
||||
size_t total_ctrls = instrument_info.master_controller_count ();
|
||||
if (total_ctrls > 0) {
|
||||
/* Controllers names available in midnam file, generate fancy menu */
|
||||
using namespace MIDI::Name;
|
||||
|
||||
unsigned n_items = 0;
|
||||
unsigned n_groups = 0;
|
||||
|
||||
/* keep track of CC numbers that are added */
|
||||
uint16_t ctl_start = 1;
|
||||
uint16_t ctl_end = 1;
|
||||
|
||||
MasterDeviceNames::ControlNameLists const& ctllist (instrument_info.master_device_names ()->controls ());
|
||||
|
||||
bool per_name_list = ctllist.size () > 1;
|
||||
bool to_top_level = total_ctrls < 32 && !per_name_list;
|
||||
|
||||
/* reverse lookup which "ChannelNameSet" has "UsesControlNameList <this list>"
|
||||
* then check for which channels it is valid "AvailableForChannels"
|
||||
*/
|
||||
|
||||
for (MasterDeviceNames::ControlNameLists::const_iterator l = ctllist.begin(); l != ctllist.end(); ++l) {
|
||||
|
||||
uint16_t channels = instrument_info.channels_for_control_list (l->first);
|
||||
bool multi_channel = (0 != (channels & (channels - 1)));
|
||||
|
||||
std::shared_ptr<ControlNameList> name_list = l->second;
|
||||
Menu* ctl_menu = nullptr;
|
||||
|
||||
for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
|
||||
c != name_list->controls().end();) {
|
||||
|
||||
const uint16_t ctl = c->second->number();
|
||||
|
||||
/* Skip bank select controllers since they're handled specially */
|
||||
if (ctl != MIDI_CTL_MSB_BANK && ctl != MIDI_CTL_LSB_BANK) {
|
||||
|
||||
if (to_top_level) {
|
||||
ctl_menu = &menu;
|
||||
} else if (!ctl_menu) {
|
||||
/* Create a new submenu */
|
||||
ctl_menu = manage (new Menu);
|
||||
ctl_start = ctl;
|
||||
}
|
||||
|
||||
MenuList& ctl_items (ctl_menu->items());
|
||||
if (multi_channel) {
|
||||
add_multi (ctl_items, channels, ctl, c->second->name());
|
||||
} else {
|
||||
add_single (ctl_items, ctl, c->second->name());
|
||||
}
|
||||
ctl_end = ctl;
|
||||
}
|
||||
|
||||
++c;
|
||||
|
||||
if (!ctl_menu || to_top_level) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (++n_items == 32 || ctl < ctl_start || c == name_list->controls().end()) {
|
||||
/* Submenu has 32 items or we're done, or a new name-list started:
|
||||
* add it to controller menu and reset */
|
||||
items.push_back (MenuElem (string_compose ("%1 %2-%3",
|
||||
(per_name_list ? l->first.c_str() : _("Controllers")),
|
||||
ctl_start, ctl_end), *ctl_menu));
|
||||
ctl_menu = nullptr;
|
||||
n_items = 0;
|
||||
++n_groups;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* No controllers names, generate generic numeric menu */
|
||||
|
||||
bool multi_channel = (0 != (channel_mask & (channel_mask - 1)));
|
||||
|
||||
/* count the number of selected channels because we will build a different menu
|
||||
* structure if there is more than 1 selected.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < 127; i += 32) {
|
||||
Menu* ctl_menu = manage (new Menu);
|
||||
MenuList& ctl_items (ctl_menu->items());
|
||||
|
||||
for (int ctl = i; ctl < i + 32; ++ctl) {
|
||||
if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
|
||||
/* Skip bank select controllers since they're handled specially */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (multi_channel) {
|
||||
add_multi (ctl_items, channel_mask, ctl, string_compose(_("Controller %1"), ctl));
|
||||
} else {
|
||||
add_single (ctl_items, ctl, string_compose(_("Controller %1"), ctl));
|
||||
}
|
||||
}
|
||||
|
||||
/* Add submenu for this block of controllers to controller menu */
|
||||
switch (i) {
|
||||
case 0:
|
||||
case 32:
|
||||
/* skip 0x00 and 0x20 (bank-select) */
|
||||
items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i + 1, i + 31), *ctl_menu));
|
||||
break;
|
||||
default:
|
||||
items.push_back (MenuElem (string_compose (_("Controllers %1-%2"), i, i + 31), *ctl_menu));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace Gtk {
|
||||
class Menu;
|
||||
namespace Menu_Helpers {
|
||||
class MenuList;
|
||||
}
|
||||
}
|
||||
|
||||
namespace ARDOUR {
|
||||
class InstrumentInfo;
|
||||
}
|
||||
|
||||
inline static void clamp_to_0_127(uint8_t &val)
|
||||
{
|
||||
@@ -31,3 +43,7 @@ inline static void clamp_to_0_127(uint8_t &val)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
build_controller_menu (Gtk::Menu& menu, ARDOUR::InstrumentInfo const & instrument_info, uint16_t channel_mask,
|
||||
std::function<void (Gtk::Menu_Helpers::MenuList&, int, const std::string&)> add_single,
|
||||
std::function<void (Gtk::Menu_Helpers::MenuList&, uint16_t, int, const std::string&)> add_multi);
|
||||
|
||||
@@ -167,6 +167,7 @@ gtk2_ardour_sources = [
|
||||
'midi_streamview.cc',
|
||||
'midi_time_axis.cc',
|
||||
'midi_tracer.cc',
|
||||
'midi_util.cc',
|
||||
'midi_velocity_dialog.cc',
|
||||
'midi_view.cc',
|
||||
'midi_view_background.cc',
|
||||
|
||||
Reference in New Issue
Block a user