MNX Document Model
Loading...
Searching...
No Matches
Document.h
1/*
2 * Copyright (C) 2025, Robert Patterson
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22#pragma once
23
24#include <filesystem>
25#include <fstream>
26
27#include "BaseTypes.h"
28#include "Global.h"
29#include "Layout.h"
30#include "Part.h"
31#include "Score.h"
32
33namespace mnx {
34
35namespace util {
36class EntityMap;
37}
38
53
58class MnxMetaData : public Object
59{
60public:
61 using Object::Object;
62
66 MnxMetaData(Base& parent, std::string_view key)
67 : Object(parent, key)
68 {
69 // required children
70 set_version(getMnxSchemaVersion());
71 setExtension("schemaVersion", json{ { "value", getMnxSchemaId() } });
72 }
73
78 class Support : public Object
79 {
80 public:
81 using Object::Object;
82
83 MNX_OPTIONAL_PROPERTY_WITH_DEFAULT(bool, useAccidentalDisplay, false);
84 MNX_OPTIONAL_PROPERTY_WITH_DEFAULT(bool, useBeams, false);
85 };
86
90 MNX_REQUIRED_PROPERTY(int, version);
91
96};
97
102class Document : public Object
103{
104private:
106 std::shared_ptr<util::EntityMap> m_entityMapping;
107
108public:
113 Document() : Object(std::make_shared<json>(json::object()), json_pointer{})
114 {
115 // create required children
116 create_mnx();
117 create_global();
118 create_parts();
119 }
120
123 Document(const std::shared_ptr<json>& root) : Object(root, json_pointer{}) {}
124
126 Document(const Document& src) : Object(src), m_entityMapping(nullptr) {}
127
128 using Base::root;
129
134 Document(std::istream& inputStream) : Object(std::make_shared<json>(json::object()), json_pointer{})
135 {
136 inputStream >> *root();
137 }
138
144
151 [[nodiscard]] static Document create(const std::filesystem::path& inputPath)
152 {
153 std::ifstream jsonFile;
154 jsonFile.exceptions(std::ios::failbit | std::ios::badbit);
155 jsonFile.open(inputPath);
156 if (!jsonFile.is_open()) {
157 throw std::runtime_error("Unable to open JSON file: " + inputPath.string());
158 }
159 return Document(jsonFile);
160 }
161
171 template <typename Byte,
172 typename = std::enable_if_t<
173 std::is_integral_v<Byte> &&
174 (sizeof(Byte) == 1) &&
175 !std::is_same_v<std::remove_cv_t<Byte>, bool>>>
176 [[nodiscard]] static Document create(const Byte* data, std::size_t size)
177 {
178 if (!data && size != 0) {
179 throw std::invalid_argument("JSON buffer pointer is null.");
180 }
181 auto root = std::make_shared<json>(nlohmann::json::parse(data, data + size));
182 return Document(root);
183 }
184
191 void save(const std::filesystem::path& outputPath, std::optional<int> indentSpaces) const
192 {
193 std::ofstream file;
194 file.exceptions(std::ofstream::failbit | std::ofstream::badbit);
195 file.open(outputPath, std::ios::out | std::ios::binary);
196 if (!file.is_open()) {
197 throw std::runtime_error("Unable to write to JSON file: " + outputPath.string());
198 }
199 file << root()->dump(indentSpaces.value_or(-1));
200 file.close();
201 }
202
207 void buildEntityMap(EntityMapPolicies policies = {},
208 const std::optional<ErrorHandler>& errorHandler = std::nullopt);
209
211 [[nodiscard]] const util::EntityMap& getEntityMap() const
212 {
213 MNX_ASSERT_IF(!m_entityMapping) {
214 throw std::logic_error("Call buildEntityMap before calling getEntityMap.");
215 }
216 return *m_entityMapping;
217 }
218
220 [[nodiscard]] bool hasEntityMap() const { return static_cast<bool>(m_entityMapping); }
221
225 [[nodiscard]] std::optional<Layout> findFullScoreLayout() const;
226};
227
228static_assert(std::is_move_constructible<mnx::Document>::value, "Document must be move constructible");
229
230} // namespace mnx
Represents an MNX array, encapsulating property access.
Definition BaseTypes.h:499
Base class wrapper for all MNX JSON nodes.
Definition BaseTypes.h:198
T parent() const
Returns the parent object for this node.
Definition BaseTypes.h:246
const std::shared_ptr< json > & root() const
Returns the root.
Definition BaseTypes.h:280
Represents an MNX document and provides methods for loading and saving.
Definition Document.h:103
void save(const std::filesystem::path &outputPath, std::optional< int > indentSpaces) const
Saves the MNX document to a file.
Definition Document.h:191
MNX_OPTIONAL_CHILD(Array< Layout >, layouts)
List of layouts for the MNX document.
MNX_OPTIONAL_CHILD(Array< Score >, scores)
List of scores for the MNX document.
MNX_REQUIRED_CHILD(Array< Part >, parts)
List of parts for the MNX document.
static Document create(const Byte *data, std::size_t size)
Creates a Document from a data buffer containing JSON.
Definition Document.h:176
static Document create(const std::filesystem::path &inputPath)
Creates a Document from a JSON file.
Definition Document.h:151
Document(const Document &src)
Copy constructor that zaps the id mapping, if any.
Definition Document.h:126
Document()
Constructs an empty MNX document. The resulting instance contains all required fields and should vali...
Definition Document.h:113
Document(const std::shared_ptr< json > &root)
Wrap a document around a root element.
Definition Document.h:123
const util::EntityMap & getEntityMap() const
Gets a reference to the entity mapping instance for the document.
Definition Document.h:211
Document(std::istream &inputStream)
Constructs a Document from an input stream.
Definition Document.h:134
bool hasEntityMap() const
Returns whether an entity mapping currently exists.
Definition Document.h:220
void buildEntityMap(EntityMapPolicies policies={}, const std::optional< ErrorHandler > &errorHandler=std::nullopt)
Builds or rebuilds the ID mapping for the document, replacing any existing mapping.
Definition Implementations.cpp:129
std::optional< Layout > findFullScoreLayout() const
Finds a layout that matches the canonical full score layout, where each part staff appears in order o...
Definition Implementations.cpp:404
MNX_REQUIRED_CHILD(MnxMetaData, mnx)
Metadata for the MNX document.
const std::shared_ptr< json > & root() const
Returns the root.
Definition BaseTypes.h:280
MNX_REQUIRED_CHILD(Global, global)
Global data for the MNX document.
Represents the global section of an MNX document, containing global measures.
Definition Global.h:404
Represents optional support metadata within an MNX document.
Definition Document.h:79
MNX_OPTIONAL_PROPERTY_WITH_DEFAULT(bool, useBeams, false)
Optional property that indicates if beams are encoded.
MNX_OPTIONAL_PROPERTY_WITH_DEFAULT(bool, useAccidentalDisplay, false)
Optional property indicating whether accidental display is used.
Represents metadata for an MNX document.
Definition Document.h:59
MNX_OPTIONAL_CHILD(Support, support)
Optional child containing support metadata.
MnxMetaData(Base &parent, std::string_view key)
Creates a new MnxMetaData class as a child of a JSON element.
Definition Document.h:66
MNX_REQUIRED_PROPERTY(int, version)
Required property indicating the version of the MNX document.
Represents an MNX object, encapsulating property access.
Definition BaseTypes.h:412
Object(const std::shared_ptr< json > &root, json_pointer pointer)
Wraps an Object class around an existing JSON object node.
Definition BaseTypes.h:417
void setExtension(const std::string &key, const json &value)
Sets a vendor extension value in _x, creating _x when needed.
Definition BaseTypes.h:435
Provides type-safe ID-based lookup for elements in an MNX document.
Definition EntityMap.h:109
object model for MNX format
nlohmann::json json
JSON class for MNX.
Definition BaseTypes.h:67
json::json_pointer json_pointer
JSON pointer class for MNX.
Definition BaseTypes.h:68
const std::string & getMnxSchemaId()
Returns the MNX schema id from the embedded schema.
Definition SchemaValidate.cpp:76
int getMnxSchemaVersion()
Returns the MNX version extracted from the trailing segment of schema $id.
Definition SchemaValidate.cpp:81
Controls optional behaviors when building an EntityMap.
Definition Document.h:47
bool ottavasRespectVoiceTargets
When false, ottava spans ignore voice-specific targeting (ottavas apply to the entire staff).
Definition Document.h:51
bool ottavasRespectGraceTargets
When false, ottava spans ignore grace-note targeting (graces follow the main event).
Definition Document.h:49