Coder Social home page Coder Social logo

webern / mx Goto Github PK

View Code? Open in Web Editor NEW
86.0 10.0 35.0 38.33 MB

C++ binding for MusicXML.

License: MIT License

CMake 0.07% HTML 0.10% C 0.33% C++ 94.20% Ruby 1.71% Shell 0.12% Objective-C 0.01% Rust 3.45%
musicxml xml-dom music music-notation xml c-plus-plus

mx's Issues

Integration Test Paths are Hard Coded

Use cmake to dynamically produce Path.h so that the integration tests will work on any system when cmake is used.

The checked-in version of Path.h should make some assumptions and use a relative path to the mx.xcworkspace directory since, in the absence of cmake, it is likely the developer is using the xcworkspace.

Support UTF-16 and wstring

Support building the MusicXML Class Library in wstring mode. Support import and export of UTF-16 files and strings.

Pitch step and alter not set when creating grace note

Here is how I am configuring the NoteParams. It works fine for rests and normal notes, but the Pitch properties are lost when creating a cue note.
`
if (item->isTemporal()) {
// Configure the note (also can be a rest)
const TemporalPtr temporal = std::dynamic_pointer_cast(item);
NoteParams noteParams;
noteParams.staffNumber = temporal->hand() + 1;
noteParams.voiceNumber = temporal->voice() + 1;
noteParams.duration = temporal->getDuration();
noteParams.durationType = temporal->XMLDurationType();

                        if (item->isNote()) {
                            const NotePtr note = std::dynamic_pointer_cast<Note>(item);
                            if (note->hasGrace()) {
                                noteParams.noteChoice = NoteChoice::Choice::grace;
                            }
                            noteParams.isRest = false;
                            noteParams.isChord = note->partOfChord(tIndex, mIndex) && !note->chordMain(tIndex, mIndex);
                            noteParams.stemDirection = note->stemUp() ? mx::utility::UpDown::up : mx::utility::UpDown::down;
                            noteParams.durationDots = note->dots();
                            noteParams.showAccidental = note->accidental();
                            std::string name;
                            note->XMLPitch(name, noteParams.step, noteParams.alter, noteParams.octave);
                            // std::vector<t::BeamValue> beams;

                        } else if (item->isRest()) {
                            const RestPtr rest = std::dynamic_pointer_cast<Rest>(item);
                            noteParams.isRest = true;
                        }

                        MusicDataChoicePtr noteData = createNote(noteParams);
                        partwiseMeasure->getMusicDataGroup()->addMusicDataChoice(noteData);
                    }

`

README: Min Occurs 1 examples

This is suspicious, fix the example or the claim.

Pattern 1 always works, even if you're not sure whether or not the minOccurs="1" or "0".

mx::core Support a newer version of MusicXML

We are stuck on MusicXML 3.0 because it’s a big job to upgrade to 3.1 (or whichever version is out when we get to it).

