sources = Split("""
fd_midiport.cc
fifomidi.cc
+event.cc
midi.cc
midichannel.cc
midifactory.cc
midimanager.cc
midiparser.cc
midiport.cc
+midnam_patch.cc
mmc.cc
mtc.cc
version.cc
--- /dev/null
+#include "midi++/event.h"
+
+namespace MIDI {
+
+#ifdef MIDI_EVENT_ALLOW_ALLOC
+Event::Event(double t, uint32_t s, uint8_t* b, bool owns_buffer)
+ : _time(t)
+ , _size(s)
+ , _buffer(b)
+ , _owns_buffer(owns_buffer)
+{
+ if (owns_buffer) {
+ _buffer = (uint8_t*)malloc(_size);
+ if (b) {
+ memcpy(_buffer, b, _size);
+ } else {
+ memset(_buffer, 0, _size);
+ }
+ }
+}
+
+Event::Event(const XMLNode& event)
+{
+ string name = event.name();
+
+ if (name == "ControlChange") {
+
+ } else if (name == "ProgramChange") {
+
+ }
+}
+
+Event::Event(const Event& copy, bool owns_buffer)
+ : _time(copy._time)
+ , _size(copy._size)
+ , _buffer(copy._buffer)
+ , _owns_buffer(owns_buffer)
+{
+ if (owns_buffer) {
+ _buffer = (uint8_t*)malloc(_size);
+ if (copy._buffer) {
+ memcpy(_buffer, copy._buffer, _size);
+ } else {
+ memset(_buffer, 0, _size);
+ }
+ }
+}
+
+Event::~Event() {
+ if (_owns_buffer) {
+ free(_buffer);
+ }
+}
+
+
+#endif // MIDI_EVENT_ALLOW_ALLOC
+
+std::string
+Event::to_string() const
+{
+ std::ostringstream result(std::ios::ate);
+ result << "MIDI::Event type:" << std::hex << "0x" << int(type()) << " buffer: ";
+
+ for(uint32_t i = 0; i < size(); ++i) {
+ result << " 0x" << int(_buffer[i]);
+ }
+ return result.str();
+}
+
+boost::shared_ptr<XMLNode>
+Event::to_xml() const
+{
+ XMLNode *result = 0;
+
+ switch (type()) {
+ case MIDI_CMD_CONTROL:
+ result = new XMLNode("ControlChange");
+ result->add_property("Channel", channel());
+ result->add_property("Control", cc_number());
+ result->add_property("Value", cc_value());
+ break;
+
+ case MIDI_CMD_PGM_CHANGE:
+ result = new XMLNode("ProgramChange");
+ result->add_property("Channel", channel());
+ result->add_property("number", pgm_number());
+ break;
+
+ default:
+ // The implementation is continued as needed
+ break;
+ }
+
+ return boost::shared_ptr<XMLNode>(result);
+}
+
+} // namespace MIDI
#include <midi++/types.h>
#include <midi++/events.h>
+#include <pbd/xml++.h>
/** If this is not defined, all methods of MidiEvent are RT safe
* but MidiEvent will never deep copy and (depending on the scenario)
*/
struct Event {
#ifdef MIDI_EVENT_ALLOW_ALLOC
- Event(double t=0, uint32_t s=0, uint8_t* b=NULL, bool owns_buffer=false)
- : _time(t)
- , _size(s)
- , _buffer(b)
- , _owns_buffer(owns_buffer)
- {
- if (owns_buffer) {
- _buffer = (uint8_t*)malloc(_size);
- if (b) {
- memcpy(_buffer, b, _size);
- } else {
- memset(_buffer, 0, _size);
- }
- }
- }
+ Event(double t=0, uint32_t s=0, uint8_t* b=NULL, bool owns_buffer=false);
/** Copy \a copy.
*
* is NOT REALTIME SAFE. Otherwise both events share a buffer and
* memory management semantics are the caller's problem.
*/
- Event(const Event& copy, bool owns_buffer)
- : _time(copy._time)
- , _size(copy._size)
- , _buffer(copy._buffer)
- , _owns_buffer(owns_buffer)
- {
- if (owns_buffer) {
- _buffer = (uint8_t*)malloc(_size);
- if (copy._buffer) {
- memcpy(_buffer, copy._buffer, _size);
- } else {
- memset(_buffer, 0, _size);
- }
- }
- }
+ Event(const Event& copy, bool owns_buffer);
- ~Event() {
- if (_owns_buffer) {
- free(_buffer);
- }
- }
+ /**
+ * see the MIDI XML specification: http://www.midi.org/dtds/MIDIEvents10.dtd
+ */
+ Event(const XMLNode &event);
+
+ ~Event();
inline const Event& operator=(const Event& copy) {
_time = copy._time;
_size = size;
}
+
#else
inline void set_buffer(uint8_t* buf) { _buffer = buf; }
inline bool is_sysex() const { return _buffer[0] == 0xF0 || _buffer[0] == 0xF7; }
inline const uint8_t* buffer() const { return _buffer; }
inline uint8_t*& buffer() { return _buffer; }
- inline std::string to_string() const {
- std::ostringstream result(std::ios::ate);
- result << "MIDI::Event type:" << std::hex << "0x" << int(type()) << " buffer: ";
-
- for(uint32_t i = 0; i < size(); ++i) {
- result << " 0x" << int(_buffer[i]);
- }
- return result.str();
- }
+
+ /**
+ * mainly used for debugging purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * see the MIDI XML specification: http://www.midi.org/dtds/MIDIEvents10.dtd
+ */
+ boost::shared_ptr<XMLNode> to_xml() const;
private:
double _time; /**< Sample index (or beat time) at which event is valid */
--- /dev/null
+#ifndef MIDNAM_PATCH_H_
+#define MIDNAM_PATCH_H_
+
+#include "pbd/stateful.h"
+#include "midi++/event.h"
+#include "pbd/xml++.h"
+
+#include <string>
+#include <list>
+#include <set>
+
+namespace MIDI
+{
+
+namespace Name
+{
+
+class Patch : public PBD::Stateful
+{
+public:
+ typedef std::list<MIDI::Event> PatchMidiCommands;
+
+ Patch() {};
+ Patch(string a_number, string a_name) : _number(a_number), _name(a_name) {};
+ ~Patch() {};
+
+ const string& name() const { return _name; }
+ void set_name(const string a_name) { _name = a_name; }
+
+ const string& number() const { return _number; }
+ void set_number(const string a_number) { _number = a_number; }
+
+ const PatchMidiCommands& patch_midi_commands() const { return _patch_midi_commands; }
+
+ XMLNode& get_state (void);
+ int set_state (const XMLNode& a_node);
+
+private:
+ string _number;
+ string _name;
+ PatchMidiCommands _patch_midi_commands;
+};
+
+class PatchBank : public PBD::Stateful
+{
+public:
+ typedef std::list<Patch> PatchNameList;
+
+ PatchBank() {};
+ virtual ~PatchBank() {};
+ PatchBank(string a_name) : _name(a_name) {};
+
+ const string& name() const { return _name; }
+ void set_name(const string a_name) { _name = a_name; }
+
+ const PatchNameList& patch_name_list() const { return _patch_name_list; }
+
+ XMLNode& get_state (void);
+ int set_state (const XMLNode& a_node);
+
+private:
+ string _name;
+ PatchNameList _patch_name_list;
+};
+
+class ChannelNameSet : public PBD::Stateful
+{
+public:
+ typedef std::set<uint8_t> AvailableForChannels;
+ typedef std::list<PatchBank> PatchBanks;
+
+ ChannelNameSet() {};
+ virtual ~ChannelNameSet() {};
+ ChannelNameSet(string a_name) : _name(a_name) {};
+
+ const string& name() const { return _name; }
+ void set_name(const string a_name) { _name = a_name; }
+
+ const AvailableForChannels& available_for_channels() const { return _available_for_channels; }
+ const PatchBanks& patch_banks() const { return _patch_banks; }
+
+ XMLNode& get_state (void);
+ int set_state (const XMLNode& a_node);
+
+private:
+ string _name;
+ AvailableForChannels _available_for_channels;
+ PatchBanks _patch_banks;
+};
+
+
+}
+
+}
+
+#endif /*MIDNAM_PATCH_H_*/
--- /dev/null
+#include "midi++/midnam_patch.h"
+#include <algorithm>
+
+namespace MIDI
+{
+
+namespace Name
+{
+
+XMLNode&
+Patch::get_state (void)
+{
+ XMLNode* node = new XMLNode("Patch");
+ node->add_property("Number", _number);
+ node->add_property("Name", _name);
+ 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(*(event->to_xml()));
+ }
+
+ return *node;
+}
+
+int
+Patch::set_state (const XMLNode& node)
+{
+ assert(node.name() == "Patch");
+ _number = node.property("Number")->value();
+ _name = node.property("Name")->value();
+ XMLNode* commands = node.child("PatchMIDICommands");
+ assert(commands);
+ const XMLNodeList events = commands->children();
+ for (XMLNodeList::const_iterator i = events.begin(); i != events.end(); ++i) {
+ _patch_midi_commands.push_back(*(new Event(*(*i))));
+ }
+
+ return 0;
+}
+
+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 XMLNode& node)
+{
+ assert(node.name() == "PatchBank");
+ _name = node.property("Name")->value();
+ XMLNode* patch_name_list = node.child("PatchNameList");
+ assert(patch_name_list);
+ const XMLNodeList patches = patch_name_list->children();
+ for (XMLNodeList::const_iterator i = patches.begin(); i != patches.end(); ++i) {
+ Patch patch;
+ patch.set_state(*(*i));
+ _patch_name_list.push_back(patch);
+ }
+
+ return 0;
+}
+
+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 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 =
+ node->find("//AvailableChannel[@Available = 'true']/@Channel");
+ for(XMLSharedNodeList::const_iterator i = channels->begin();
+ i != channels->end();
+ ++i) {
+ _available_for_channels.insert(atoi((*i)->attribute_value().c_str()));
+ }
+ }
+
+ if (node->name() == "PatchBank") {
+ PatchBank bank;
+ bank.set_state(*node);
+ _patch_banks.push_back(bank);
+ }
+ }
+
+ return 0;
+}
+
+} //namespace Name
+
+} //namespace MIDI
+
string _filename;
XMLNode *_root;
int _compression;
-
+ bool read_internal(bool validate);
+
public:
XMLTree();
- XMLTree(const string &fn);
+ XMLTree(const string &fn, bool validate = false);
XMLTree(const XMLTree *);
~XMLTree();
int compression() const { return _compression; };
int set_compression(int);
- bool read();
- bool read(const string &fn) { set_filename(fn); return read(); };
+ bool read() { return read_internal(false); };
+ bool read(const string &fn) { set_filename(fn); return read_internal(false); };
+ bool read_and_validate() { return read_internal(true); };
+ bool read_and_validate(const string &fn) { set_filename(fn); return read_internal(true); };
bool read_buffer(const string &);
bool write() const;
XMLPropertyMap _propmap;
public:
- XMLNode(const string &);
- XMLNode(const string &, const string &);
- XMLNode(const XMLNode&);
+ XMLNode(const string& name);
+ XMLNode(const string& name, const string& content);
+ XMLNode(const XMLNode& other);
~XMLNode();
const string name() const { return _name; };
{ return ((XMLNode *) this)->property(n); };
const XMLProperty *property(const std::string& ns) const
{ return ((XMLNode *) this)->property(ns); };
- XMLProperty *add_property(const char *, const string &);
- XMLProperty *add_property(const char *, const char * = "");
+ XMLProperty *add_property(const char *name, const string& value);
+ XMLProperty *add_property(const char *name, const char *value = "");
+ XMLProperty *add_property(const char *name, const long value);
void remove_property(const string &);
test: xpath
LD_LIBRARY_PATH=..:../../sigc++2:../../glibmm2 ./xpath
- LD_LIBRARY_PATH=..:../../sigc++2:../../glibmm2 gprof ./xpath
+ LD_LIBRARY_PATH=..:../../sigc++2:../../glibmm2 gprof ./xpath > gprof.out
xpath: xpath.cc
- gcc -o $@ -g -pg -I.. `xml2-config --libs --cflags` -L.. -L../../sigc++2 -L../../glibmm2 -lstdc++ -lpbd -lglibmm2 -lsigc++2 $<
\ No newline at end of file
+ gcc -o $@ -g -pg -I.. `xml2-config --libs --cflags` -L.. -L../../sigc++2 -L../../glibmm2 -lstdc++ -lpbd -lglibmm2 -lsigc++2 $<
cout << "\t found attribute node: " << node->name()
<< " value: " << node->attribute_value() << endl;
}
+
+ cout << endl << endl << "Test 6: ProtoolsPatchFile.midnam: Find available channels on 'Name Set 1'" << endl;
+ result = doc3.root()->find(
+ "//ChannelNameSet[@Name = 'Name Set 1']//AvailableChannel[@Available = 'true']/@Channel");
+
+ assert(result->size() == 15);
+ for(XMLSharedNodeList::const_iterator i = result->begin(); i != result->end(); ++i) {
+ boost::shared_ptr<XMLNode> node = (*i);
+ cout << "\t found available Channel: " << node->name()
+ << " value: " << node->attribute_value() << endl;
+ }
+
}
{
}
-XMLTree::XMLTree(const string &fn)
+XMLTree::XMLTree(const string &fn, bool validate)
: _filename(fn),
_root(0),
_compression(0)
{
- read();
+ read_internal(validate);
}
XMLTree::XMLTree(const XMLTree * from)
XMLTree::set_compression(int c)
{
if (c > 9) {
- c = 9;
+ c = 9;
} else if (c < 0) {
- c = 0;
+ c = 0;
}
_compression = c;
}
bool
-XMLTree::read(void)
+XMLTree::read_internal(bool validate)
{
- xmlDocPtr doc;
-
+ //shouldnt be used anywhere ATM, remove if so!
+ assert(!validate);
if (_root) {
delete _root;
_root = 0;
}
+ xmlParserCtxtPtr ctxt; /* the parser context */
+ xmlDocPtr doc; /* the resulting document tree */
+
xmlKeepBlanksDefault(0);
+ /* parse the file, activating the DTD validation option */
+ if(validate) {
+ /* create a parser context */
+ ctxt = xmlNewParserCtxt();
+ if (ctxt == NULL) {
+ return false;
+ }
+ doc = xmlCtxtReadFile(ctxt, _filename.c_str(), NULL, XML_PARSE_DTDVALID);
+ } else {
+ doc = xmlParseFile(_filename.c_str());
+ }
- doc = xmlParseFile(_filename.c_str());
- if (!doc) {
- return false;
+ /* check if parsing suceeded */
+ if (doc == NULL) {
+ if(validate) {
+ xmlFreeParserCtxt(ctxt);
+ }
+ return false;
+ } else {
+ /* check if validation suceeded */
+ if (validate && ctxt->valid == 0) {
+ xmlFreeParserCtxt(ctxt);
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+ throw XMLException("Failed to validate document " + _filename);
+ }
}
_root = readnode(xmlDocGetRootElement(doc));
+
+ /* free up the parser context */
+ if(validate) {
+ xmlFreeParserCtxt(ctxt);
+ }
xmlFreeDoc(doc);
+ xmlCleanupParser();
return true;
}
void
XMLTree::debug(FILE* out) const
{
- xmlDocPtr doc;
- XMLNodeList children;
+ xmlDocPtr doc;
+ XMLNodeList children;
- xmlKeepBlanksDefault(0);
- doc = xmlNewDoc((xmlChar *) XML_VERSION);
- xmlSetDocCompressMode(doc, _compression);
- writenode(doc, _root, doc->children, 1);
- xmlDebugDumpDocument (out, doc);
- xmlFreeDoc(doc);
+ xmlKeepBlanksDefault(0);
+ doc = xmlNewDoc((xmlChar *) XML_VERSION);
+ xmlSetDocCompressMode(doc, _compression);
+ writenode(doc, _root, doc->children, 1);
+ xmlDebugDumpDocument (out, doc);
+ xmlFreeDoc(doc);
}
const string &
for (curchild = _children.begin(); curchild != _children.end(); ++curchild) {
delete *curchild;
}
-
+
for (curprop = _proplist.begin(); curprop != _proplist.end(); ++curprop) {
delete *curprop;
}
} else {
_is_content = true;
}
-
+
_content = c;
return _content;
if (name == 0) {
return 0;
}
-
+
for (cur = _children.begin(); cur != _children.end(); ++cur) {
if ((*cur)->name() == name) {
return *cur;
}
}
-
+
return 0;
}
if (n.empty()) {
return _children;
}
-
+
retval.erase(retval.begin(), retval.end());
for (cur = _children.begin(); cur != _children.end(); ++cur) {
retval.insert(retval.end(), *cur);
}
}
-
+
return retval;
}
return add_property(n, vs);
}
+XMLProperty *
+XMLNode::add_property(const char *name, const long value)
+{
+ static char str[1024];
+ snprintf(str, 1024, "%ld", value);
+ return add_property(name, str);
+}
+
void
XMLNode::remove_property(const string & n)
{
} else {
node = xmlNewChild(p, 0, (xmlChar *) n->name().c_str(), 0);
}
-
+
if (n->is_content()) {
node->type = XML_TEXT_NODE;
xmlNodeSetContentLen(node, (const xmlChar *) n->content().c_str(), n->content().length());
for (curprop = props.begin(); curprop != props.end(); ++curprop) {
xmlSetProp(node, (xmlChar *) (*curprop)->name().c_str(), (xmlChar *) (*curprop)->value().c_str());
}
-
+
children = n->children();
for (curchild = children.begin(); curchild != children.end(); ++curchild) {
writenode(doc, *curchild, node);