13
0
livetrax/libs/midi++2/midnam_patch.cc
Robin Gareus a361781e08 plug a major mem hog.
(default empty session is now ~140MB RSS, was 280MB)
libXML memory was only free() at exit
2014-09-09 23:53:27 +02:00

1083 lines
29 KiB
C++

/*
Copyright (C) 2008 Hans Baier
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 <stdlib.h>
#include <algorithm>
#include <iostream>
#include "midi++/midnam_patch.h"
#include "pbd/compose.h"
#include "pbd/convert.h"
#include "pbd/error.h"
#include "pbd/failed_constructor.h"
using namespace std;
using PBD::error;
namespace MIDI
{
namespace Name
{
Patch::Patch (std::string name, uint8_t p_number, uint16_t b_number)
: _name (name)
, _id (p_number, b_number)
{
}
static int
string_to_int(const XMLTree& tree, const std::string& str)
{
char* endptr = NULL;
const int i = strtol(str.c_str(), &endptr, 10);
if (str.empty() || *endptr != '\0') {
PBD::error << string_compose("%1: Bad number `%2'", tree.filename(), str)
<< endmsg;
}
return i;
}
static int
initialize_primary_key_from_commands (
const XMLTree& tree, PatchPrimaryKey& id, const XMLNode* node)
{
id.bank_number = 0;
const XMLNodeList events = node->children();
for (XMLNodeList::const_iterator i = events.begin(); i != events.end(); ++i) {
XMLNode* node = *i;
if (node->name() == "ControlChange") {
const string& control = node->property("Control")->value();
const string& value = node->property("Value")->value();
if (control == "0") {
id.bank_number |= string_to_int(tree, value) << 7;
} else if (control == "32") {
id.bank_number |= string_to_int(tree, value);
}
} else if (node->name() == "ProgramChange") {
const string& number = node->property("Number")->value();
assert(number != "");
id.program_number = string_to_int(tree, number);
}
}
return 0;
}
XMLNode&
Patch::get_state (void)
{
XMLNode* node = new XMLNode("Patch");
/* XXX this is totally wrong */
node->add_property("Number", string_compose ("%1", _id.program_number));
node->add_property("Name", _name);
/*
typedef std::list< boost::shared_ptr< Evoral::MIDIEvent<double> > > PatchMidiCommands;
XMLNode* commands = node->add_child("PatchMIDICommands");
for (PatchMidiCommands::const_iterator event = _patch_midi_commands.begin();
event != _patch_midi_commands.end();
++event) {
commands->add_child_copy(*((((Evoral::MIDIEvent&)*event)).to_xml()));
}
*/
return *node;
}
int
Patch::set_state (const XMLTree& tree, const XMLNode& node)
{
if (node.name() != "Patch") {
cerr << "Incorrect node " << node.name() << " handed to Patch" << endl;
return -1;
}
/* Note there is a "Number" attribute, but it's really more like a label
and is often not numeric. We currently do not use it. */
const XMLProperty* program_change = node.property("ProgramChange");
if (program_change) {
_id.program_number = string_to_int(tree, program_change->value());
}
const XMLProperty* name = node.property("Name");
if (!name) {
return -1;
}
_name = name->value();
XMLNode* commands = node.child("PatchMIDICommands");
if (commands) {
if (initialize_primary_key_from_commands(tree, _id, commands) &&
!program_change) {
return -1; // Failed to find a program number anywhere
}
}
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;
}
XMLNode&
Note::get_state (void)
{
XMLNode* node = new XMLNode("Note");
node->add_property("Number", _number + 1);
node->add_property("Name", _name);
return *node;
}
int
Note::set_state (const XMLTree& tree, const XMLNode& node)
{
assert(node.name() == "Note");
const int num = string_to_int(tree, node.property("Number")->value());
if (num < 1 || num > 128) {
PBD::warning << string_compose("%1: Note number %2 (%3) out of range",
tree.filename(), num, _name)
<< endmsg;
return -1;
}
_number = num - 1;
_name = node.property("Name")->value();
return 0;
}
XMLNode&
NoteNameList::get_state (void)
{
XMLNode* node = new XMLNode("NoteNameList");
node->add_property("Name", _name);
return *node;
}
static void
add_note_from_xml (NoteNameList::Notes& notes, const XMLTree& tree, const XMLNode& node)
{
boost::shared_ptr<Note> note(new Note());
if (!note->set_state (tree, node)) {
if (!notes[note->number()]) {
notes[note->number()] = note;
} else {
PBD::warning
<< string_compose("%1: Duplicate note number %2 (%3) ignored",
tree.filename(), (int)note->number(), note->name())
<< endmsg;
}
}
}
int
NoteNameList::set_state (const XMLTree& tree, const XMLNode& node)
{
assert(node.name() == "NoteNameList");
_name = node.property("Name")->value();
_notes.clear();
_notes.resize(128);
for (XMLNodeList::const_iterator i = node.children().begin();
i != node.children().end(); ++i) {
if ((*i)->name() == "Note") {
add_note_from_xml(_notes, tree, **i);
} else if ((*i)->name() == "NoteGroup") {
for (XMLNodeList::const_iterator j = (*i)->children().begin();
j != (*i)->children().end(); ++j) {
if ((*j)->name() == "Note") {
add_note_from_xml(_notes, tree, **j);
} else {
PBD::warning << string_compose("%1: Invalid NoteGroup child %2 ignored",
tree.filename(), (*j)->name())
<< endmsg;
}
}
}
}
return 0;
}
XMLNode&
Control::get_state (void)
{
XMLNode* node = new XMLNode("Control");
node->add_property("Type", _type);
node->add_property("Number", _number);
node->add_property("Name", _name);
return *node;
}
int
Control::set_state (const XMLTree& tree, const XMLNode& node)
{
assert(node.name() == "Control");
if (node.property("Type")) {
_type = node.property("Type")->value();
} else {
_type = "7bit";
}
_number = string_to_int(tree, node.property("Number")->value());
_name = node.property("Name")->value();
for (XMLNodeList::const_iterator i = node.children().begin();
i != node.children().end(); ++i) {
if ((*i)->name() == "Values") {
// <Values> has Min and Max properties, but we don't care
for (XMLNodeList::const_iterator j = (*i)->children().begin();
j != (*i)->children().end(); ++j) {
if ((*j)->name() == "ValueNameList") {
_value_name_list = boost::shared_ptr<ValueNameList>(new ValueNameList());
_value_name_list->set_state(tree, **j);
} else if ((*j)->name() == "UsesValueNameList") {
_value_name_list_name = (*j)->property("Name")->value();
}
}
}
}
return 0;
}
XMLNode&
ControlNameList::get_state (void)
{
XMLNode* node = new XMLNode("ControlNameList");
node->add_property("Name", _name);
return *node;
}
int
ControlNameList::set_state (const XMLTree& tree, const XMLNode& node)
{
assert(node.name() == "ControlNameList");
_name = node.property("Name")->value();
_controls.clear();
for (XMLNodeList::const_iterator i = node.children().begin();
i != node.children().end(); ++i) {
if ((*i)->name() == "Control") {
boost::shared_ptr<Control> control(new Control());
control->set_state (tree, *(*i));
if (_controls.find(control->number()) == _controls.end()) {
_controls.insert(make_pair(control->number(), control));
} else {
PBD::warning << string_compose("%1: Duplicate control %2 ignored",
tree.filename(), control->number())
<< endmsg;
}
}
}
return 0;
}
boost::shared_ptr<const Control>
ControlNameList::control(uint16_t num) const
{
Controls::const_iterator i = _controls.find(num);
if (i != _controls.end()) {
return i->second;
}
return boost::shared_ptr<const Control>();
}
XMLNode&
Value::get_state (void)
{
XMLNode* node = new XMLNode("Value");
node->add_property("Number", _number);
node->add_property("Name", _name);
return *node;
}
int
Value::set_state (const XMLTree& tree, const XMLNode& node)
{
assert(node.name() == "Value");
_number = string_to_int(tree, node.property("Number")->value());
_name = node.property("Name")->value();
return 0;
}
XMLNode&
ValueNameList::get_state (void)
{
XMLNode* node = new XMLNode("ValueNameList");
node->add_property("Name", _name);
return *node;
}
int
ValueNameList::set_state (const XMLTree& tree, const XMLNode& node)
{
assert(node.name() == "ValueNameList");
const XMLProperty* name_prop = node.property("Name");
if (name_prop) {
// May be anonymous if written inline within a single <Control> tag
_name = name_prop->value();
}
_values.clear();
for (XMLNodeList::const_iterator i = node.children().begin();
i != node.children().end(); ++i) {
if ((*i)->name() == "Value") {
boost::shared_ptr<Value> value(new Value());
value->set_state (tree, *(*i));
if (_values.find(value->number()) == _values.end()) {
_values.insert(make_pair(value->number(), value));
} else {
PBD::warning << string_compose("%1: Duplicate value %2 ignored",
tree.filename(), value->number())
<< endmsg;
}
}
}
return 0;
}
boost::shared_ptr<const Value>
ValueNameList::value(uint16_t num) const
{
Values::const_iterator i = _values.find(num);
if (i != _values.end()) {
return i->second;
}
return boost::shared_ptr<const Value>();
}
boost::shared_ptr<const Value>
ValueNameList::max_value_below(uint16_t num) const
{
Values::const_iterator i = _values.lower_bound(num);
if (i->first == num) {
// Exact match
return i->second;
} else if (i == _values.begin()) {
// No value is < num
return boost::shared_ptr<const Value>();
} else {
// Found the smallest element >= num, so the previous one is our result
--i;
return i->second;
}
}
XMLNode&
PatchBank::get_state (void)
{
XMLNode* node = new XMLNode("PatchBank");
node->add_property("Name", _name);
XMLNode* patch_name_list = node->add_child("PatchNameList");
for (PatchNameList::iterator patch = _patch_name_list.begin();
patch != _patch_name_list.end();
++patch) {
patch_name_list->add_child_nocopy((*patch)->get_state());
}
return *node;
}
int
PatchBank::set_state (const XMLTree& tree, const XMLNode& node)
{
assert(node.name() == "PatchBank");
_name = node.property("Name")->value();
XMLNode* commands = node.child("MIDICommands");
if (commands) {
PatchPrimaryKey id (0, 0);
if (initialize_primary_key_from_commands (tree, id, commands)) {
return -1;
}
_number = id.bank_number;
}
XMLNode* patch_name_list = node.child("PatchNameList");
if (patch_name_list) {
const XMLNodeList patches = patch_name_list->children();
for (XMLNodeList::const_iterator i = patches.begin(); i != patches.end(); ++i) {
boost::shared_ptr<Patch> patch (new Patch (string(), 0, _number));
patch->set_state(tree, *(*i));
_patch_name_list.push_back(patch);
}
} else {
XMLNode* use_patch_name_list = node.child ("UsesPatchNameList");
if (use_patch_name_list) {
_patch_list_name = use_patch_name_list->property ("Name")->value();
} else {
error << "Patch without patch name list - patchfile will be ignored" << endmsg;
return -1;
}
}
return 0;
}
int
PatchBank::set_patch_name_list (const PatchNameList& pnl)
{
_patch_name_list = pnl;
_patch_list_name = "";
for (PatchNameList::iterator p = _patch_name_list.begin(); p != _patch_name_list.end(); p++) {
(*p)->set_bank_number (_number);
}
return 0;
}
std::ostream&
operator<< (std::ostream& os, const ChannelNameSet& cns)
{
os << "Channel Name Set: name = " << cns._name << endl
<< "Map size " << cns._patch_map.size () << endl
<< "List size " << cns._patch_list.size() << endl
<< "Patch list name = [" << cns._patch_list_name << ']' << endl
<< "Available channels : ";
for (set<uint8_t>::const_iterator x = cns._available_for_channels.begin(); x != cns._available_for_channels.end(); ++x) {
os << (int) (*x) << ' ';
}
os << endl;
for (ChannelNameSet::PatchBanks::const_iterator pbi = cns._patch_banks.begin(); pbi != cns._patch_banks.end(); ++pbi) {
os << "\tPatch Bank " << (*pbi)->name() << " with " << (*pbi)->patch_name_list().size() << " patches\n";
for (PatchNameList::const_iterator pni = (*pbi)->patch_name_list().begin(); pni != (*pbi)->patch_name_list().end(); ++pni) {
os << "\t\tPatch name " << (*pni)->name() << " prog " << (int) (*pni)->program_number() << " bank " << (*pni)->bank_number() << endl;
}
}
return os;
}
void
ChannelNameSet::set_patch_banks (const ChannelNameSet::PatchBanks& pb)
{
_patch_banks = pb;
_patch_map.clear ();
_patch_list.clear ();
_patch_list_name = "";
_available_for_channels.clear ();
for (PatchBanks::const_iterator pbi = _patch_banks.begin(); pbi != _patch_banks.end(); ++pbi) {
for (PatchNameList::const_iterator pni = (*pbi)->patch_name_list().begin(); pni != (*pbi)->patch_name_list().end(); ++pni) {
_patch_map[(*pni)->patch_primary_key()] = (*pni);
_patch_list.push_back ((*pni)->patch_primary_key());
}
}
for (uint8_t n = 0; n < 16; ++n) {
_available_for_channels.insert (n);
}
}
void
ChannelNameSet::use_patch_name_list (const PatchNameList& pnl)
{
for (PatchNameList::const_iterator p = pnl.begin(); p != pnl.end(); ++p) {
_patch_map[(*p)->patch_primary_key()] = (*p);
_patch_list.push_back ((*p)->patch_primary_key());
}
}
XMLNode&
ChannelNameSet::get_state (void)
{
XMLNode* node = new XMLNode("ChannelNameSet");
node->add_property("Name", _name);
XMLNode* available_for_channels = node->add_child("AvailableForChannels");
assert(available_for_channels);
for (uint8_t channel = 0; channel < 16; ++channel) {
XMLNode* available_channel = available_for_channels->add_child("AvailableChannel");
assert(available_channel);
available_channel->add_property("Channel", (long) channel);
if (_available_for_channels.find(channel) != _available_for_channels.end()) {
available_channel->add_property("Available", "true");
} else {
available_channel->add_property("Available", "false");
}
}
for (PatchBanks::iterator patch_bank = _patch_banks.begin();
patch_bank != _patch_banks.end();
++patch_bank) {
node->add_child_nocopy((*patch_bank)->get_state());
}
return *node;
}
int
ChannelNameSet::set_state (const XMLTree& tree, const XMLNode& node)
{
assert(node.name() == "ChannelNameSet");
_name = node.property("Name")->value();
const XMLNodeList children = node.children();
for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
XMLNode* node = *i;
assert(node);
if (node->name() == "AvailableForChannels") {
boost::shared_ptr<XMLSharedNodeList> channels =
tree.find("//AvailableChannel[@Available = 'true']/@Channel", node);
for (XMLSharedNodeList::const_iterator i = channels->begin();
i != channels->end();
++i) {
_available_for_channels.insert(
string_to_int(tree, (*i)->attribute_value()));
}
} else if (node->name() == "PatchBank") {
boost::shared_ptr<PatchBank> bank (new PatchBank ());
bank->set_state(tree, *node);
_patch_banks.push_back(bank);
const PatchNameList& patches = bank->patch_name_list();
for (PatchNameList::const_iterator patch = patches.begin();
patch != patches.end();
++patch) {
_patch_map[(*patch)->patch_primary_key()] = *patch;
_patch_list.push_back((*patch)->patch_primary_key());
}
} else if (node->name() == "UsesNoteNameList") {
_note_list_name = node->property ("Name")->value();
} else if (node->name() == "UsesControlNameList") {
_control_list_name = node->property ("Name")->value();
}
}
return 0;
}
int
CustomDeviceMode::set_state(const XMLTree& tree, const XMLNode& a_node)
{
assert(a_node.name() == "CustomDeviceMode");
_name = a_node.property("Name")->value();
boost::shared_ptr<XMLSharedNodeList> channel_name_set_assignments =
tree.find("//ChannelNameSetAssign", const_cast<XMLNode *>(&a_node));
for (XMLSharedNodeList::const_iterator i = channel_name_set_assignments->begin();
i != channel_name_set_assignments->end();
++i) {
const int channel = string_to_int(tree, (*i)->property("Channel")->value());
const string& name_set = (*i)->property("NameSet")->value();
assert( 1 <= channel && channel <= 16 );
_channel_name_set_assignments[channel - 1] = name_set;
}
return 0;
}
XMLNode&
CustomDeviceMode::get_state(void)
{
XMLNode* custom_device_mode = new XMLNode("CustomDeviceMode");
custom_device_mode->add_property("Name", _name);
XMLNode* channel_name_set_assignments =
custom_device_mode->add_child("ChannelNameSetAssignments");
for (int i = 0; i < 15 && !_channel_name_set_assignments[i].empty(); i++) {
XMLNode* channel_name_set_assign =
channel_name_set_assignments->add_child("ChannelNameSetAssign");
channel_name_set_assign->add_property("Channel", i + 1);
channel_name_set_assign->add_property("NameSet", _channel_name_set_assignments[i]);
}
return *custom_device_mode;
}
boost::shared_ptr<const ValueNameList>
MasterDeviceNames::value_name_list_by_control(const std::string& mode, uint8_t channel, uint8_t number)
{
boost::shared_ptr<ChannelNameSet> chan_names = channel_name_set_by_channel(mode, channel);
if (!chan_names) {
return boost::shared_ptr<const ValueNameList>();
}
boost::shared_ptr<ControlNameList> control_names = control_name_list(chan_names->control_list_name());
if (!control_names) {
return boost::shared_ptr<const ValueNameList>();
}
boost::shared_ptr<const Control> control = control_names->control(number);
if (!control) {
return boost::shared_ptr<const ValueNameList>();
}
if (!control->value_name_list_name().empty()) {
return value_name_list(control->value_name_list_name());
} else {
return control->value_name_list();
}
}
boost::shared_ptr<CustomDeviceMode>
MasterDeviceNames::custom_device_mode_by_name(const std::string& mode_name)
{
return _custom_device_modes[mode_name];
}
boost::shared_ptr<ChannelNameSet>
MasterDeviceNames::channel_name_set_by_channel(const std::string& mode, uint8_t channel)
{
boost::shared_ptr<CustomDeviceMode> cdm = custom_device_mode_by_name(mode);
boost::shared_ptr<ChannelNameSet> cns = _channel_name_sets[cdm->channel_name_set_name_by_channel(channel)];
return cns;
}
boost::shared_ptr<Patch>
MasterDeviceNames::find_patch(const std::string& mode, uint8_t channel, const PatchPrimaryKey& key)
{
boost::shared_ptr<ChannelNameSet> cns = channel_name_set_by_channel(mode, channel);
if (!cns) return boost::shared_ptr<Patch>();
return cns->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<ControlNameList>
MasterDeviceNames::control_name_list(const std::string& name)
{
ControlNameLists::const_iterator i = _control_name_lists.find(name);
if (i != _control_name_lists.end()) {
return i->second;
}
return boost::shared_ptr<ControlNameList>();
}
boost::shared_ptr<ValueNameList>
MasterDeviceNames::value_name_list(const std::string& name)
{
ValueNameLists::const_iterator i = _value_name_lists.find(name);
if (i != _value_name_lists.end()) {
return i->second;
}
return boost::shared_ptr<ValueNameList>();
}
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 NoteNameList> note_names;
boost::shared_ptr<const Patch> patch(
find_patch(mode_name, channel, PatchPrimaryKey(program, bank)));
if (patch) {
note_names = note_name_list(patch->note_list_name());
}
if (!note_names) {
/* No note names specific to this patch, check the ChannelNameSet */
boost::shared_ptr<ChannelNameSet> chan_names = channel_name_set_by_channel(
mode_name, channel);
if (chan_names) {
note_names = note_name_list(chan_names->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&)
{
// Manufacturer
boost::shared_ptr<XMLSharedNodeList> manufacturer = tree.find("//Manufacturer");
assert(manufacturer->size() == 1);
_manufacturer = manufacturer->front()->children().front()->content();
// Models
boost::shared_ptr<XMLSharedNodeList> models = tree.find("//Model");
assert(models->size() >= 1);
for (XMLSharedNodeList::iterator i = models->begin();
i != models->end();
++i) {
const XMLNodeList& contents = (*i)->children();
assert(contents.size() == 1);
XMLNode * content = *(contents.begin());
assert(content->is_content());
_models.insert(content->content());
}
// CustomDeviceModes
boost::shared_ptr<XMLSharedNodeList> custom_device_modes = tree.find("//CustomDeviceMode");
for (XMLSharedNodeList::iterator i = custom_device_modes->begin();
i != custom_device_modes->end();
++i) {
boost::shared_ptr<CustomDeviceMode> custom_device_mode(new CustomDeviceMode());
custom_device_mode->set_state(tree, *(*i));
_custom_device_modes[custom_device_mode->name()] = custom_device_mode;
_custom_device_mode_names.push_back(custom_device_mode->name());
}
// ChannelNameSets
boost::shared_ptr<XMLSharedNodeList> channel_name_sets = tree.find("//ChannelNameSet");
for (XMLSharedNodeList::iterator i = channel_name_sets->begin();
i != channel_name_sets->end();
++i) {
boost::shared_ptr<ChannelNameSet> channel_name_set(new ChannelNameSet());
channel_name_set->set_state(tree, *(*i));
_channel_name_sets[channel_name_set->name()] = channel_name_set;
}
// NoteNameLists
boost::shared_ptr<XMLSharedNodeList> note_name_lists = tree.find("//NoteNameList");
for (XMLSharedNodeList::iterator i = note_name_lists->begin();
i != note_name_lists->end();
++i) {
boost::shared_ptr<NoteNameList> note_name_list(new NoteNameList());
note_name_list->set_state (tree, *(*i));
_note_name_lists[note_name_list->name()] = note_name_list;
}
// ControlNameLists
boost::shared_ptr<XMLSharedNodeList> control_name_lists = tree.find("//ControlNameList");
for (XMLSharedNodeList::iterator i = control_name_lists->begin();
i != control_name_lists->end();
++i) {
boost::shared_ptr<ControlNameList> control_name_list(new ControlNameList());
control_name_list->set_state (tree, *(*i));
_control_name_lists[control_name_list->name()] = control_name_list;
}
// ValueNameLists
boost::shared_ptr<XMLSharedNodeList> value_name_lists = tree.find("/child::MIDINameDocument/child::MasterDeviceNames/child::ValueNameList");
for (XMLSharedNodeList::iterator i = value_name_lists->begin();
i != value_name_lists->end();
++i) {
boost::shared_ptr<ValueNameList> value_name_list(new ValueNameList());
value_name_list->set_state (tree, *(*i));
_value_name_lists[value_name_list->name()] = value_name_list;
}
// global/post-facto PatchNameLists
boost::shared_ptr<XMLSharedNodeList> patch_name_lists = tree.find("/child::MIDINameDocument/child::MasterDeviceNames/child::PatchNameList");
for (XMLSharedNodeList::iterator i = patch_name_lists->begin();
i != patch_name_lists->end();
++i) {
PatchNameList patch_name_list;
const XMLNodeList patches = (*i)->children();
for (XMLNodeList::const_iterator p = patches.begin(); p != patches.end(); ++p) {
boost::shared_ptr<Patch> patch (new Patch ());
patch->set_state(tree, *(*p));
patch_name_list.push_back(patch);
}
if (!patch_name_list.empty()) {
_patch_name_lists[(*i)->property ("Name")->value()] = patch_name_list;
}
}
/* now traverse patches and hook up anything that used UsePatchNameList
* to the right patch list
*/
for (ChannelNameSets::iterator cns = _channel_name_sets.begin(); cns != _channel_name_sets.end(); ++cns) {
ChannelNameSet::PatchBanks pbs = cns->second->patch_banks();
PatchNameLists::iterator p;
for (ChannelNameSet::PatchBanks::iterator pb = pbs.begin(); pb != pbs.end(); ++pb) {
const std::string& pln = (*pb)->patch_list_name();
if (!pln.empty()) {
if ((p = _patch_name_lists.find (pln)) != _patch_name_lists.end()) {
if ((*pb)->set_patch_name_list (p->second)) {
return -1;
}
cns->second->use_patch_name_list (p->second);
} else {
error << string_compose ("Patch list name %1 was not found - patch file ignored", pln) << endmsg;
return -1;
}
}
}
}
return 0;
}
XMLNode&
MasterDeviceNames::get_state(void)
{
static XMLNode nothing("<nothing>");
return nothing;
}
MIDINameDocument::MIDINameDocument (const string& filename)
{
XMLTree document;
if (!document.read (filename)) {
throw failed_constructor ();
}
document.set_filename (filename);
set_state (document, *document.root());
}
int
MIDINameDocument::set_state (const XMLTree& tree, const XMLNode&)
{
// Author
boost::shared_ptr<XMLSharedNodeList> author = tree.find("//Author");
if (author->size() < 1) {
error << "No author information in MIDNAM file" << endmsg;
return -1;
}
if (author->front()->children().size() > 0) {
_author = author->front()->children().front()->content();
}
// MasterDeviceNames
boost::shared_ptr<XMLSharedNodeList> master_device_names_list = tree.find ("//MasterDeviceNames");
for (XMLSharedNodeList::iterator i = master_device_names_list->begin();
i != master_device_names_list->end();
++i) {
boost::shared_ptr<MasterDeviceNames> master_device_names(new MasterDeviceNames());
if (master_device_names->set_state(tree, *(*i))) {
return -1;
}
for (MasterDeviceNames::Models::const_iterator model = master_device_names->models().begin();
model != master_device_names->models().end();
++model) {
_master_device_names_list.insert(
std::pair<std::string, boost::shared_ptr<MasterDeviceNames> >
(*model, master_device_names));
_all_models.insert(*model);
}
}
return 0;
}
XMLNode&
MIDINameDocument::get_state(void)
{
static XMLNode nothing("<nothing>");
return nothing;
}
boost::shared_ptr<MasterDeviceNames>
MIDINameDocument::master_device_names(const std::string& model)
{
MasterDeviceNamesList::const_iterator m = _master_device_names_list.find(model);
if (m != _master_device_names_list.end()) {
return boost::shared_ptr<MasterDeviceNames>(m->second);
}
return boost::shared_ptr<MasterDeviceNames>();
}
const char* general_midi_program_names[128] = {
"Acoustic Grand Piano",
"Bright Acoustic Piano",
"Electric Grand Piano",
"Honky-tonk Piano",
"Rhodes Piano",
"Chorused Piano",
"Harpsichord",
"Clavinet",
"Celesta",
"Glockenspiel",
"Music Box",
"Vibraphone",
"Marimba",
"Xylophone",
"Tubular Bells",
"Dulcimer",
"Hammond Organ",
"Percussive Organ",
"Rock Organ",
"Church Organ",
"Reed Organ",
"Accordion",
"Harmonica",
"Tango Accordion",
"Acoustic Guitar (nylon)",
"Acoustic Guitar (steel)",
"Electric Guitar (jazz)",
"Electric Guitar (clean)",
"Electric Guitar (muted)",
"Overdriven Guitar",
"Distortion Guitar",
"Guitar Harmonics",
"Acoustic Bass",
"Electric Bass (finger)",
"Electric Bass (pick)",
"Fretless Bass",
"Slap Bass 1",
"Slap Bass 2",
"Synth Bass 1",
"Synth Bass 2",
"Violin",
"Viola",
"Cello",
"Contrabass",
"Tremolo Strings",
"Pizzicato Strings",
"Orchestral Harp",
"Timpani",
"String Ensemble 1",
"String Ensemble 2",
"SynthStrings 1",
"SynthStrings 2",
"Choir Aahs",
"Voice Oohs",
"Synth Voice",
"Orchestra Hit",
"Trumpet",
"Trombone",
"Tuba",
"Muted Trumpet",
"French Horn",
"Brass Section",
"Synth Brass 1",
"Synth Brass 2",
"Soprano Sax",
"Alto Sax",
"Tenor Sax",
"Baritone Sax",
"Oboe",
"English Horn",
"Bassoon",
"Clarinet",
"Piccolo",
"Flute",
"Recorder",
"Pan Flute",
"Bottle Blow",
"Shakuhachi",
"Whistle",
"Ocarina",
"Lead 1 (square)",
"Lead 2 (sawtooth)",
"Lead 3 (calliope lead)",
"Lead 4 (chiff lead)",
"Lead 5 (charang)",
"Lead 6 (voice)",
"Lead 7 (fifths)",
"Lead 8 (bass + lead)",
"Pad 1 (new age)",
"Pad 2 (warm)",
"Pad 3 (polysynth)",
"Pad 4 (choir)",
"Pad 5 (bowed)",
"Pad 6 (metallic)",
"Pad 7 (halo)",
"Pad 8 (sweep)",
"FX 1 (rain)",
"FX 2 (soundtrack)",
"FX 3 (crystal)",
"FX 4 (atmosphere)",
"FX 5 (brightness)",
"FX 6 (goblins)",
"FX 7 (echoes)",
"FX 8 (sci-fi)",
"Sitar",
"Banjo",
"Shamisen",
"Koto",
"Kalimba",
"Bagpipe",
"Fiddle",
"Shanai",
"Tinkle Bell",
"Agogo",
"Steel Drums",
"Woodblock",
"Taiko Drum",
"Melodic Tom",
"Synth Drum",
"Reverse Cymbal",
"Guitar Fret Noise",
"Breath Noise",
"Seashore",
"Bird Tweet",
"Telephone Ring",
"Helicopter",
"Applause",
"Gunshot",
};
} //namespace Name
} //namespace MIDI