Do this without breaking mx::api

  • Create a program that parses the XSD. (In Progress)
    • parse xs:annotation
    • parse xs:attribute
    • parse xs:attributeGroup
    • parse xs:choice
    • parse xs:complexContent
    • parse xs:complexType
    • parse xs:documentation
    • parse xs:element
    • parse xs:enumeration
    • parse xs:extension
    • parse xs:group
    • parse xs:import
    • parse xs:maxInclusive
    • parse xs:minExclusive
    • parse xs:minInclusive
    • parse xs:pattern
    • parse xs:restriction
    • parse xs:schema
    • parse xs:sequence
    • parse xs:simpleContent
    • parse xs:simpleType
    • parse xs:union
  • Create a program that flattens and links the XSD.
  • Create a program that converts the XSD into programming friendly types (Class, Enum, etc).
  • Regenerate Enums
  • Regenerate other SimpleTypes
  • Regenerate unions
  • Check for changes to custom simple types during generating.
  • Regenerate Attributes
  • Regenerate Choices
  • Regenerate Groups
  • Regenerate Elements
  • Create a program that re-generates mx::core for MusicXML 3.0 without too much breakage.
  • Use the program to generate mx::core for MusicXML 3.1 (or 3.2 or 4.0, w3c/musicxml#314) without breakage.
  • Expose some new functionality from mx::core to mx:api.

cmake options to avoid building tests

set up cmake to take options so that, by default we

Build NO test binary.

But we can choose to build
Light tests

Or we can choose to build
Full tests

e.g.
maybe
MX_TEST_BUILD=none
MX_TEST_BUILD=light
MX_TEST_BUILD=all

Import MusicXML

Add the feature to import MusicXML files into the MusicXML-Class-Library object structure.

Use RAII for the DocumentManager

The DocumentManager is a weird concept. Explain why it exists and how to use it early in the Readme and in the code itself.

For extra credit, return an RAII object instead of a document ID so that leaks won't ever happen.

e.g. std::unique_ptr<mx::api::Document> createFromFile( "/some/file.xml" ).

[feature] Constructor with defaults.

Hi, I hope you are well and good amidst the current pandemic.

I've been hitting a minor snag when trying to store mx::api types in various const/global containers. It would be nice if PitchData offered a flexible value constructor to remedy this.

For example:
PitchData(Step step = Step::c, int alter = 0, double cents = 0.0, Accidental c = Accidental::none, bool = false, bool = false, bool = false, bool = false, int octave = 4);

This would enable a user to create pitches like this: PitchData p{Step::c, -1}; which is nice.

A real world use case, I am building an unordered_map to map a root to a mx::api::KeyData fifth.

namespace mx {
using namespace api;
}

namespace std {
template <>
struct hash<mx::PitchData> {
	constexpr inline size_t operator()(const mx::PitchData& p) const {
		size_t h1 = size_t(p.step) << 32;
		size_t h2 = size_t(p.alter);
		return h1 ^ h2;
	}
};
} // namespace std


namespace {
std::unordered_map<mx::PitchData, int> root_to_key_circle {
    { mx::PitchData{/* you cannot do that :( */ }, -1 },
    { mx::PitchData{/* you cannot do that :( */ }, 0 },
    { mx::PitchData{/* you cannot do that :( */ }, 1 },
// etc
};
} // namespace

Now, you may want to have different or other types of constructors, but the general idea is the same. It would be nice to be able to construct a PitchData with a few arguments.

Take care and stay safe!

ci testing fanciness

See issue #23

When we are on any branch other than master (e.g. when we are on develop) the circleci should build with MX_TEST_BUILD=light

When we are on master circleci should build MX_TEST_BUILD=all

Prevent Pugi Symbol Conflicts

Per @p-groarke in #53

Embedding pugixml in your repo like you did will make mx unusable to anyone who links directly with pugixml in their project (duplicate symbols). You can google "dependency hell" for more info (yes, that's the real name). To fix that, you could use something super robust like conan to install pugi when you build mx. Or you can use the less robust ExternalProject_Add as well. I would be happy to send a PR with any of those solutions.

True, embedding could be retained but this could be fixed by patching the pugi namespace to something else.

See webern/ezxml#6

Add Tenets to the readme

Add tenants to the readme explaining why we don't use a package manager and why we don't use find_package in the CMakeLists.txt files.

Properly hide mx::core

mx::core is currently hoisted into the mx::api namespace. Ensure that client code can use the library while referencing only the mx::api headers.

Create an example program that demonstrates that this is working and add it to the CI build so that it doesn't regress.

[Question] new-system

Hi, me again :)

I am trying to add line-breaks every 4 measures. From what I read on musicxml, I need the print new-system attribute. https://usermanuals.musicxml.com/MusicXML/Content/CT-MusicXML-print.htm

I am trying to create new systems like this (I have 6 measures right now).

	for (size_t i = 0; i < part.measures.size(); i += 4) {
		mx::api::SystemData system;
		system.measureIndex = int(i);
		score.systems.insert(system);
	}

	score.sort();
	mx::DocumentManager& mgr = mx::DocumentManager::getInstance();
	const int documentID = mgr.createFromScore(score);

But all I get is the first new-system, not the second. Any idea what I am doing wrong?
Thx

README: Usage Section

Rename the section currently labeled Usage as Core, prepend it with a new section called Usage which describes the mx::api namespace.

NonTraditional key : C key

By using the KeyComponent vector empty to check whether a key is in non-traditional mode, it makes it impossible to create C keys.

Words Color

Color is missing from WordsAttributes and does not save from the api::WordsData struct

KeyComponent : Uninitialized.

Right now, there is no default constructor provided for KeyComponent. This means, if you aren't using cents, it will corrupt the output.

When exporting, in Converter::convertToAlter, the cents won't be equal to 0 and so the generated alter is gibberish.

          <key-step>E</key-step>
          <key-alter>-9223372036854775809</key-alter>
          <key-accidental>flat</key-accidental>

[feature] Enum classes "count".

I don't know how much effort this would take, but if it is too much don't worry about it. I understand you maintain this for fun on your free time.

One of my only gripes with mx is the lack of count enum class members.

In my experience, it is often best practice to add a trailing count enum, which enables you to write generalized loops on enums without ever worrying about size problems. For ex.

enum class potato {
    russet,
    yukon,
    sweet,
    count, // This will always be equal to the number of enum elements, if they aren't specified values.
};

So I can do.

for (size_t i = 0; i < size_t(potato::count); ++i) {
    potato my_potato = potato(i); //etc
}

So, in mx. I wish there was a count where it makes sense. For ex with Step.

    	enum class Step
    	{
    		c = 0,
    		d = 1,
    		e = 2,
    		f = 3,
    		g = 4,
    		a = 5,
    		b = 6,
    		count,
            unspecified = -1
    	};

Cheers

Create a Back Door to `mx::core::DocumentPtr`

A user may want to use mx::api for most things, but need to get at mx::core::DocumentPtr for some tweaking. Provide a way to do this without exposing mx::core symbols in any mx::api headers.

Requested here #44 but leaving that issue to be about the specific key signature issue.

Publish mx with Conan

Respecting #72, mx will remain a zero-dependency library that does not require a package manager to build. There is no reason why we can not publish it into package managers though. So let's publish it with Conan.

Support Pages

The current ScoreData looks like this, with no way to specify page layout (as far as I can tell/remember).

        class ScoreData
        {
        public:
            ScoreData();
            MusicXmlVersion musicXmlVersion;
            std::string musicXmlType;
            std::string workTitle;
            std::string workNumber;
            std::string movementTitle;
            std::string movementNumber;
            std::string composer;
            std::string lyricist;
            std::string arranger;
            std::string publisher;
            std::string copyright;
            EncodingData encoding;
            std::vector<PageTextData> pageTextItems;
            LayoutData layout;
            std::vector<PartData> parts;
            std::vector<PartGroupData> partGroups;
            int ticksPerQuarter;
            std::set<SystemData> systems;

            int getNumMeasures() const;
            int getNumStavesPerSystem() const;

            /// sorts all of the events, directions, etc.
            /// it is good to call this before writing to xml.
            void sort();
        };

Implement page layout in a manner consistent with the SystemData approach.

Open questions: should page breaks be specified by measure index, like systems are, or should page breaks be specified with system index?

[Q] Mixing ::core and ::api structures.

Is it possible to mix core and api data structures? From what I can tell, I don't believe it is. At least I couldn't find it quickly.

My use case :
I must add a theoretical key signature to an mx::api::Measure (d flat minor). As such, I cannot use the mx::api::KeyData, since it cuts off values not present in the signature circle. I think mx::core::NonTraditionalKey is meant to build just that.

I really like the mx::api workflow, so I'm hoping I don't need to change my whole project to use mx::core. Is there a way to retro-fit the NonTraditionalKey into an api::measure?

Thanks!

Mx Backup Staff Change Voice Increment Bug

If Mx encounters a <backup> or <forward>, but this is the last thing that happens before switching to another hand (staff), then the voice number should not be incremented.

Make Objects Copyable

There is no easy way to "deep copy" anything. Each element and attributesclass needs a "clone" function. Alternatively each makeSomething() could be overloaded to create a clone.

Remove empty cpp files

file: libMx.a(MiscData.cpp.o) has no symbols
file: libMx.a(WordsData.cpp.o) has no symbols
file: libMx.a(Elements.cpp.o) has no symbols
file: libMx.a(AttributesIterface.cpp.o) has no symbols
file: libMx.a(MiscData.cpp.o) has no symbols
file: libMx.a(WordsData.cpp.o) has no symbols
file: libMx.a(Elements.cpp.o) has no symbols
file: libMx.a(AttributesIterface.cpp.o) has no symbols
``

[feature] mx::api NonTraditionalKey equivalent

We've discussed about this in the past, and I've found mixing mx::core with mx::api to be a pain! :)

