musicality 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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")
|