Skip to content

Commit 988cc7d

Browse files
authored
Add Hello, world! example to README (#165)
1 parent 4603fcc commit 988cc7d

File tree

4 files changed

+173
-22
lines changed

4 files changed

+173
-22
lines changed

Documentation/hello_world.gif

1.42 KB
Loading

README.md

Lines changed: 159 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,142 @@ A **work-in-progress** implementation of the [musicXML](https://www.musicxml.com
99

1010
The goal of this project is to allow Swift users to read, manipulate, and write musicXML files in a richly-typed manner on any platform supported by Swift.
1111

12-
## Roadmap
12+
## Hello, world!
13+
14+
Let's construct the "Hello, world!" score example from the [musicXML documentation](https://www.musicxml.com/tutorial/hello-world/). This musical composition consists of one measure that contains a whole note on middle C, based in 4/4 time.
15+
16+
### Graphical Representation
17+
18+
When rendered graphically, this score example should look something like this:
19+
20+
![Hello, world!](Documentation/hello_world.gif)
21+
22+
### musicXML Representation
23+
24+
The musicXML representation looks like this:
25+
26+
```XML
27+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
28+
<!DOCTYPE score-partwise PUBLIC
29+
"-//Recordare//DTD MusicXML 3.1 Partwise//EN"
30+
"http://www.musicxml.org/dtds/partwise.dtd">
31+
<score-partwise version="3.1">
32+
<part-list>
33+
<score-part id="P1">
34+
<part-name>Music</part-name>
35+
</score-part>
36+
</part-list>
37+
<part id="P1">
38+
<measure number="1">
39+
<attributes>
40+
<divisions>1</divisions>
41+
<key>
42+
<fifths>0</fifths>
43+
</key>
44+
<time>
45+
<beats>4</beats>
46+
<beat-type>4</beat-type>
47+
</time>
48+
<clef>
49+
<sign>G</sign>
50+
<line>2</line>
51+
</clef>
52+
</attributes>
53+
<note>
54+
<pitch>
55+
<step>C</step>
56+
<octave>4</octave>
57+
</pitch>
58+
<duration>4</duration>
59+
<type>whole</type>
60+
</note>
61+
</measure>
62+
</part>
63+
</score-partwise>
64+
```
1365

14-
The upcoming pre-release versions will be focused on completing different tasks.
66+
### Constructing the "Hello, world!" example using the `MusicXML` library
1567

16-
### 0.3.0
68+
Let's build up this musical example from the ground up, using the `MusicXML` library.
1769

18-
Pre-release version **0.3.0** will be defined by completing the implementation of the **encoding** of **abstract musical content**. The LilyPond Test Suite tests will be transformed into round-trip tests to ensure that the plumbing is clean.
70+
First, we will create our whole note:
1971

20-
### 0.4.0
72+
```Swift
73+
let note = Note(
74+
pitch: Pitch(step: .c, octave: 4),
75+
duration: 4,
76+
type: .whole
77+
)
78+
```
2179

22-
Pre-release version **0.4.0** will be defined by refining the public interfaces exposed by the `MusicXML` package. Up until this point, pubic initializers may be somewhat clumsy.
80+
Let's establish our `Key`, `Time`, and `Clef`:
2381

24-
## Getting Started
82+
```Swift
83+
let key = Key(fifths: 0)
84+
let time = Time(4,4)
85+
let clef = Clef(sign: .g, line: 2)
86+
```
2587

26-
### Requirements
88+
We can bundle these attributes up:
2789

28-
Use the [Swift Package Manager](https://swift.org/package-manager/) to include the `MusicXML` module into your project.
90+
```Swift
91+
let attributes = Attributes(
92+
divisions: 1,
93+
keys: [key],
94+
times: [time],
95+
clefs: [clef]
96+
)
97+
```
2998

30-
### Usage
99+
Now, we have all the information we need to put together our single measure. In this case, we are traversing the score in a partwise fashion, so we will create a `Partwise.Measure`. Otherwise, we would create a `Timewise.Measure`.
31100

32-
If you want to use the `MusicXML` module in your own project, add the `MusicXML` package to the `dependencies` section of your `Package.swift` file:
101+
```Swift
102+
let measure = Partwise.Measure(
103+
number: "1",
104+
musicData: [
105+
.attributes(attributes),
106+
.note(note)
107+
]
108+
)
109+
```
110+
111+
We have all of the musical information under control, so let's do some administrative work to declare who is playing this music. We will start by creating a single part. Again, as we are traversing the score in a partwise fashion, we will create a `Partwise.Part`, rather than a `Timewise.Part`. We can keep track of this part by its identifier, `"P1"`.
33112

34113
```Swift
35-
let package = Package(
36-
name: ...,
37-
products: [ ... ],
38-
dependencies: [
39-
...,
40-
.package(url: "https://github.com/dn-m/MusicXML", from: "0.1.0")
41-
],
42-
targets: [ ... ]
114+
let part = Partwise.Part(id: "P1", measures: [measure])
115+
```
116+
117+
Almost there. We just need to declare all of the parts in our composition so that we can keep track of things at a high level.
118+
119+
```Swift
120+
let header = Header(
121+
partList: [
122+
.part(ScorePart(id: "P1", name: "Music"))
123+
]
43124
)
44125
```
45126

46-
Then, import the `MusicXML` module into a file which uses it:
127+
We can package up our `header` and our solo `part` into a `Partwise` traversal of the work.
128+
129+
```Swift
130+
let traversal = Partwise(header: header, parts: [part])
131+
```
132+
133+
And then place our traversal inside a `Score`.
47134

48135
```Swift
49-
import MusicXML
136+
let score = Score(traversal: .partwise(traversal))
137+
50138
```
51139

140+
Et voilà, we have willed into being a `MusicXML` value which represents our rigorous masterpiece.
141+
142+
```
143+
let musicXML = MusicXML(score)
144+
```
145+
146+
### 🧬 Decoding musicXML into a `MusicXML.Score`
147+
52148
You can decode a `MusicXML` structure in a variety of ways:
53149

54150
```Swift
@@ -57,6 +153,35 @@ let fromString: MusicXML = try MusicXML(string: string)
57153
let fromURL: MusicXML = try MusicXML(url: url)
58154
```
59155

156+
If you decode the musicXML representation of our "Hello, world!" composition, you will get a value equivalent to the one you have built by hand above.
157+
158+
### 🚧 Work-in-progress: Encoding a `MusicXML.Score` into musicXML
159+
160+
[Pre-release version 0.3.0](https://github.com/dn-m/MusicXML/milestone/1) will see the completion of the encoding from a `MusicXML.Score` into the musicXML format.
161+
162+
163+
## Getting Started
164+
165+
### Requirements
166+
167+
Use the [Swift Package Manager](https://swift.org/package-manager/) to include the `MusicXML` module into your project.
168+
169+
### Usage
170+
171+
If you want to use the `MusicXML` module in your own project, add the `MusicXML` package to the `dependencies` section of your `Package.swift` file:
172+
173+
```Swift
174+
let package = Package(
175+
name: ...,
176+
products: [ ... ],
177+
dependencies: [
178+
...,
179+
.package(url: "https://github.com/dn-m/MusicXML", from: "0.2.0")
180+
],
181+
targets: [ ... ]
182+
)
183+
```
184+
60185
### Development
61186

62187
To contribute to the `MusicXML` package, clone the `git` repository:
@@ -83,6 +208,19 @@ If you use the Xcode IDE, use the Swift Package Manager to generate an `.xcodepr
83208
swift package generate-xcodeproj
84209
```
85210

211+
### Development Roadmap
212+
213+
The upcoming pre-release versions will be focused on completing different tasks.
214+
215+
### 0.3.0
216+
217+
Pre-release version **0.3.0** will be defined by completing the implementation of the **encoding** of **abstract musical content**. The LilyPond Test Suite tests will be transformed into round-trip tests to ensure that the plumbing is clean.
218+
219+
### 0.4.0
220+
221+
Pre-release version **0.4.0** will be defined by refining the public interfaces exposed by the `MusicXML` package. Up until this point, pubic initializers may be somewhat clumsy.
222+
223+
86224
## More Resources
87225

88226
See the [MusicXML XSD Schema Reference](http://usermanuals.musicxml.com/MusicXML/MusicXML.htm#MusicXMLReference.htm%3FTocPath%3DMusicXML%2520Reference%7C_____0) for more information about how musicXML is structured.

Sources/MusicXML/Complex Types/PartList.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,12 @@ extension PartList: Codable {
7878
self.parts = try singleValue.decode([Item].self)
7979
}
8080
}
81+
82+
extension PartList: ExpressibleByArrayLiteral {
83+
84+
// MARK: - ExpressibleByArrayLiteral
85+
86+
public init(arrayLiteral elements: Item...) {
87+
self.init(elements)
88+
}
89+
}

Tests/MusicXMLTests/HelloWorld.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,11 @@ class HelloWorld: XCTestCase {
7272
// Create the part
7373
let part = Partwise.Part(id: "P1", measures: [measure])
7474
// Create the score header
75-
let header = Header(partList: PartList([.part(ScorePart(id: "P1", name: "Music"))]))
75+
let header = Header(
76+
partList: [
77+
.part(ScorePart(id: "P1", name: "Music"))
78+
]
79+
)
7680
// Create the traversal
7781
let traversal = Partwise(header: header, parts: [part])
7882
// Create the score

0 commit comments

Comments
 (0)