musicality 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +27 -1
- data/README.md +153 -10
- data/bin/collidify +102 -0
- data/bin/lilify +57 -29
- data/bin/midify +64 -24
- data/bin/musicality +39 -0
- data/examples/composition/auto_counterpoint.rb +4 -5
- data/examples/composition/part_generator.rb +8 -2
- data/examples/composition/scale_exercise.rb +1 -1
- data/examples/notation/notes.rb +27 -0
- data/examples/notation/parts.rb +51 -0
- data/examples/notation/scores.rb +38 -0
- data/examples/notation/twinkle.rb +34 -0
- data/examples/notation/twinkle.score +33 -0
- data/lib/musicality.rb +46 -11
- data/lib/musicality/composition/dsl/score_dsl.rb +2 -2
- data/lib/musicality/composition/dsl/score_methods.rb +10 -7
- data/lib/musicality/notation/conversion/change_conversion.rb +1 -1
- data/lib/musicality/notation/conversion/note_time_converter.rb +6 -23
- data/lib/musicality/notation/conversion/score_conversion.rb +15 -15
- data/lib/musicality/notation/conversion/score_converter.rb +50 -67
- data/lib/musicality/notation/model/articulations.rb +3 -2
- data/lib/musicality/notation/model/change.rb +15 -6
- data/lib/musicality/notation/model/dynamics.rb +11 -8
- data/lib/musicality/notation/model/instrument.rb +61 -0
- data/lib/musicality/notation/model/instruments.rb +111 -0
- data/lib/musicality/notation/model/key.rb +137 -0
- data/lib/musicality/notation/model/keys.rb +37 -0
- data/lib/musicality/notation/model/link.rb +6 -19
- data/lib/musicality/notation/model/mark.rb +43 -0
- data/lib/musicality/notation/model/marks.rb +11 -0
- data/lib/musicality/notation/model/meter.rb +4 -0
- data/lib/musicality/notation/model/note.rb +42 -28
- data/lib/musicality/notation/model/part.rb +18 -5
- data/lib/musicality/notation/model/pitch.rb +13 -4
- data/lib/musicality/notation/model/score.rb +104 -66
- data/lib/musicality/notation/model/symbols.rb +16 -11
- data/lib/musicality/notation/parsing/articulation_parsing.rb +38 -38
- data/lib/musicality/notation/parsing/articulation_parsing.treetop +14 -14
- data/lib/musicality/notation/parsing/link_parsing.rb +6 -6
- data/lib/musicality/notation/parsing/link_parsing.treetop +3 -3
- data/lib/musicality/notation/parsing/mark_parsing.rb +138 -0
- data/lib/musicality/notation/parsing/mark_parsing.treetop +31 -0
- data/lib/musicality/notation/parsing/note_node.rb +19 -12
- data/lib/musicality/notation/parsing/note_parsing.rb +218 -87
- data/lib/musicality/notation/parsing/note_parsing.treetop +9 -5
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +7 -2
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.treetop +1 -1
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.rb +6 -4
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.treetop +1 -1
- data/lib/musicality/notation/util/function.rb +41 -18
- data/lib/musicality/packable.rb +156 -0
- data/lib/musicality/performance/conversion/glissando_converter.rb +2 -2
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +223 -70
- data/lib/musicality/performance/conversion/portamento_converter.rb +5 -2
- data/lib/musicality/performance/conversion/score_collator.rb +70 -64
- data/lib/musicality/performance/midi/midi_events.rb +3 -3
- data/lib/musicality/performance/midi/midi_settings.rb +127 -0
- data/lib/musicality/performance/midi/midi_util.rb +8 -2
- data/lib/musicality/performance/midi/part_sequencer.rb +19 -18
- data/lib/musicality/performance/midi/score_sequencer.rb +13 -9
- data/lib/musicality/performance/midi/score_sequencing.rb +5 -5
- data/lib/musicality/performance/model/attack.rb +8 -0
- data/lib/musicality/performance/model/duration_functions.rb +23 -0
- data/lib/musicality/performance/model/note_sequence.rb +52 -95
- data/lib/musicality/performance/model/separation.rb +10 -0
- data/lib/musicality/performance/supercollider/add_actions.rb +13 -0
- data/lib/musicality/performance/supercollider/bundle.rb +18 -0
- data/lib/musicality/performance/supercollider/conductor.rb +125 -0
- data/lib/musicality/performance/supercollider/group.rb +71 -0
- data/lib/musicality/performance/supercollider/message.rb +26 -0
- data/lib/musicality/performance/supercollider/node.rb +122 -0
- data/lib/musicality/performance/supercollider/performer.rb +123 -0
- data/lib/musicality/performance/supercollider/score_conducting.rb +17 -0
- data/lib/musicality/performance/supercollider/server.rb +8 -0
- data/lib/musicality/performance/supercollider/synth.rb +43 -0
- data/lib/musicality/performance/supercollider/synthdef.rb +57 -0
- data/lib/musicality/performance/supercollider/synthdef_settings.rb +23 -0
- data/lib/musicality/performance/supercollider/synthdefs.rb +1654 -0
- data/lib/musicality/{composition/model/pitch_class.rb → pitch_class.rb} +1 -1
- data/lib/musicality/{composition/model/pitch_classes.rb → pitch_classes.rb} +9 -9
- data/lib/musicality/printing/lilypond/clef.rb +12 -0
- data/lib/musicality/printing/lilypond/key_engraving.rb +9 -0
- data/lib/musicality/printing/lilypond/lilypond_settings.rb +105 -0
- data/lib/musicality/printing/lilypond/meter_engraving.rb +1 -1
- data/lib/musicality/printing/lilypond/note_engraving.rb +112 -30
- data/lib/musicality/printing/lilypond/part_engraver.rb +114 -3
- data/lib/musicality/printing/lilypond/pitch_class_engraving.rb +22 -0
- data/lib/musicality/printing/lilypond/pitch_engraving.rb +2 -15
- data/lib/musicality/printing/lilypond/score_engraver.rb +44 -73
- data/lib/musicality/printing/lilypond/score_engraving.rb +3 -3
- data/lib/musicality/project/create_tasks.rb +31 -0
- data/lib/musicality/project/file_cleaner.rb +19 -0
- data/lib/musicality/project/file_raker.rb +107 -0
- data/lib/musicality/project/load_config.rb +43 -0
- data/lib/musicality/project/project.rb +64 -0
- data/lib/musicality/version.rb +1 -1
- data/musicality.gemspec +3 -0
- data/spec/composition/util/random_sampler_spec.rb +1 -1
- data/spec/notation/conversion/measure_note_map_spec.rb +1 -1
- data/spec/notation/conversion/note_time_converter_spec.rb +5 -85
- data/spec/notation/conversion/score_conversion_spec.rb +6 -41
- data/spec/notation/conversion/score_converter_spec.rb +19 -137
- data/spec/notation/model/change_spec.rb +55 -0
- data/spec/notation/model/key_spec.rb +171 -0
- data/spec/notation/model/link_spec.rb +34 -5
- data/spec/notation/model/meter_spec.rb +15 -0
- data/spec/notation/model/note_spec.rb +33 -27
- data/spec/notation/model/part_spec.rb +53 -4
- data/spec/notation/model/pitch_spec.rb +15 -0
- data/spec/notation/model/score_spec.rb +64 -72
- data/spec/notation/parsing/link_nodes_spec.rb +3 -3
- data/spec/notation/parsing/link_parsing_spec.rb +6 -6
- data/spec/notation/parsing/note_node_spec.rb +34 -9
- data/spec/notation/parsing/note_parsing_spec.rb +11 -9
- data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +4 -0
- data/spec/notation/parsing/pitch_node_spec.rb +0 -1
- data/spec/notation/util/value_computer_spec.rb +2 -2
- data/spec/performance/conversion/glissando_converter_spec.rb +9 -9
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +48 -53
- data/spec/performance/conversion/portamento_converter_spec.rb +11 -9
- data/spec/performance/conversion/score_collator_spec.rb +59 -63
- data/spec/performance/midi/midi_util_spec.rb +22 -8
- data/spec/performance/midi/part_sequencer_spec.rb +2 -2
- data/spec/performance/midi/score_sequencer_spec.rb +12 -10
- data/spec/performance/midi/score_sequencing_spec.rb +2 -2
- data/spec/performance/model/note_sequence_spec.rb +41 -134
- data/spec/printing/note_engraving_spec.rb +204 -0
- data/spec/printing/score_engraver_spec.rb +40 -0
- data/spec/spec_helper.rb +1 -0
- metadata +69 -23
- data/examples/notation/hip.rb +0 -32
- data/examples/notation/missed_connection.rb +0 -26
- data/examples/notation/song1.rb +0 -33
- data/examples/notation/song2.rb +0 -32
- data/lib/musicality/notation/model/links.rb +0 -11
- data/lib/musicality/notation/packing/change_packing.rb +0 -56
- data/lib/musicality/notation/packing/part_packing.rb +0 -31
- data/lib/musicality/notation/packing/score_packing.rb +0 -123
- data/lib/musicality/performance/model/note_attacks.rb +0 -19
- data/lib/musicality/performance/util/note_linker.rb +0 -28
- data/spec/notation/packing/change_packing_spec.rb +0 -304
- data/spec/notation/packing/part_packing_spec.rb +0 -66
- data/spec/notation/packing/score_packing_spec.rb +0 -255
- data/spec/performance/util/note_linker_spec.rb +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2ca1d5317ab9f47ee4a5a48391c529b6db3dc80
|
4
|
+
data.tar.gz: 61306cd02de6089beb8ebfd71617cefbafb7a1ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48c4022b31b8fede1ecf3ae7d8a0f5ee574d02cb7c46863e746d2df11ce0a5f7eec568df3180742202c2ae11d0885c34a8df07c68d43bf17aa1af13fbeecc001
|
7
|
+
data.tar.gz: f4ef016ba31054de3de408c1952e2e8d8319c7d09b6faa6dbd72d166636ac7a4fafa1c2e3ffbbf996d3edff397cdbf808d3406bdb62631994d8dc4a5100f3228
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
### 0.8.0 / 2016-01-01
|
2
|
+
* Require ruby v2.0 or greater.
|
3
|
+
* Remove Score::Unmeasured and change Score::Measured to Score::Tempo
|
4
|
+
* Add more convenience methods for note creation, and alter their interface to take a variable number of args, each being interpreted as a pitch group (which may also be a single pitch)
|
5
|
+
* Add back Score#title= and Score#composer= methods
|
6
|
+
* Change score creation method ScoreDSL#score to ScoreDSL#tempo_score, and add ScoreDSL#score reader method to get the created score.
|
7
|
+
* Add bin/lilify to convert score (in YAML format) to Lilypond format using the ScoreEngraver class.
|
8
|
+
* Add Score::Tempo#to_lilypond
|
9
|
+
* Make default behaviour in lilify to engrave all parts, unless --split option is used. Replaced partname/title pair args with plain part names.
|
10
|
+
* Add Key class. Add start_key and key_changes to Score class.
|
11
|
+
* Integrate start_key into Lilypond engraving. Add sharp pitch classes.
|
12
|
+
* Revise note model (for notation) and note sequence model (for performance), including parsing, to use slur marks and articulation only. And there are no legato/slur links or articulations anymore.
|
13
|
+
* Modify note model (again) to include marks for slur and triplet. Modify parsing, performance, and printing code accordingly.
|
14
|
+
* MIDI performance changes to support the new note sequence model
|
15
|
+
* Add Packable module to take care of packing and unpacking. Remove custom pack/unpack code.
|
16
|
+
* Add Part#settings. Create settings classes for LilyPond and MIDI
|
17
|
+
* Add Part#lilypond_settings in lilypond_settings.rb and Part#midi_settings in midi_settings.rb
|
18
|
+
* Add support for non-realtime SUperCollider performance
|
19
|
+
* Make dynamic levels increase exponentially, like
|
20
|
+
* In ScoreCollator#collate_changes, return new start value as well as dynamic changes, instead of always creating an initial immediate change
|
21
|
+
* Add SynthDef class to be able to include SynthDefs in SuperCollider code
|
22
|
+
* Add musicality project infrastructure
|
23
|
+
* Make examples less vague
|
24
|
+
* Add #to_osc for Score::Tempo and Score::Timed
|
25
|
+
* In ScoreCollator, use entire score if score has no program segments
|
26
|
+
|
1
27
|
### 0.7.0 / 2015-04-28
|
2
28
|
* Replace Score's title and composer accessors with dual-methods Score#title and Score#composer that can be used to get/set. This makes them useful in the DSL context.
|
3
29
|
|
@@ -12,7 +38,7 @@
|
|
12
38
|
* disallow articulation and accent when pitches aren't present
|
13
39
|
* do not provide syntax for targeted slur and legato links
|
14
40
|
* Add *basic* support for Lilypond engraving (sheet music printing)
|
15
|
-
* Add `#to_midi_seq` convenience method to
|
41
|
+
* Add `#to_midi_seq` convenience method to timed and tempo-based scores.
|
16
42
|
* Add some rudimentary composition features
|
17
43
|
* `ScaleClass` class: contains a series of increasing pitch intervals. Can be realized as a scale given a starting pitch class.
|
18
44
|
* `Scale` class: contains a starting pitch class, and a series of pitch intervals. Can be realized as a series of pitches given a starting octave.
|
data/README.md
CHANGED
@@ -20,16 +20,44 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Basic Usage
|
22
22
|
|
23
|
-
|
23
|
+
To begin with, Musicality has a class to represent pitch:
|
24
|
+
```ruby
|
25
|
+
require 'musicality'
|
26
|
+
middle_c = Musicality::Pitch.new(octave: 4, semitone: 0)
|
27
|
+
puts middle_c.freq # => 261.625...
|
28
|
+
|
29
|
+
not_quite_middle_c = Musicality::Pitch.new(octave: 4, semitone: 0, cent: 12)
|
30
|
+
puts not_quite_middle_c.freq # => 263.445...
|
31
|
+
```
|
32
|
+
|
33
|
+
For convenience, there are Pitch objects for commonly used octave-semitone combinations:
|
34
|
+
```ruby
|
35
|
+
require 'musicality'
|
36
|
+
include Musicality::Pitches
|
37
|
+
|
38
|
+
c_scale = [C4,D4,E4,F4,G4,A4,B4,C4]
|
39
|
+
freqs = c_scale.map {|p| p.freq }
|
40
|
+
```
|
41
|
+
|
42
|
+
Notes can be created like this:
|
24
43
|
```ruby
|
25
44
|
require 'musicality'
|
26
45
|
include Musicality
|
27
46
|
include Pitches
|
28
|
-
include Dynamics
|
29
47
|
|
48
|
+
# convenience methods for common durations
|
30
49
|
single = Note.quarter(Ab4)
|
31
50
|
rest = Note.quarter
|
32
51
|
chord = Note.whole([C3,E3,G3])
|
52
|
+
|
53
|
+
# specific duration + articulation
|
54
|
+
note = Note.new(Rational(7,8), Bb3, articulation: Articulations::STACCATO)
|
55
|
+
puts note.to_s # => "7/8Bb3."
|
56
|
+
|
57
|
+
# magic!
|
58
|
+
puts note.transpose(2).to_s # => "7/8C4."
|
59
|
+
|
60
|
+
# combine notes into a part
|
33
61
|
part = Part.new(MP, notes:[single,rest,chord])
|
34
62
|
```
|
35
63
|
|
@@ -44,35 +72,66 @@ require 'musicality'
|
|
44
72
|
include Musicality
|
45
73
|
include Meters
|
46
74
|
include Dynamics
|
75
|
+
include Pitches
|
47
76
|
|
48
|
-
|
77
|
+
score = Score::Tempo.new(FOUR_FOUR, 120, title: "Twinkle, Twinkle, Little Star") do |s|
|
49
78
|
s.parts["rhand"] = Part.new(MF) do |p|
|
50
|
-
|
51
|
-
|
79
|
+
a_notes = q(C4,C4,G4,G4,A4,A4) + h(G4) +
|
80
|
+
q(F4,F4,E4,E4,D4,D4) + h(C4)
|
81
|
+
b_notes = q(G4,G4,F4,F4,E4,E4) + h(D4)
|
82
|
+
p.notes += a_notes + b_notes
|
52
83
|
end
|
84
|
+
|
53
85
|
s.parts["lhand"] = Part.new(MF) do |p|
|
54
|
-
|
55
|
-
|
86
|
+
Cmaj = [C3,E3,G3]
|
87
|
+
Fmaj = [F2,A2,C3]
|
88
|
+
Gmaj = [G2,B2,D3]
|
89
|
+
|
90
|
+
a_chords = h(Cmaj,Cmaj,Fmaj,Cmaj) +
|
91
|
+
h(Fmaj,Cmaj,Gmaj,Cmaj)
|
92
|
+
b_chords = h(Cmaj,Fmaj,Cmaj,Gmaj)
|
93
|
+
p.notes += a_chords + b_chords
|
56
94
|
end
|
95
|
+
|
96
|
+
s.program.push 0...4
|
97
|
+
s.program.push 4...6
|
98
|
+
s.program.push 4...6
|
57
99
|
s.program.push 0...4
|
58
100
|
end
|
59
101
|
```
|
60
102
|
|
61
103
|
## MIDI Sequencing
|
62
104
|
|
63
|
-
A score can be prepared for MIDI playback
|
105
|
+
A score can be prepared for MIDI playback by converting it to a MIDI::Sequence object (see [midilib]( https://github.com/jimm/midilib )). This can be accomplished with the `ScoreSequencer` class or `Score#to_midi_seq` method. To continue the previous example,
|
64
106
|
```ruby
|
65
107
|
TEMPO_SAMPLE_RATE = 500
|
66
108
|
seq = twinkle.to_midi_seq TEMPO_SAMPLE_RATE
|
67
|
-
File.open('twinkle.mid', 'wb'){ |
|
109
|
+
File.open('twinkle.mid', 'wb'){ |f| seq.write(f) }
|
68
110
|
```
|
111
|
+
|
112
|
+
## LilyPond Engraving
|
113
|
+
|
114
|
+
A score can be prepared for engraving (fancy printing) by converting it to a string in LilyPond text format (see [lilypond.org](http://lilypond.org/)). This can be accomplished using the `ScoreEngraver` class or `Score#to_lilypond` method. Using the score from the above example,
|
115
|
+
```ruby
|
116
|
+
File.open('twinkle.ly','w'){|f| f.write(twinkle.to_lilypond) }
|
117
|
+
```
|
118
|
+
|
119
|
+
|
120
|
+
## SuperCollider Rendering
|
121
|
+
|
122
|
+
A score can be prepared for rendering (as audio) by converting it to a raw OSC binary file, used for SuperCollider non-realtime rendering (see [SuperCollider homepage](https://supercollider.github.io/)). This can be accomplished using the `SuperCollider::Conductor` class or `Score#to_osc` method. Using the score from the above example,
|
123
|
+
```ruby
|
124
|
+
twinkle.to_osc('twinkle')
|
125
|
+
```
|
126
|
+
|
127
|
+
|
69
128
|
## Score DSL
|
70
129
|
|
71
130
|
The score DSL is an internal DSL (built on Ruby) that consists of a *score* block with additional blocks inside this to add sections, notes, and tempo/meter/dynamic changes.
|
72
131
|
|
73
132
|
Here is an example of a score file.
|
74
133
|
```ruby
|
75
|
-
|
134
|
+
tempo_score Meters::FOUR_FOUR, 120 do
|
76
135
|
title "Twinkle, Twinkle, Little Star"
|
77
136
|
|
78
137
|
Cmaj = [C3,E3,G3]
|
@@ -109,6 +168,90 @@ dsl = ScoreDSL.load 'twinkle.score'
|
|
109
168
|
score = dsl.score
|
110
169
|
```
|
111
170
|
|
171
|
+
|
172
|
+
## Musicality Projects
|
173
|
+
|
174
|
+
To create a new project for working on Muscality scores, use the `musicality` command-line executable that is installed along with the gem.
|
175
|
+
|
176
|
+
$ musicality new my_scores
|
177
|
+
|
178
|
+
This will create a directory (or fill an existing one) with three files:
|
179
|
+
* *Gemfile* - a Bundler gem dependency file that lists the `musicality` gem
|
180
|
+
* *Rakefile* - creates rake tasks for processing score files (files with a .score extension)
|
181
|
+
* *config.yml* - customize project configuration options
|
182
|
+
|
183
|
+
Also, a *scores* subdirectory is created as the default location to keep score files.
|
184
|
+
|
185
|
+
Before processing any scores, run
|
186
|
+
|
187
|
+
$ bundle install
|
188
|
+
|
189
|
+
To process score files, run rake with the desired target format. The scores will be converted into any intermediate formats as necessary. For example, to generate a PDF by LilyPond engraving, run
|
190
|
+
|
191
|
+
$ rake pdf
|
192
|
+
|
193
|
+
This will generate a .pdf file for each score file. In addition, this would cause a chain of intermediate files to be created as well, as follows:
|
194
|
+
|
195
|
+
fname.score -> fname.yml -> fname.ly -> fname.pdf
|
196
|
+
|
197
|
+
The supported final target formats are listed in the table below.
|
198
|
+
|
199
|
+
<table>
|
200
|
+
<tr>
|
201
|
+
<th>Target format</th>
|
202
|
+
<th>Rake command</th>
|
203
|
+
</tr>
|
204
|
+
<tr>
|
205
|
+
<td>MIDI</td>
|
206
|
+
<td>midi</td>
|
207
|
+
</tr>
|
208
|
+
<tr>
|
209
|
+
<td>LilyPond PDF</td>
|
210
|
+
<td>pdf</td>
|
211
|
+
</tr>
|
212
|
+
<tr>
|
213
|
+
<td>LilyPond PNG</td>
|
214
|
+
<td>png</td>
|
215
|
+
</tr>
|
216
|
+
<tr>
|
217
|
+
<td>LilyPond PostScript</td>
|
218
|
+
<td>ps</td>
|
219
|
+
</tr>
|
220
|
+
<tr>
|
221
|
+
<td>SuperCollider AIFF</td>
|
222
|
+
<td>aiff</td>
|
223
|
+
</tr>
|
224
|
+
<tr>
|
225
|
+
<td>SuperCollider WAV</td>
|
226
|
+
<td>wav</td>
|
227
|
+
</tr>
|
228
|
+
<tr>
|
229
|
+
<td>SuperCollider FLAC</td>
|
230
|
+
<td>flac</td>
|
231
|
+
</tr>
|
232
|
+
</table>
|
233
|
+
|
234
|
+
In addition, there are also commands for all the intermediate formats
|
235
|
+
|
236
|
+
<table>
|
237
|
+
<tr>
|
238
|
+
<th>Target format</th>
|
239
|
+
<th>Rake command</th>
|
240
|
+
</tr>
|
241
|
+
<tr>
|
242
|
+
<td>YAML</td>
|
243
|
+
<td>yaml</td>
|
244
|
+
</tr>
|
245
|
+
<tr>
|
246
|
+
<td>LilyPond (text)</td>
|
247
|
+
<td>ly</td>
|
248
|
+
</tr>
|
249
|
+
<tr>
|
250
|
+
<td>Raw OSC (binary)</td>
|
251
|
+
<td>osc</td>
|
252
|
+
</tr>
|
253
|
+
</table>
|
254
|
+
|
112
255
|
## Contributing
|
113
256
|
|
114
257
|
1. Fork it ( https://github.com/[my-github-username]/musicality/fork )
|
data/bin/collidify
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
exe_name = File.basename(__FILE__)
|
4
|
+
|
5
|
+
doc = <<DOCOPT
|
6
|
+
Loads a musicality score from YAML file, and generates SuperCollider code
|
7
|
+
for non-realtime SuperCollider rendering.
|
8
|
+
|
9
|
+
If no part names are given, all score parts are selected for performance.
|
10
|
+
Otherwise, only the given parts names will be selected. If --outdir is not
|
11
|
+
given, files will be put in the same directory as the score file.
|
12
|
+
|
13
|
+
Usage:
|
14
|
+
#{exe_name} SCORE [PART]... [options]
|
15
|
+
#{exe_name} -h | --help
|
16
|
+
#{exe_name} --version
|
17
|
+
|
18
|
+
Arguments:
|
19
|
+
SCORE A musicality score file (may be packed as a hash) in a YAML file
|
20
|
+
PART name of a part in the score (e.g. "lhand")
|
21
|
+
|
22
|
+
Options:
|
23
|
+
-v --verbose Display sclang output
|
24
|
+
--outdir=OUTD Dir where files will be put (defaults to same dir as score file)
|
25
|
+
--srate=SRATE Sampling rate for converting tempo-based score to time-based
|
26
|
+
score, and for sampling dynamic change values [default: 200]
|
27
|
+
--leadtime=LT Time before performance begins (must be > 0) [default: 0.1]
|
28
|
+
-h --help Show this screen.
|
29
|
+
--version Show version.
|
30
|
+
DOCOPT
|
31
|
+
|
32
|
+
require 'docopt'
|
33
|
+
begin
|
34
|
+
args = Docopt::docopt(doc)
|
35
|
+
puts args
|
36
|
+
rescue Docopt::Exit => e
|
37
|
+
puts e.message
|
38
|
+
exit
|
39
|
+
end
|
40
|
+
|
41
|
+
require 'musicality'
|
42
|
+
|
43
|
+
if args["--version"]
|
44
|
+
puts "#{exe_name} from musicality v#{Musicality::VERSION}"
|
45
|
+
exit
|
46
|
+
end
|
47
|
+
|
48
|
+
SCORE_FILE = args["SCORE"]
|
49
|
+
unless File.exists? SCORE_FILE
|
50
|
+
puts "Score file #{SCORE_FILE} does not exist. Aborting."
|
51
|
+
exit
|
52
|
+
end
|
53
|
+
|
54
|
+
if args["--outdir"]
|
55
|
+
OUTDIR = args["--outdir"]
|
56
|
+
unless Dir.exists? OUTDIR
|
57
|
+
puts "Output directory #{OUTDIR} does not exist. Aborting."
|
58
|
+
exit
|
59
|
+
end
|
60
|
+
else
|
61
|
+
OUTDIR = File.dirname(SCORE_FILE)
|
62
|
+
end
|
63
|
+
|
64
|
+
VERBOSE = args["--verbose"]
|
65
|
+
PARTS = args["PART"]
|
66
|
+
LEADTIME = args["--leadtime"].to_f
|
67
|
+
|
68
|
+
require 'yaml'
|
69
|
+
include Musicality
|
70
|
+
|
71
|
+
File.open(SCORE_FILE) do |fin|
|
72
|
+
print "Reading file '#{SCORE_FILE}'..."
|
73
|
+
score = YAML.load(fin.read)
|
74
|
+
|
75
|
+
if score.is_a? Hash
|
76
|
+
score = score.unpack
|
77
|
+
end
|
78
|
+
puts "done"
|
79
|
+
|
80
|
+
unless score.is_a? Score::Timed
|
81
|
+
print "Converting to timed score..."
|
82
|
+
score = score.to_timed(args["--srate"].to_i)
|
83
|
+
puts "done"
|
84
|
+
end
|
85
|
+
|
86
|
+
if score.valid?
|
87
|
+
conductor = SuperCollider::Conductor.new(score)
|
88
|
+
|
89
|
+
perform_kwargs = { :verbose => VERBOSE, :lead_time => LEADTIME }
|
90
|
+
if PARTS.any?
|
91
|
+
perform_kwargs[:selected_parts] = PARTS
|
92
|
+
end
|
93
|
+
base_fpath = "#{OUTDIR}/#{File.basename(SCORE_FILE,File.extname(SCORE_FILE))}"
|
94
|
+
|
95
|
+
print "Making SuperCollider binary OSC file..."
|
96
|
+
conductor.perform(base_fpath, **perform_kwargs)
|
97
|
+
puts "done"
|
98
|
+
else
|
99
|
+
puts "Score is not valid. See errors:"
|
100
|
+
puts score.errors.join("\n")
|
101
|
+
end
|
102
|
+
end
|
data/bin/lilify
CHANGED
@@ -3,24 +3,27 @@
|
|
3
3
|
exe_name = File.basename(__FILE__)
|
4
4
|
|
5
5
|
doc = <<DOCOPT
|
6
|
-
Loads a musicality score from YAML file, and converts it to
|
6
|
+
Loads a musicality score from YAML file, and converts it to one or more Lilypond
|
7
|
+
files for engraving. If no part names are given, all score parts are selected for
|
8
|
+
engraving. Otherwise, only the given parts names will be selected. By default, a
|
9
|
+
a single engraving file will be produced. If the --split flag is used, a file
|
10
|
+
will be produced for each part. If --outdir is not given, files will be put in
|
11
|
+
the same directory as the score file.
|
7
12
|
|
8
13
|
Usage:
|
9
|
-
#{exe_name}
|
14
|
+
#{exe_name} SCORE [PART]... [options]
|
10
15
|
#{exe_name} -h | --help
|
11
16
|
#{exe_name} --version
|
12
17
|
|
13
18
|
Arguments:
|
14
|
-
|
19
|
+
SCORE A musicality score file (may be packed as a hash) in a YAML file
|
15
20
|
PART name of a part in the score (e.g. "lhand")
|
16
|
-
TITLE The title to give the part (e.g. "Left Hand")
|
17
21
|
|
18
22
|
Options:
|
19
|
-
--
|
20
|
-
|
21
|
-
--
|
22
|
-
--
|
23
|
-
|
23
|
+
--split Make separate Lilypond files for each part
|
24
|
+
--outdir=OUTD Dir where files will be put (defaults to same dir as score file)
|
25
|
+
-h --help Show this screen.
|
26
|
+
--version Show version.
|
24
27
|
DOCOPT
|
25
28
|
|
26
29
|
require 'docopt'
|
@@ -39,43 +42,68 @@ if args["--version"]
|
|
39
42
|
exit
|
40
43
|
end
|
41
44
|
|
45
|
+
SCORE_FILE = args["SCORE"]
|
46
|
+
unless File.exists? SCORE_FILE
|
47
|
+
puts "Score file #{SCORE_FILE} does not exist. Aborting."
|
48
|
+
exit
|
49
|
+
end
|
50
|
+
|
51
|
+
if args["--outdir"]
|
52
|
+
OUTDIR = args["--outdir"]
|
53
|
+
unless Dir.exists? OUTDIR
|
54
|
+
puts "Output directory #{OUTDIR} does not exist. Aborting."
|
55
|
+
exit
|
56
|
+
end
|
57
|
+
else
|
58
|
+
OUTDIR = File.dirname(SCORE_FILE)
|
59
|
+
end
|
60
|
+
|
61
|
+
PARTS = args["PART"]
|
62
|
+
SPLIT = args["--split"]
|
63
|
+
|
42
64
|
require 'yaml'
|
43
65
|
include Musicality
|
44
66
|
|
45
|
-
|
46
|
-
|
47
|
-
print "Reading file '#{fin_name}'..."
|
67
|
+
File.open(SCORE_FILE) do |fin|
|
68
|
+
print "Reading file '#{SCORE_FILE}'..."
|
48
69
|
score = YAML.load(fin.read)
|
49
70
|
|
50
71
|
if score.is_a? Hash
|
51
|
-
score =
|
72
|
+
score = score.unpack
|
52
73
|
end
|
53
74
|
puts "done"
|
54
75
|
|
55
76
|
if score.valid?
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
make_lilypond_args = {
|
61
|
-
:part_titles => Hash[[part_names,part_titles].transpose]
|
62
|
-
}
|
63
|
-
unless args["--all"]
|
64
|
-
make_lilypond_args[:selected_parts] = part_names
|
77
|
+
if PARTS.any?
|
78
|
+
selected_parts = PARTS
|
79
|
+
else
|
80
|
+
selected_parts = score.parts.keys
|
65
81
|
end
|
66
82
|
|
67
83
|
print "Making Lilypond instructions..."
|
68
84
|
engraver = ScoreEngraver.new(score)
|
69
|
-
|
70
|
-
puts "done"
|
85
|
+
outfiles = {}
|
71
86
|
|
72
|
-
|
73
|
-
|
74
|
-
|
87
|
+
if SPLIT
|
88
|
+
selected_parts.each do |selected_part|
|
89
|
+
outfiles[selected_part] = engraver.make_lilypond([selected_part])
|
90
|
+
end
|
91
|
+
else
|
92
|
+
outfiles[""] = engraver.make_lilypond(selected_parts)
|
75
93
|
end
|
76
|
-
print "Writing Lilypond file '#{fout_name}'..."
|
77
|
-
File.write(fout_name, lilypond_text)
|
78
94
|
puts "done"
|
95
|
+
|
96
|
+
base_fout_name = "#{OUTDIR}/#{File.basename(SCORE_FILE,File.extname(SCORE_FILE))}"
|
97
|
+
outfiles.each do |outfile, lilypond_text|
|
98
|
+
if outfile.empty?
|
99
|
+
fout_name = "#{base_fout_name}.ly"
|
100
|
+
else
|
101
|
+
fout_name = "#{base_fout_name}_#{outfile}.ly"
|
102
|
+
end
|
103
|
+
print "Writing Lilypond file '#{fout_name}'..."
|
104
|
+
File.write(fout_name, lilypond_text)
|
105
|
+
puts "done"
|
106
|
+
end
|
79
107
|
else
|
80
108
|
puts "Score is not valid. See errors:"
|
81
109
|
puts score.errors.join("\n")
|