Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' into experimental-meisolesmes

Conflicts:
	python/pymei/Modules/layout.py
	python/pymei/Modules/shared.py
  • Loading branch information...
commit 3144ca8eb9698a2bd91b3d425a9fcca3fdd8a2db 2 parents f9986e2 + c43993a
Alastair Porter alastair authored
6 .gitignore
View
@@ -19,4 +19,8 @@ build/
/tools/mei-customization.xml
/tools/mei-source.xml
-/tools/mei-all.xml
+/tools/mei-all.xml
+python/build
+*.so
+python/dist
+pymei.egg-info
2  python/pymei/Modules/layout.py
View
@@ -15,7 +15,7 @@
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE ANDpython/pymei/Modules/layout.py
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
11 python/pymei/__init__.py
View
@@ -19,4 +19,13 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-from _libmei import *
+from _libmei import *
+import types
+
+def read(filename):
+ """ Extra wrapper to make sure we can handle unicode filenames. """
+ if isinstance(filename, types.UnicodeType):
+ filename = str(filename)
+ doc = XmlImport.documentFromFile(filename)
+ return doc
+XmlImport.read = staticmethod(read)
52 python/src/_libmei.cpp
View
@@ -39,6 +39,7 @@
#include <vector>
#include <string>
#include <exception>
+#include <sstream>
using namespace boost::python;
using namespace std;
@@ -56,27 +57,59 @@ typedef vector<MeiNamespace*> MeiNamespaceList;
bool MeiElement_EqualWrap(const MeiElement* x, const MeiElement* y) { return x == y; }
bool MeiElement_NEqualWrap(const MeiElement* x, const MeiElement* y) { return x != y; }
+string MeiElement_Print(MeiElement* x) { return "<MeiElement " + x->getName() + ":" + x->getId() + ">"; }
bool MeiDocument_EqualWrap(const MeiDocument* x, const MeiDocument* y) { return x == y; }
bool MeiDocument_NEqualWrap(const MeiDocument* x, const MeiDocument* y) { return x != y; }
+string MeiDocument_Print(MeiDocument *x) { return "<MeiDocument " + x->getVersion() + ">"; }
bool MeiAttribute_EqualWrap(const MeiAttribute* x, const MeiAttribute* y) { return x == y; }
bool MeiAttribute_NEqualWrap(const MeiAttribute* x, const MeiAttribute* y) { return x != y; }
+string MeiAttribute_Print(MeiAttribute* x) { return "<MeiAttribute " + x->getName() + ":" + x->getValue() + ">"; }
bool MeiNamespace_EqualWrap(const MeiNamespace* x, const MeiNamespace* y) { return x == y; }
bool MeiNamespace_NEqualWrap(const MeiNamespace* x, const MeiNamespace* y) { return x != y; }
+string MeiNamespace_Print(MeiNamespace* x) { return "<MeiNamespace " + x->getPrefix() + ":" + x->getHref() + ">"; }
bool MeiElementList_EqualWrap(const MeiElementList x, const MeiElementList y) { return x == y; }
bool MeiElementList_NEqualWrap(const MeiElementList x, const MeiElementList y) { return x != y; }
bool MeiElementList_NonZero(const MeiElementList x) { return !x.empty(); }
+string MeiElementList_Print(MeiElementList x) {
+ stringstream res;
+ res << "[ ";
+ for(vector<MeiElement*>::iterator iter = x.begin(); iter != x.end(); ++iter) {
+ res << "<MeiElement " << (*iter)->getName() << ":" << (*iter)->getId() << "> ";
+ }
+ res << "]";
+ return res.str();
+}
bool MeiAttributeList_EqualWrap(const MeiAttributeList x, const MeiAttributeList y) { return x == y; }
bool MeiAttributeList_NEqualWrap(const MeiAttributeList x, const MeiAttributeList y) { return x != y; }
bool MeiAttributeList_NonZero(const MeiAttributeList x) { return !x.empty(); }
+string MeiAttributeList_Print(MeiAttributeList x) {
+ stringstream res;
+ res << "[ ";
+ for(vector<MeiAttribute*>::iterator iter = x.begin(); iter != x.end(); ++iter) {
+ res << "<MeiAttribute " << (*iter)->getName() << ":" << (*iter)->getValue() << "> ";
+ }
+ res << "]";
+ return res.str();
+}
bool MeiNamespaceList_EqualWrap(const MeiNamespaceList x, const MeiNamespaceList y) { return x == y; }
bool MeiNamespaceList_NEqualWrap(const MeiNamespaceList x, const MeiNamespaceList y) { return x != y; }
bool MeiNamespaceList_NonZero(const MeiNamespaceList x) { return !x.empty(); }
+string MeiNamespaceList_Print(MeiNamespaceList x) {
+ stringstream res;
+ res << "[ ";
+ for(vector<MeiNamespace*>::iterator iter = x.begin(); iter != x.end(); ++iter) {
+ res << "<MeiNamespace " << (*iter)->getPrefix() << ":" << (*iter)->getHref() << "> ";
+ }
+ res << "]";
+ return res.str();
+}
+
BOOST_PYTHON_MODULE(_libmei) {
docstring_options local_docstring_options(true, true, false);
@@ -87,6 +120,8 @@ BOOST_PYTHON_MODULE(_libmei) {
.def("__ne__", &MeiElementList_NEqualWrap)
.def("__iter__", boost::python::iterator<MeiElementList>())
.def("__nonzero__", &MeiElementList_NonZero)
+ .def("__str__", &MeiElementList_Print)
+ .def("__repr__", &MeiElementList_Print)
;
class_<MeiAttributeList>("MeiAttributeList")
@@ -95,6 +130,8 @@ BOOST_PYTHON_MODULE(_libmei) {
.def("__ne__", &MeiAttributeList_NEqualWrap)
.def("__iter__", boost::python::iterator<MeiAttributeList>())
.def("__nonzero__", &MeiAttributeList_NonZero)
+ .def("__str__", &MeiAttributeList_Print)
+ .def("__repr__", &MeiAttributeList_Print)
;
class_<MeiNamespaceList>("MeiNamespaceList")
@@ -103,11 +140,15 @@ BOOST_PYTHON_MODULE(_libmei) {
.def("__ne__", &MeiNamespaceList_NEqualWrap)
.def("__iter__", boost::python::iterator<MeiNamespaceList>())
.def("__nonzero__", &MeiNamespaceList_NonZero)
+ .def("__str__", &MeiNamespaceList_Print)
+ .def("__repr__", &MeiNamespaceList_Print)
;
class_<MeiNamespace, MeiNamespace*>("MeiNamespace", init<string, string>())
.def("__eq__", &MeiNamespace_EqualWrap)
.def("__ne__", &MeiNamespace_NEqualWrap)
+ .def("__str__", &MeiNamespace_Print)
+ .def("__repr__", &MeiNamespace_Print)
.def("getHref", &MeiNamespace::getHref)
.add_property("href", &MeiNamespace::getHref)
.def("getPrefix", &MeiNamespace::getPrefix)
@@ -145,9 +186,13 @@ BOOST_PYTHON_MODULE(_libmei) {
class_<MeiDocument, MeiDocument*>("MeiDocument", init<optional<string> >())
.def("__eq__", &MeiDocument_EqualWrap)
.def("__ne__", &MeiDocument_NEqualWrap)
+ .def("__str__", &MeiDocument_Print)
+ .def("__repr__", &MeiDocument_Print)
.def("hasNamespace", &MeiDocument::hasNamespace)
.def("getNamespace", &MeiDocument::getNamespace, return_value_policy<reference_existing_object>())
.def("getNamespaces", &MeiDocument::getNamespaces)
+ .add_property("namespaces", &MeiDocument::getNamespaces)
+
.def("addNamespace", &MeiDocument::addNamespace)
.def("getVersion", &MeiDocument::getVersion)
.add_property("version", &MeiDocument::getVersion)
@@ -174,6 +219,9 @@ BOOST_PYTHON_MODULE(_libmei) {
// .def(init<const MeiElement&>())
.def("__eq__", &MeiElement_EqualWrap)
.def("__ne__", &MeiElement_NEqualWrap)
+ .def("__str__", &MeiElement_Print)
+ .def("__repr__", &MeiElement_Print)
+
.def("getId", &MeiElement::getId)
.def("setId", &MeiElement::setId)
.add_property("id", &MeiElement::getId, &MeiElement::setId)
@@ -243,8 +291,6 @@ BOOST_PYTHON_MODULE(_libmei) {
.def("getPositionInDocument", &MeiElement::getPositionInDocument)
.def("lookBack", &MeiElement::lookBack, return_value_policy<reference_existing_object>())
.def("flatten", &MeiElement::flatten)
- .def("print", printAll)
- .def("print", printLvl)
.def("updateDocument", &MeiElement::updateDocument)
;
@@ -252,6 +298,8 @@ BOOST_PYTHON_MODULE(_libmei) {
.def(init<MeiNamespace*, string, string>())
.def("__eq__", &MeiAttribute_EqualWrap)
.def("__ne__", &MeiAttribute_NEqualWrap)
+ .def("__str__", &MeiAttribute_Print)
+ .def("__repr__", &MeiAttribute_Print)
.def("getName", &MeiAttribute::getName)
.add_property("name", &MeiAttribute::getName)
30 python/src/_libmei_exceptions.cpp
View
@@ -41,6 +41,8 @@ object pyChildNotFoundExceptionType;
object pyNoVersionFoundExceptionType;
object pyElementNotRegisteredExceptionType;
object pyDocumentRootNotSetExceptionType;
+object pyFileWriteFailureExceptionType;
+object pyMalformedFileExceptionType;
void MeiExceptionTranslate(mei::MeiException const& e) {
assert(pyMeiExceptionType != NULL);
@@ -98,6 +100,20 @@ void DocumentRootNotSetExceptionTranslate(mei::DocumentRootNotSetException const
throw_error_already_set();
}
+void FileWriteFailureExceptionTranslate(mei::FileWriteFailureException const& e) {
+ assert(pyFileWriteFailureExceptionType != NULL);
+ object pythonExceptionInstance(e);
+ PyErr_SetObject(pyFileWriteFailureExceptionType.ptr(), pythonExceptionInstance.ptr());
+ throw_error_already_set();
+}
+
+void MalformedFileExceptionTranslate(mei::MalformedFileException const& e) {
+ assert(pyMalformedFileExceptionType != NULL);
+ object pythonExceptionInstance(e);
+ PyErr_SetObject(pyMalformedFileExceptionType.ptr(), pythonExceptionInstance.ptr());
+ throw_error_already_set();
+}
+
BOOST_PYTHON_MODULE(_libmei_exceptions) {
object meiexception = class_<mei::MeiException>("MeiException", init<string>())
@@ -156,4 +172,18 @@ BOOST_PYTHON_MODULE(_libmei_exceptions) {
pyDocumentRootNotSetExceptionType = noroot;
register_exception_translator<mei::DocumentRootNotSetException>(&DocumentRootNotSetExceptionTranslate);
+ object filewrite = class_<mei::FileWriteFailureException>("FileWriteFailureException", init<string>())
+ .def("what", &mei::FileWriteFailureException::what)
+ .add_property("message", &mei::FileWriteFailureException::what)
+ ;
+ pyFileWriteFailureExceptionType = filewrite;
+ register_exception_translator<mei::FileWriteFailureException>(&FileWriteFailureExceptionTranslate);
+
+ object malformed = class_<mei::MalformedFileException>("MalformedFileException", init<string>())
+ .def("what", &mei::MalformedFileException::what)
+ .add_property("message", &mei::MalformedFileException::what)
+ ;
+ pyMalformedFileExceptionType = malformed;
+ register_exception_translator<mei::MalformedFileException>(&MalformedFileExceptionTranslate);
+
}
111 python/test/testdocs/malformed.mei
View
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?oxygen SCHSchema="http://music-encoding.org/mei/schemata/2010-05/rng/mei-all.rng"?>
+<?oxygen RNGSchema="http://music-encoding.org/mei/schemata/2010-05/rng/mei-all.rng"?>
+<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="2012">
+ <meiHead>
+ <fileDesc>
+ <titleStmt>
+ <title>Lute Tablature</title>
+ <respStmt>
+ <name>Campion</name>
+ </respStmt>
+ </titleStmt>
+ <pubStmt/>
+ <sourceDesc>
+ <source>
+ <titleStmt>
+ <title/>
+ <respStmt>
+ <name/>
+ </respStmt>
+ </titleStmt>
+ <pubStmt/>
+ </source>
+ </sourceDesc>
+ </meiHead>
+ <music>
+ <body>
+ <!-- Encoding 1: above-the-staff duration values not explicitly encoded
+ They can be implied from the @dur attributes on chord/note. -->
+ <mdiv>
+ <score>
+ <scoreDef meter.count="2" meter.unit="2" meter.sym="cut" key.sig="0">
+ <staffGrp>
+ <!-- Tab "staff" has same number of lines as tokens in tab.strings -->
+ <!-- String pitches (written) given from highest to lowest -->
+ <staffDef n="1" lines="6" tab.strings="e5 b4 g4 d4 a3 e3"/>
+ </staffGrp>
+ </scoreDef>
+ <section>
+ <measure n="1">
+ <staff>
+ <layer>
+ <chord dur="2">
+ <!-- extend tab.fret notation to include non-numerical values, such as 'a'? -->
+ <note tab.fret="1" tab.string="6"/>
+ <!-- more notes -->
+ </chord>
+ <chord dur="4">
+ <!-- notes -->
+ </chord>
+ <!-- Ambiguous rhythmic representation, i.e., missing @dur on chord, is OK in MEI -->
+ <chord>
+ <!-- notes -->
+ </chord>
+ </layer>
+ </staff>
+ </measure>
+ <measure n="2"/>
+ <measure n="3"/>
+ <!-- Extend list of values for @left/@right to include value that indicates dots in all spaces? -->
+ <measure n="4" right="rptboth"/>
+ <measure n="5" left="rptboth"/>
+ </section>
+ </score>
+ </mdiv>
+
+ <!-- Encoding 2: above-the-staff duration values explicitly encoded
+ This is probably bad practice as it puts stuff in the model (the MEI) that ought to be in the view. -->
+ <mdiv>
+ <score>
+ <scoreDef meter.count="2" meter.unit="2" meter.sym="cut" key.sig="0">
+ <staffGrp>
+ <!-- A single-line staff where the line is invisible, all notes placed 'on the line' -->
+ <staffDef n="1" lines="1" lines.visible="false" ontheline="true"/>
+ <staffDef n="2" lines="6" tab.strings="e5 b4 g4 d4 a3 e3"/>
+ </staffGrp>
+ </scoreDef>
+ <section>
+ <measure n="1">
+ <staff n="1">
+ <layer>
+ <note dur="2"/>
+ <note dur="4"/>
+ <space/>
+ </layer>
+ </staff>
+ <staff n="2">
+ <layer>
+ <chord dur="2">
+ <note tab.fret="1" tab.string="6"/>
+ <!-- notes -->
+ </chord>
+ <chord dur="4">
+ <!-- notes -->
+ </chord>
+ <chord>
+ <!-- notes -->
+ </chord>
+ </layer>
+ </staff>
+ </measure>
+ <measure n="2"/>
+ <measure n="3"/>
+ <measure n="4" right="rptboth"/>
+ <measure n="5" left="rptboth"/>
+ </section>
+ </score>
+ </mdiv>
+ </body>
+ </music>
+</mei>
11 python/test/xmlexport_test.py
View
@@ -5,7 +5,7 @@
import shutil
import pymei
from pymei import MeiElement, MeiAttribute, MeiElementList, MeiDocument, MeiNamespace, XmlImport, XmlExport
-from pymei.exceptions import DocumentRootNotSetException
+from pymei.exceptions import DocumentRootNotSetException, FileWriteFailureException
class XmlExportTest(unittest.TestCase):
@@ -37,6 +37,15 @@ def test_documentrootnotset(self):
with self.assertRaises(DocumentRootNotSetException) as cm:
ret = XmlExport.meiDocumentToText(doc)
self.assertTrue(isinstance(cm.exception, DocumentRootNotSetException))
+
+ def test_documentwritefailure(self):
+ doc = MeiDocument()
+ root = MeiElement("mei")
+ root.id = "myid"
+ doc.root = root
+ with self.assertRaises(FileWriteFailureException) as cm:
+ ret = XmlExport.meiDocumentToFile(doc, "C:/StupidPath")
+ self.assertTrue(isinstance(cm.exception, FileWriteFailureException))
def test_exportvalueandtail(self):
doc = MeiDocument()
24 python/test/xmlimport_test.py
View
@@ -3,7 +3,7 @@
import os
import pymei
from pymei import MeiElement, MeiAttribute, MeiElementList, MeiDocument, XmlImport
-from pymei.exceptions import VersionMismatchException, NoVersionFoundException
+from pymei.exceptions import VersionMismatchException, NoVersionFoundException, MalformedFileException
class XmlImportTest(unittest.TestCase):
@@ -39,6 +39,22 @@ def test_readfile(self):
el = doc.getElementById("d1e41")
self.assertEqual("c", el.getAttribute("pname").value)
self.assertEqual("4", el.getAttribute("oct").value)
+
+ def test_readmethod_string(self):
+ fn = os.path.join("test", "testdocs", "beethoven.mei")
+ doc = XmlImport.read(fn)
+ self.assertNotEqual(None, doc)
+ el = doc.getElementById("d1e41")
+ self.assertEqual("c", el.getAttribute("pname").value)
+ self.assertEqual("4", el.getAttribute("oct").value)
+
+ def test_readmethod_unicode(self):
+ fn = unicode(os.path.join("test", "testdocs", "beethoven.mei"))
+ doc = XmlImport.read(fn)
+ self.assertNotEqual(None, doc)
+ el = doc.getElementById("d1e41")
+ self.assertEqual("c", el.getAttribute("pname").value)
+ self.assertEqual("4", el.getAttribute("oct").value)
def test_readlargefile(self):
doc = XmlImport.documentFromFile(os.path.join("test", "testdocs", "beethoven_no5.mei"))
@@ -54,6 +70,12 @@ def test_noversionexception(self):
XmlImport.documentFromFile(os.path.join("test", "testdocs", "noversion.mei"))
self.assertTrue(isinstance(cm.exception, NoVersionFoundException))
+ def test_malformedexception(self):
+ with self.assertRaises(MalformedFileException) as cm:
+ XmlImport.documentFromFile(os.path.join("test", "testdocs", "malformed.mei"))
+ self.assertTrue(isinstance(cm.exception, MalformedFileException))
+
+
def suite():
test_suite = unittest.makeSuite(XmlImportTest, 'test')
return test_suite
14 src/exceptions.h
View
@@ -80,6 +80,20 @@ class MEI_EXPORT DocumentRootNotSetException : public MeiException {
~DocumentRootNotSetException() throw () {}
};
+class MEI_EXPORT FileWriteFailureException : public MeiException {
+public:
+ explicit FileWriteFailureException(const std::string &what) :
+ MeiException("There was an error writing the file " + what + ".") {}
+ ~FileWriteFailureException() throw () {}
+};
+
+class MEI_EXPORT MalformedFileException : public MeiException {
+public:
+ explicit MalformedFileException(const std::string &what) :
+ MeiException("The file " + what + " is malformed.") {}
+ ~MalformedFileException() throw () {}
+};
+
class MEI_EXPORT FooBarException : public MeiException {
public:
explicit FooBarException(const std::string &what) : MeiException("blahblah") {}
11 src/export/xmlexport.cpp
View
@@ -18,6 +18,7 @@
#include "meidocument.h"
#include "meielement.h"
#include "shared.h"
+#include "exceptions.h"
using std::string;
using std::vector;
@@ -60,11 +61,13 @@ string XmlExport::meiDocumentToText(mei::MeiDocument *doc) {
}
-bool XmlExportImpl::meiDocumentToFile(string filename) {
+bool XmlExportImpl::meiDocumentToFile(string filename) throw(FileWriteFailureException) {
xmlKeepBlanksDefault(0);
- xmlSaveFormatFileEnc(filename.c_str(), xmlDocOutput, "UTF-8", 1);
-
- return true;
+ if (xmlSaveFormatFileEnc(filename.c_str(), xmlDocOutput, "UTF-8", 1) == -1) {
+ throw FileWriteFailureException(filename);
+ } else {
+ return true;
+ }
}
string XmlExportImpl::meiDocumentToText() {
2  src/export/xmlexport_impl.h
View
@@ -44,7 +44,7 @@ namespace mei {
xmlNode* meiElementToXmlNode(MeiElement *el);
void outputToFile(const char* filename);
- bool meiDocumentToFile(std::string filename);
+ bool meiDocumentToFile(std::string filename) throw(FileWriteFailureException);
std::string meiDocumentToText();
MeiDocument* meiDocument;
15 src/import/xmlimport.cpp
View
@@ -15,6 +15,8 @@
#include "xmlimport.h"
#include "meidocument.h"
+#include <iostream>
+
using std::string;
using std::vector;
@@ -31,7 +33,7 @@ XmlImport::~XmlImport() {
delete impl;
}
-MeiDocument* XmlImport::documentFromFile(const char *filename) {
+MeiDocument* XmlImport::documentFromFile(string filename) {
XmlImport *import = new XmlImport();
MeiDocument *d = import->impl->documentFromFile(filename);
delete import;
@@ -52,9 +54,16 @@ XmlImportImpl::XmlImportImpl() {
rootMeiElement = NULL;
}
-MeiDocument* XmlImportImpl::documentFromFile(const char *filename) {
+MeiDocument* XmlImportImpl::documentFromFile(string filename) {
xmlDoc *doc = NULL;
- doc = xmlReadFile(filename, NULL, 0);
+ /* XML_PARSE_NOERROR will simply suppress the libxml error messages on malformed XML,
+ it won't actually stop it from parsing. */
+ doc = xmlReadFile(filename.c_str(), NULL, XML_PARSE_NOERROR);
+
+ if (doc == NULL) {
+ throw MalformedFileException(filename);
+ }
+
this->xmlMeiDocument = doc;
this->rootXmlNode = xmlDocGetRootElement(this->xmlMeiDocument);
2  src/import/xmlimport.h
View
@@ -38,7 +38,7 @@ class XmlImport {
/** public interfaces for importing. Each of these will convert their input
* into an xmlNode for processing by the _MeiXmlStruct class.
*/
- static MeiDocument* documentFromFile(const char* filename);
+ static MeiDocument* documentFromFile(std::string filename);
static MeiDocument* documentFromText(std::string text);
private:
XmlImportImpl *impl;
2  src/import/xmlimport_impl.h
View
@@ -37,7 +37,7 @@ namespace mei {
/** public interfaces for importing. Each of these will convert their input
* into an xmlNode for processing by the _MeiXmlStruct class.
*/
- MeiDocument* documentFromFile(const char* filename);
+ MeiDocument* documentFromFile(std::string filename);
MeiDocument* documentFromText(std::string text);
XmlImportImpl();
6 src/meidocument.cpp
View
@@ -126,9 +126,9 @@ MeiElement* mei::MeiDocument::getElementById(string id) {
vector<MeiElement*> mei::MeiDocument::getElementsByName(string name) {
vector<MeiElement*> ret;
- for (map<string, MeiElement*>::iterator iter = idMap.begin(); iter != idMap.end(); ++iter) {
- if ((*iter).second->getName() == name) {
- ret.push_back((*iter).second);
+ for (vector<MeiElement*>::iterator iter = flattenedDoc.begin(); iter != flattenedDoc.end(); ++iter) {
+ if ((*iter)->getName() == name) {
+ ret.push_back((*iter));
}
}
return ret;
111 test/malformed.mei
View
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?oxygen SCHSchema="http://music-encoding.org/mei/schemata/2010-05/rng/mei-all.rng"?>
+<?oxygen RNGSchema="http://music-encoding.org/mei/schemata/2010-05/rng/mei-all.rng"?>
+<mei xmlns="http://www.music-encoding.org/ns/mei" meiversion="2012">
+ <meiHead>
+ <fileDesc>
+ <titleStmt>
+ <title>Lute Tablature</title>
+ <respStmt>
+ <name>Campion</name>
+ </respStmt>
+ </titleStmt>
+ <pubStmt/>
+ <sourceDesc>
+ <source>
+ <titleStmt>
+ <title/>
+ <respStmt>
+ <name/>
+ </respStmt>
+ </titleStmt>
+ <pubStmt/>
+ </source>
+ </sourceDesc>
+ </meiHead>
+ <music>
+ <body>
+ <!-- Encoding 1: above-the-staff duration values not explicitly encoded
+ They can be implied from the @dur attributes on chord/note. -->
+ <mdiv>
+ <score>
+ <scoreDef meter.count="2" meter.unit="2" meter.sym="cut" key.sig="0">
+ <staffGrp>
+ <!-- Tab "staff" has same number of lines as tokens in tab.strings -->
+ <!-- String pitches (written) given from highest to lowest -->
+ <staffDef n="1" lines="6" tab.strings="e5 b4 g4 d4 a3 e3"/>
+ </staffGrp>
+ </scoreDef>
+ <section>
+ <measure n="1">
+ <staff>
+ <layer>
+ <chord dur="2">
+ <!-- extend tab.fret notation to include non-numerical values, such as 'a'? -->
+ <note tab.fret="1" tab.string="6"/>
+ <!-- more notes -->
+ </chord>
+ <chord dur="4">
+ <!-- notes -->
+ </chord>
+ <!-- Ambiguous rhythmic representation, i.e., missing @dur on chord, is OK in MEI -->
+ <chord>
+ <!-- notes -->
+ </chord>
+ </layer>
+ </staff>
+ </measure>
+ <measure n="2"/>
+ <measure n="3"/>
+ <!-- Extend list of values for @left/@right to include value that indicates dots in all spaces? -->
+ <measure n="4" right="rptboth"/>
+ <measure n="5" left="rptboth"/>
+ </section>
+ </score>
+ </mdiv>
+
+ <!-- Encoding 2: above-the-staff duration values explicitly encoded
+ This is probably bad practice as it puts stuff in the model (the MEI) that ought to be in the view. -->
+ <mdiv>
+ <score>
+ <scoreDef meter.count="2" meter.unit="2" meter.sym="cut" key.sig="0">
+ <staffGrp>
+ <!-- A single-line staff where the line is invisible, all notes placed 'on the line' -->
+ <staffDef n="1" lines="1" lines.visible="false" ontheline="true"/>
+ <staffDef n="2" lines="6" tab.strings="e5 b4 g4 d4 a3 e3"/>
+ </staffGrp>
+ </scoreDef>
+ <section>
+ <measure n="1">
+ <staff n="1">
+ <layer>
+ <note dur="2"/>
+ <note dur="4"/>
+ <space/>
+ </layer>
+ </staff>
+ <staff n="2">
+ <layer>
+ <chord dur="2">
+ <note tab.fret="1" tab.string="6"/>
+ <!-- notes -->
+ </chord>
+ <chord dur="4">
+ <!-- notes -->
+ </chord>
+ <chord>
+ <!-- notes -->
+ </chord>
+ </layer>
+ </staff>
+ </measure>
+ <measure n="2"/>
+ <measure n="3"/>
+ <measure n="4" right="rptboth"/>
+ <measure n="5" left="rptboth"/>
+ </section>
+ </score>
+ </mdiv>
+ </body>
+ </music>
+</mei>
24 test/test_shared.cpp
View
@@ -9,12 +9,14 @@
#include <iostream>
#include <gtest/gtest.h>
#include <mei/shared.h>
+#include <mei/header.h>
#include <mei/meielement.h>
#include <mei/meinamespace.h>
using mei::MeiAttribute;
using mei::MeiElement;
using mei::MeiNamespace;
using mei::Note;
+using mei::Hand;
using mei::Accid;
using mei::Layer;
@@ -26,23 +28,21 @@ TEST(TestMeiShared, NoteConstructorTest) {
ASSERT_EQ("note", n->getName());
};
-TEST(TestMeiShared, NoteDefinedMethodsTest) {
- // some methods are defined on Note(), and some are defined on a mixin.
- // test the methods that are defined on note first.
+TEST(TestMeiShared, HandDefinedMethodsTest) {
+ // some methods are defined on Hand(), and some are defined on a mixin.
+ // test the methods that are defined on hand first.
- Note* n = new Note();
-
- n->m_NoteVis.setHeadshape("diamond");
+ Hand* h = new Hand();
- ASSERT_TRUE(n->m_NoteVis.hasHeadshape());
+ h->setInitial("true");
- ASSERT_EQ("diamond", n->m_NoteVis.getHeadshape()->getValue());
+ ASSERT_TRUE(h->hasInitial());
- MeiAttribute* v = n->m_NoteVis.getHeadshape();
- ASSERT_EQ("diamond", v->getValue());
- ASSERT_EQ("headshape", v->getName());
+ ASSERT_EQ("true", h->getInitial()->getValue());
- ASSERT_FALSE(n->m_NoteLogMensural.hasLig());
+ MeiAttribute* i = h->getInitial();
+ ASSERT_EQ("true", i->getValue());
+ ASSERT_EQ("initial", i->getName());
}
TEST(TestMeiShared, NoteDefinedBaseMethodsTest) {
4 test/test_xmlinput.cpp
View
@@ -72,3 +72,7 @@ TEST(TestMeiXmlImport, TestBadVersionException) {
TEST(TestMeiXmlImport, TestNoVersionException) {
ASSERT_THROW(mei::XmlImport::documentFromFile("noversion.mei"), mei::NoVersionFoundException);
}
+
+TEST(TestMeiXmlImport, TestMalformedFileException) {
+ ASSERT_THROW(mei::XmlImport::documentFromFile("malformed.mei"), mei::MalformedFileException);
+}
10 test/test_xmloutput.cpp
View
@@ -14,6 +14,7 @@
#include <mei/meielement.h>
#include <mei/meinamespace.h>
#include <mei/meiattribute.h>
+#include <mei/exceptions.h>
#include <string>
@@ -111,7 +112,14 @@ xml:id=\"musid\" xlink:title=\"my awesome thing\">mus!</music>\n</mei>\n";
ASSERT_EQ(expected, ret);
}
-TEST(TextXmlMeiExport, ThrowsDocumentRootException) {
+TEST(TestXmlMeiExport, ThrowsDocumentRootException) {
MeiDocument *d = new MeiDocument();
ASSERT_THROW(XmlExport::meiDocumentToText(d), mei::DocumentRootNotSetException);
}
+
+TEST(TestXmlMeiExport, ThrowsFileWriteFailureException) {
+ MeiDocument *d = new MeiDocument();
+ MeiElement *m = new MeiElement("mei");
+ d->setRootElement(m);
+ ASSERT_THROW(XmlExport::meiDocumentToFile(d, "C:/StupidName"), mei::FileWriteFailureException);
+}
Please sign in to comment.
Something went wrong with that request. Please try again.