So, I'm just adding this here in case someday you'd want to add this feature to mx::api.

Cheers

Publish mx with Cocoapods

Respecting #72, mx will remain a zero-dependency library that does not require a package manager to build. There is no reason why we can not publish it into package managers though. So let's publish it with Cocoapods.

Remove install_package for ezxml

ezxml is a transparent, built-in part of the mx code base that users need not concern themselves with. We should not install it when installing mx.

Note: maybe it doesn't get installed when installing mx, I'm not sure because it is in a child directory and is statically linked into the mx library.

Create an Self-Contained Example that relies on the installation of Mx

Somewhere, probably at the top-level, an Examples directory could be created.
In there a sub directory could contain a small main function along with a CMakeLists.txt file. In that CMakeLists.txt file we should relay on this installation of mx and use find_package( mx ). During continuous integration runs, we should add a step where we make install then cd to the example and build it. If mx installation isn't working, that build should fail. If mx installation is working, that build should succeed.

Issues with extraneous <forward> element.

While building some measures with 2 staves (treble & bass), 2 voices, I get an extraneous <forward> element at the beginning of the second measure. The export doesn't seem to know the "playhead" is already at the correct position.

I'm curious if there is something to watch out for when dealing with multiple staves/voices?

Snippets of the generating code based on your example, writing a test scale.

