Support note names from midnam files (tested with the DM5).
Do this via a simple MasterDeviceNames::note_name() function. The same really needs to be done for program names, this stuff is absolutely brutal to use. Store note names in a vector indexed by number instead of a list with string "numbers" for reasonable lookup time. Make some references const that should be. git-svn-id: svn://localhost/ardour2/branches/3.0@13908 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
448c156b4b
commit
88de45b7cc
|
@ -1846,7 +1846,7 @@ MidiRegionView::patch_change_to_patch_key (MidiModel::PatchChangePtr p)
|
|||
}
|
||||
|
||||
void
|
||||
MidiRegionView::get_patch_key_at (double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key)
|
||||
MidiRegionView::get_patch_key_at (double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const
|
||||
{
|
||||
MidiModel::PatchChanges::iterator i = _model->patch_change_lower_bound (time);
|
||||
while (i != _model->patch_changes().end() && (*i)->channel() != channel) {
|
||||
|
@ -3808,14 +3808,32 @@ MidiRegionView::delete_sysex (CanvasSysEx* sysex)
|
|||
void
|
||||
MidiRegionView::show_verbose_cursor (boost::shared_ptr<NoteType> n) const
|
||||
{
|
||||
char buf[24];
|
||||
snprintf (buf, sizeof (buf), "%s (%d) Chn %d\nVel %d",
|
||||
Evoral::midi_note_name (n->note()).c_str(),
|
||||
using namespace MIDI::Name;
|
||||
|
||||
std::string name;
|
||||
|
||||
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
|
||||
if (mtv) {
|
||||
boost::shared_ptr<MasterDeviceNames> device_names(mtv->get_device_names());
|
||||
if (device_names) {
|
||||
MIDI::Name::PatchPrimaryKey patch_key;
|
||||
get_patch_key_at(n->time(), n->channel(), patch_key);
|
||||
name = device_names->note_name(mtv->gui_property(X_("midnam-custom-device-mode")),
|
||||
n->channel(),
|
||||
patch_key.bank_number,
|
||||
patch_key.program_number,
|
||||
n->note());
|
||||
}
|
||||
}
|
||||
|
||||
char buf[128];
|
||||
snprintf (buf, sizeof (buf), "%d %s\nCh %d Vel %d",
|
||||
(int) n->note (),
|
||||
name.empty() ? Evoral::midi_note_name (n->note()).c_str() : name.c_str(),
|
||||
(int) n->channel() + 1,
|
||||
(int) n->velocity());
|
||||
|
||||
show_verbose_cursor (buf, 10, 20);
|
||||
show_verbose_cursor(buf, 10, 20);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -127,11 +127,11 @@ public:
|
|||
* @key a reference to an instance of MIDI::Name::PatchPrimaryKey whose fields will
|
||||
* will be set according to the result of the lookup
|
||||
*/
|
||||
void get_patch_key_at (double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key);
|
||||
void get_patch_key_at (double time, uint8_t channel, MIDI::Name::PatchPrimaryKey& key) const;
|
||||
|
||||
/** Convert a given PatchChange into a PatchPrimaryKey
|
||||
*/
|
||||
MIDI::Name::PatchPrimaryKey patch_change_to_patch_key (ARDOUR::MidiModel::PatchChangePtr);
|
||||
/** Convert a given PatchChange into a PatchPrimaryKey
|
||||
*/
|
||||
MIDI::Name::PatchPrimaryKey patch_change_to_patch_key (ARDOUR::MidiModel::PatchChangePtr);
|
||||
|
||||
/** Change old_patch to new_patch.
|
||||
* @param old_patch the canvas patch change which is to be altered
|
||||
|
|
|
@ -232,8 +232,7 @@ MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
|
|||
}
|
||||
|
||||
if (gui_property (X_("midnam-custom-device-mode")).empty()) {
|
||||
boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names(
|
||||
gui_property (X_("midnam-model-name")));
|
||||
boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
|
||||
if (device_names) {
|
||||
set_gui_property (X_("midnam-custom-device-mode"),
|
||||
*device_names->custom_device_mode_names().begin());
|
||||
|
@ -760,10 +759,27 @@ MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_
|
|||
dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
|
||||
}
|
||||
|
||||
boost::shared_ptr<MIDI::Name::MasterDeviceNames>
|
||||
MidiTimeAxisView::get_device_names(const std::string& model)
|
||||
boost::shared_ptr<MIDI::Name::CustomDeviceMode>
|
||||
MidiTimeAxisView::get_device_mode()
|
||||
{
|
||||
using namespace MIDI::Name;
|
||||
|
||||
boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
|
||||
if (!device_names) {
|
||||
return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
|
||||
}
|
||||
|
||||
return device_names->custom_device_mode_by_name(
|
||||
gui_property (X_("midnam-custom-device-mode")));
|
||||
}
|
||||
|
||||
boost::shared_ptr<MIDI::Name::MasterDeviceNames>
|
||||
MidiTimeAxisView::get_device_names()
|
||||
{
|
||||
using namespace MIDI::Name;
|
||||
|
||||
const std::string model = gui_property (X_("midnam-model-name"));
|
||||
|
||||
boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
|
||||
.document_by_model(model);
|
||||
if (midnam) {
|
||||
|
@ -807,8 +823,7 @@ MidiTimeAxisView::build_controller_menu ()
|
|||
}
|
||||
|
||||
using namespace MIDI::Name;
|
||||
boost::shared_ptr<MasterDeviceNames> device_names = get_device_names(
|
||||
_midnam_model_selector.get_active_text());
|
||||
boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
|
||||
|
||||
if (device_names && !device_names->controls().empty()) {
|
||||
/* Controllers names available in midnam file, generate fancy menu */
|
||||
|
|
|
@ -80,6 +80,9 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
|||
ARDOUR::NoteMode note_mode() const { return _note_mode; }
|
||||
ARDOUR::ColorMode color_mode() const { return _color_mode; }
|
||||
|
||||
boost::shared_ptr<MIDI::Name::MasterDeviceNames> get_device_names();
|
||||
boost::shared_ptr<MIDI::Name::CustomDeviceMode> get_device_mode();
|
||||
|
||||
void update_range();
|
||||
|
||||
sigc::signal<void, ARDOUR::ChannelMode, uint16_t>& signal_channel_mode_changed() {
|
||||
|
@ -112,8 +115,6 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
|||
Gtk::Menu* build_note_mode_menu();
|
||||
Gtk::Menu* build_color_mode_menu();
|
||||
|
||||
boost::shared_ptr<MIDI::Name::MasterDeviceNames> get_device_names(const std::string& model);
|
||||
|
||||
void set_note_mode (ARDOUR::NoteMode mode, bool apply_to_selection = false);
|
||||
void set_color_mode (ARDOUR::ColorMode, bool force = false, bool redisplay = true, bool apply_to_selection = false);
|
||||
void set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection = false);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -44,12 +45,12 @@ public:
|
|||
int bank_number;
|
||||
int program_number;
|
||||
|
||||
PatchPrimaryKey (uint8_t a_program_number = 0, uint16_t a_bank_number = 0) {
|
||||
PatchPrimaryKey (uint8_t a_program_number = 0, uint16_t a_bank_number = 0) {
|
||||
bank_number = std::min (a_bank_number, (uint16_t) 16384);
|
||||
program_number = std::min (a_program_number, (uint8_t) 127);
|
||||
}
|
||||
|
||||
bool is_sane() {
|
||||
bool is_sane() const {
|
||||
return ((bank_number >= 0) && (bank_number <= 16384) &&
|
||||
(program_number >=0 ) && (program_number <= 127));
|
||||
}
|
||||
|
@ -87,13 +88,15 @@ public:
|
|||
Patch (std::string a_name = std::string(), uint8_t a_number = 0, uint16_t bank_number = 0);
|
||||
virtual ~Patch() {};
|
||||
|
||||
const std::string& name() const { return _name; }
|
||||
void set_name(const std::string a_name) { _name = a_name; }
|
||||
const std::string& name() const { return _name; }
|
||||
void set_name(const std::string a_name) { _name = a_name; }
|
||||
|
||||
const std::string& note_list_name() const { return _note_list_name; }
|
||||
|
||||
uint8_t program_number() const { return _id.program_number; }
|
||||
void set_program_number(uint8_t n) { _id.program_number = n; }
|
||||
uint8_t program_number() const { return _id.program_number; }
|
||||
void set_program_number(uint8_t n) { _id.program_number = n; }
|
||||
|
||||
uint16_t bank_number() const { return _id.bank_number; }
|
||||
uint16_t bank_number() const { return _id.bank_number; }
|
||||
void set_bank_number (uint16_t n) { _id.bank_number = n; }
|
||||
|
||||
const PatchPrimaryKey& patch_primary_key() const { return _id; }
|
||||
|
@ -104,6 +107,7 @@ public:
|
|||
private:
|
||||
std::string _name;
|
||||
PatchPrimaryKey _id;
|
||||
std::string _note_list_name;
|
||||
};
|
||||
|
||||
class PatchBank
|
||||
|
@ -155,12 +159,12 @@ public:
|
|||
return _available_for_channels.find(channel) != _available_for_channels.end();
|
||||
}
|
||||
|
||||
boost::shared_ptr<Patch> find_patch(PatchPrimaryKey& key) {
|
||||
boost::shared_ptr<Patch> find_patch(const PatchPrimaryKey& key) {
|
||||
assert(key.is_sane());
|
||||
return _patch_map[key];
|
||||
}
|
||||
|
||||
boost::shared_ptr<Patch> previous_patch(PatchPrimaryKey& key) {
|
||||
boost::shared_ptr<Patch> previous_patch(const PatchPrimaryKey& key) {
|
||||
assert(key.is_sane());
|
||||
for (PatchList::const_iterator i = _patch_list.begin();
|
||||
i != _patch_list.end();
|
||||
|
@ -176,7 +180,7 @@ public:
|
|||
return boost::shared_ptr<Patch>();
|
||||
}
|
||||
|
||||
boost::shared_ptr<Patch> next_patch(PatchPrimaryKey& key) {
|
||||
boost::shared_ptr<Patch> next_patch(const PatchPrimaryKey& key) {
|
||||
assert(key.is_sane());
|
||||
for (PatchList::const_iterator i = _patch_list.begin();
|
||||
i != _patch_list.end();
|
||||
|
@ -214,43 +218,42 @@ std::ostream& operator<< (std::ostream&, const ChannelNameSet&);
|
|||
class Note
|
||||
{
|
||||
public:
|
||||
Note() {};
|
||||
Note(std::string a_number, std::string a_name) : _number(a_number), _name(a_name) {};
|
||||
~Note() {};
|
||||
Note() {}
|
||||
Note(uint8_t number, const std::string& name) : _number(number), _name(name) {}
|
||||
|
||||
const std::string& name() const { return _name; }
|
||||
void set_name(const std::string a_name) { _name = a_name; }
|
||||
const std::string& name() const { return _name; }
|
||||
void set_name(const std::string& name) { _name = name; }
|
||||
|
||||
const std::string& number() const { return _number; }
|
||||
void set_number(const std::string a_number) { _number = a_number; }
|
||||
uint8_t number() const { return _number; }
|
||||
void set_number(uint8_t number) { _number = number; }
|
||||
|
||||
XMLNode& get_state (void);
|
||||
int set_state (const XMLTree&, const XMLNode&);
|
||||
|
||||
private:
|
||||
std::string _number;
|
||||
uint8_t _number;
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
class NoteNameList
|
||||
{
|
||||
public:
|
||||
typedef std::list<boost::shared_ptr<Note> > Notes;
|
||||
NoteNameList() {};
|
||||
NoteNameList (std::string a_name) : _name(a_name) {};
|
||||
~NoteNameList() {};
|
||||
typedef std::vector< boost::shared_ptr<Note> > Notes;
|
||||
|
||||
const std::string& name() const { return _name; }
|
||||
void set_name(const std::string a_name) { _name = a_name; }
|
||||
NoteNameList() { _notes.resize(128); }
|
||||
NoteNameList (const std::string& name) : _name(name) { _notes.resize(128); }
|
||||
|
||||
const Notes& notes() const { return _notes; }
|
||||
const std::string& name() const { return _name; }
|
||||
const Notes& notes() const { return _notes; }
|
||||
|
||||
void set_name(const std::string& name) { _name = name; }
|
||||
|
||||
XMLNode& get_state (void);
|
||||
int set_state (const XMLTree&, const XMLNode&);
|
||||
|
||||
private:
|
||||
std::string _name;
|
||||
Notes _notes;
|
||||
Notes _notes;
|
||||
};
|
||||
|
||||
class Control
|
||||
|
@ -339,7 +342,7 @@ public:
|
|||
typedef std::list<std::string> CustomDeviceModeNames;
|
||||
/// maps name to ChannelNameSet
|
||||
typedef std::map<std::string, boost::shared_ptr<ChannelNameSet> > ChannelNameSets;
|
||||
typedef std::list<boost::shared_ptr<NoteNameList> > NoteNameLists;
|
||||
typedef std::map<std::string, boost::shared_ptr<NoteNameList> > NoteNameLists;
|
||||
typedef std::list<boost::shared_ptr<ControlNameList> > ControlNameLists;
|
||||
typedef std::map<std::string, PatchBank::PatchNameList> PatchNameLists;
|
||||
|
||||
|
@ -358,8 +361,17 @@ public:
|
|||
|
||||
boost::shared_ptr<CustomDeviceMode> custom_device_mode_by_name(std::string mode_name);
|
||||
boost::shared_ptr<ChannelNameSet> channel_name_set_by_device_mode_and_channel(std::string mode, uint8_t channel);
|
||||
boost::shared_ptr<Patch> find_patch(std::string mode, uint8_t channel, PatchPrimaryKey& key);
|
||||
|
||||
boost::shared_ptr<Patch> find_patch(std::string mode, uint8_t channel, const PatchPrimaryKey& key);
|
||||
|
||||
boost::shared_ptr<NoteNameList> note_name_list(const std::string& name);
|
||||
boost::shared_ptr<ChannelNameSet> channel_name_set(const std::string& name);
|
||||
|
||||
std::string note_name(const std::string& mode_name,
|
||||
uint8_t channel,
|
||||
uint16_t bank,
|
||||
uint8_t program,
|
||||
uint8_t number);
|
||||
|
||||
XMLNode& get_state (void);
|
||||
int set_state (const XMLTree&, const XMLNode&);
|
||||
|
||||
|
|
|
@ -128,6 +128,11 @@ Patch::set_state (const XMLTree&, const XMLNode& node)
|
|||
assert(program_change.length());
|
||||
_id.program_number = PBD::atoi(program_change);
|
||||
}
|
||||
|
||||
XMLNode* use_note_name_list = node.child("UsesNoteNameList");
|
||||
if (use_note_name_list) {
|
||||
_note_list_name = use_note_name_list->property ("Name")->value();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -146,7 +151,12 @@ int
|
|||
Note::set_state (const XMLTree&, const XMLNode& node)
|
||||
{
|
||||
assert(node.name() == "Note");
|
||||
_number = node.property("Number")->value();
|
||||
|
||||
/* If the note number is junk, this will pull a number from the start, or
|
||||
return zero if there isn't one. Better error detection would be a good
|
||||
idea, but the duplicate check in NoteNameList::set_state() will probably
|
||||
catch really broken files anyway. */
|
||||
_number = atoi(node.property("Number")->value().c_str());
|
||||
_name = node.property("Name")->value();
|
||||
|
||||
return 0;
|
||||
|
@ -156,7 +166,7 @@ XMLNode&
|
|||
NoteNameList::get_state (void)
|
||||
{
|
||||
XMLNode* node = new XMLNode("NoteNameList");
|
||||
node->add_property("Name", _name);
|
||||
node->add_property("Name", _name);
|
||||
|
||||
return *node;
|
||||
}
|
||||
|
@ -165,13 +175,29 @@ int
|
|||
NoteNameList::set_state (const XMLTree& tree, const XMLNode& node)
|
||||
{
|
||||
assert(node.name() == "NoteNameList");
|
||||
_name = node.property("Name")->value();
|
||||
_name = node.property("Name")->value();
|
||||
_notes.clear();
|
||||
_notes.resize(128);
|
||||
|
||||
boost::shared_ptr<XMLSharedNodeList> notes = tree.find("//Note");
|
||||
for (XMLSharedNodeList::const_iterator i = notes->begin(); i != notes->end(); ++i) {
|
||||
for (XMLNodeList::const_iterator i = node.children().begin();
|
||||
i != node.children().end(); ++i) {
|
||||
if ((*i)->name() != "Note") {
|
||||
continue;
|
||||
}
|
||||
boost::shared_ptr<Note> note(new Note());
|
||||
note->set_state (tree, *(*i));
|
||||
_notes.push_back(note);
|
||||
if (note->number() > 127) {
|
||||
PBD::warning << string_compose("Note number %1 in %3 out of range",
|
||||
(int)note->number(), tree.filename())
|
||||
<< endmsg;
|
||||
} else if (_notes[note->number()]) {
|
||||
PBD::warning <<
|
||||
string_compose("Duplicate note number %1 name %2 in %3 ignored",
|
||||
(int)note->number(), note->name(), tree.filename())
|
||||
<< endmsg;
|
||||
} else {
|
||||
_notes[note->number()] = note;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -465,11 +491,58 @@ MasterDeviceNames::channel_name_set_by_device_mode_and_channel(std::string mode,
|
|||
}
|
||||
|
||||
boost::shared_ptr<Patch>
|
||||
MasterDeviceNames::find_patch(std::string mode, uint8_t channel, PatchPrimaryKey& key)
|
||||
MasterDeviceNames::find_patch(std::string mode, uint8_t channel, const PatchPrimaryKey& key)
|
||||
{
|
||||
return channel_name_set_by_device_mode_and_channel(mode, channel)->find_patch(key);
|
||||
}
|
||||
|
||||
boost::shared_ptr<ChannelNameSet>
|
||||
MasterDeviceNames::channel_name_set(const std::string& name)
|
||||
{
|
||||
ChannelNameSets::const_iterator i = _channel_name_sets.find(name);
|
||||
if (i != _channel_name_sets.end()) {
|
||||
return i->second;
|
||||
}
|
||||
return boost::shared_ptr<ChannelNameSet>();
|
||||
}
|
||||
|
||||
boost::shared_ptr<NoteNameList>
|
||||
MasterDeviceNames::note_name_list(const std::string& name)
|
||||
{
|
||||
NoteNameLists::const_iterator i = _note_name_lists.find(name);
|
||||
if (i != _note_name_lists.end()) {
|
||||
return i->second;
|
||||
}
|
||||
return boost::shared_ptr<NoteNameList>();
|
||||
}
|
||||
|
||||
std::string
|
||||
MasterDeviceNames::note_name(const std::string& mode_name,
|
||||
uint8_t channel,
|
||||
uint16_t bank,
|
||||
uint8_t program,
|
||||
uint8_t number)
|
||||
{
|
||||
if (number > 127) {
|
||||
return "";
|
||||
}
|
||||
|
||||
boost::shared_ptr<const Patch> patch(
|
||||
find_patch(mode_name, channel, PatchPrimaryKey(program, bank)));
|
||||
if (!patch) {
|
||||
return "";
|
||||
}
|
||||
|
||||
boost::shared_ptr<const NoteNameList> note_names(
|
||||
note_name_list(patch->note_list_name()));
|
||||
if (!note_names) {
|
||||
return "";
|
||||
}
|
||||
|
||||
boost::shared_ptr<const Note> note(note_names->notes()[number]);
|
||||
return note ? note->name() : "";
|
||||
}
|
||||
|
||||
int
|
||||
MasterDeviceNames::set_state(const XMLTree& tree, const XMLNode&)
|
||||
{
|
||||
|
@ -520,7 +593,7 @@ MasterDeviceNames::set_state(const XMLTree& tree, const XMLNode&)
|
|||
++i) {
|
||||
boost::shared_ptr<NoteNameList> note_name_list(new NoteNameList());
|
||||
note_name_list->set_state (tree, *(*i));
|
||||
_note_name_lists.push_back(note_name_list);
|
||||
_note_name_lists[(*i)->property ("Name")->value()] = note_name_list;
|
||||
}
|
||||
|
||||
// ControlNameLists
|
||||
|
|
Loading…
Reference in New Issue