Adding notes to measures.

	int current_time = 0;
	for (const mx::NoteData& n : scale) {
		ret.back().staves[0].voices[treb_voice_id].notes.push_back(n);
		mx::NoteData bass_n = n;
		bass_n.pitchData.octave -= 1;
		ret.back().staves[1].voices[bass_voice_id].notes.push_back(bass_n);

		current_time += n.durationData.durationTimeTicks;

		if (current_time >= ret.back().timeSignature.beats
						* ret.back().timeSignature.beatType) {
			ret.push_back(build_measure());
			current_time = 0;
		}
	}

How the measure is built.

mx::MeasureData build_measure(bool first = false) {
	mx::MeasureData ret;
	mx::StaffData staff_treb;
	mx::StaffData staff_bass;

	ret.timeSignature.beats = qticks;
	ret.timeSignature.beatType = qticks;

	if (first) {
		ret.timeSignature.isImplicit = false;

		// set the clef
		mx::ClefData clef_treb;
		clef_treb.setTreble();
		staff_treb.clefs.push_back(clef_treb);

		mx::ClefData clef_bass;
		clef_bass.setBass();
		staff_bass.clefs.push_back(clef_bass);

		mx::KeyData key;
		key.fifths = 4; //test
		ret.keys.push_back(key);
	}


	// add a voice
	mx::VoiceData voice_treb;
	mx::VoiceData voice_bass;

	staff_treb.voices[treb_voice_id] = voice_treb;
	staff_bass.voices[bass_voice_id] = voice_bass;

	// add a staff
	ret.staves.push_back(staff_treb);
	ret.staves.push_back(staff_bass);

	return ret;
}

The Encoding Element should allow multiple choices

class Encoding in Elements.h is implemented incorrectly, it should allow for an unbounded number of Encoding Choices.

        <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element name="encoding-date" type="yyyy-mm-dd"/>
            <xs:element name="encoder" type="typed-text"/>
            <xs:element name="software" type="xs:string"/>
            <xs:element name="encoding-description" type="xs:string"/>
            <xs:element name="supports" type="supports"/>
        </xs:choice>

Currently I have this implemented as maxOccurs=1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.