musicality 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +27 -1
  3. data/README.md +153 -10
  4. data/bin/collidify +102 -0
  5. data/bin/lilify +57 -29
  6. data/bin/midify +64 -24
  7. data/bin/musicality +39 -0
  8. data/examples/composition/auto_counterpoint.rb +4 -5
  9. data/examples/composition/part_generator.rb +8 -2
  10. data/examples/composition/scale_exercise.rb +1 -1
  11. data/examples/notation/notes.rb +27 -0
  12. data/examples/notation/parts.rb +51 -0
  13. data/examples/notation/scores.rb +38 -0
  14. data/examples/notation/twinkle.rb +34 -0
  15. data/examples/notation/twinkle.score +33 -0
  16. data/lib/musicality.rb +46 -11
  17. data/lib/musicality/composition/dsl/score_dsl.rb +2 -2
  18. data/lib/musicality/composition/dsl/score_methods.rb +10 -7
  19. data/lib/musicality/notation/conversion/change_conversion.rb +1 -1
  20. data/lib/musicality/notation/conversion/note_time_converter.rb +6 -23
  21. data/lib/musicality/notation/conversion/score_conversion.rb +15 -15
  22. data/lib/musicality/notation/conversion/score_converter.rb +50 -67
  23. data/lib/musicality/notation/model/articulations.rb +3 -2
  24. data/lib/musicality/notation/model/change.rb +15 -6
  25. data/lib/musicality/notation/model/dynamics.rb +11 -8
  26. data/lib/musicality/notation/model/instrument.rb +61 -0
  27. data/lib/musicality/notation/model/instruments.rb +111 -0
  28. data/lib/musicality/notation/model/key.rb +137 -0
  29. data/lib/musicality/notation/model/keys.rb +37 -0
  30. data/lib/musicality/notation/model/link.rb +6 -19
  31. data/lib/musicality/notation/model/mark.rb +43 -0
  32. data/lib/musicality/notation/model/marks.rb +11 -0
  33. data/lib/musicality/notation/model/meter.rb +4 -0
  34. data/lib/musicality/notation/model/note.rb +42 -28
  35. data/lib/musicality/notation/model/part.rb +18 -5
  36. data/lib/musicality/notation/model/pitch.rb +13 -4
  37. data/lib/musicality/notation/model/score.rb +104 -66
  38. data/lib/musicality/notation/model/symbols.rb +16 -11
  39. data/lib/musicality/notation/parsing/articulation_parsing.rb +38 -38
  40. data/lib/musicality/notation/parsing/articulation_parsing.treetop +14 -14
  41. data/lib/musicality/notation/parsing/link_parsing.rb +6 -6
  42. data/lib/musicality/notation/parsing/link_parsing.treetop +3 -3
  43. data/lib/musicality/notation/parsing/mark_parsing.rb +138 -0
  44. data/lib/musicality/notation/parsing/mark_parsing.treetop +31 -0
  45. data/lib/musicality/notation/parsing/note_node.rb +19 -12
  46. data/lib/musicality/notation/parsing/note_parsing.rb +218 -87
  47. data/lib/musicality/notation/parsing/note_parsing.treetop +9 -5
  48. data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +7 -2
  49. data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.treetop +1 -1
  50. data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.rb +6 -4
  51. data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.treetop +1 -1
  52. data/lib/musicality/notation/util/function.rb +41 -18
  53. data/lib/musicality/packable.rb +156 -0
  54. data/lib/musicality/performance/conversion/glissando_converter.rb +2 -2
  55. data/lib/musicality/performance/conversion/note_sequence_extractor.rb +223 -70
  56. data/lib/musicality/performance/conversion/portamento_converter.rb +5 -2
  57. data/lib/musicality/performance/conversion/score_collator.rb +70 -64
  58. data/lib/musicality/performance/midi/midi_events.rb +3 -3
  59. data/lib/musicality/performance/midi/midi_settings.rb +127 -0
  60. data/lib/musicality/performance/midi/midi_util.rb +8 -2
  61. data/lib/musicality/performance/midi/part_sequencer.rb +19 -18
  62. data/lib/musicality/performance/midi/score_sequencer.rb +13 -9
  63. data/lib/musicality/performance/midi/score_sequencing.rb +5 -5
  64. data/lib/musicality/performance/model/attack.rb +8 -0
  65. data/lib/musicality/performance/model/duration_functions.rb +23 -0
  66. data/lib/musicality/performance/model/note_sequence.rb +52 -95
  67. data/lib/musicality/performance/model/separation.rb +10 -0
  68. data/lib/musicality/performance/supercollider/add_actions.rb +13 -0
  69. data/lib/musicality/performance/supercollider/bundle.rb +18 -0
  70. data/lib/musicality/performance/supercollider/conductor.rb +125 -0
  71. data/lib/musicality/performance/supercollider/group.rb +71 -0
  72. data/lib/musicality/performance/supercollider/message.rb +26 -0
  73. data/lib/musicality/performance/supercollider/node.rb +122 -0
  74. data/lib/musicality/performance/supercollider/performer.rb +123 -0
  75. data/lib/musicality/performance/supercollider/score_conducting.rb +17 -0
  76. data/lib/musicality/performance/supercollider/server.rb +8 -0
  77. data/lib/musicality/performance/supercollider/synth.rb +43 -0
  78. data/lib/musicality/performance/supercollider/synthdef.rb +57 -0
  79. data/lib/musicality/performance/supercollider/synthdef_settings.rb +23 -0
  80. data/lib/musicality/performance/supercollider/synthdefs.rb +1654 -0
  81. data/lib/musicality/{composition/model/pitch_class.rb → pitch_class.rb} +1 -1
  82. data/lib/musicality/{composition/model/pitch_classes.rb → pitch_classes.rb} +9 -9
  83. data/lib/musicality/printing/lilypond/clef.rb +12 -0
  84. data/lib/musicality/printing/lilypond/key_engraving.rb +9 -0
  85. data/lib/musicality/printing/lilypond/lilypond_settings.rb +105 -0
  86. data/lib/musicality/printing/lilypond/meter_engraving.rb +1 -1
  87. data/lib/musicality/printing/lilypond/note_engraving.rb +112 -30
  88. data/lib/musicality/printing/lilypond/part_engraver.rb +114 -3
  89. data/lib/musicality/printing/lilypond/pitch_class_engraving.rb +22 -0
  90. data/lib/musicality/printing/lilypond/pitch_engraving.rb +2 -15
  91. data/lib/musicality/printing/lilypond/score_engraver.rb +44 -73
  92. data/lib/musicality/printing/lilypond/score_engraving.rb +3 -3
  93. data/lib/musicality/project/create_tasks.rb +31 -0
  94. data/lib/musicality/project/file_cleaner.rb +19 -0
  95. data/lib/musicality/project/file_raker.rb +107 -0
  96. data/lib/musicality/project/load_config.rb +43 -0
  97. data/lib/musicality/project/project.rb +64 -0
  98. data/lib/musicality/version.rb +1 -1
  99. data/musicality.gemspec +3 -0
  100. data/spec/composition/util/random_sampler_spec.rb +1 -1
  101. data/spec/notation/conversion/measure_note_map_spec.rb +1 -1
  102. data/spec/notation/conversion/note_time_converter_spec.rb +5 -85
  103. data/spec/notation/conversion/score_conversion_spec.rb +6 -41
  104. data/spec/notation/conversion/score_converter_spec.rb +19 -137
  105. data/spec/notation/model/change_spec.rb +55 -0
  106. data/spec/notation/model/key_spec.rb +171 -0
  107. data/spec/notation/model/link_spec.rb +34 -5
  108. data/spec/notation/model/meter_spec.rb +15 -0
  109. data/spec/notation/model/note_spec.rb +33 -27
  110. data/spec/notation/model/part_spec.rb +53 -4
  111. data/spec/notation/model/pitch_spec.rb +15 -0
  112. data/spec/notation/model/score_spec.rb +64 -72
  113. data/spec/notation/parsing/link_nodes_spec.rb +3 -3
  114. data/spec/notation/parsing/link_parsing_spec.rb +6 -6
  115. data/spec/notation/parsing/note_node_spec.rb +34 -9
  116. data/spec/notation/parsing/note_parsing_spec.rb +11 -9
  117. data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +4 -0
  118. data/spec/notation/parsing/pitch_node_spec.rb +0 -1
  119. data/spec/notation/util/value_computer_spec.rb +2 -2
  120. data/spec/performance/conversion/glissando_converter_spec.rb +9 -9
  121. data/spec/performance/conversion/note_sequence_extractor_spec.rb +48 -53
  122. data/spec/performance/conversion/portamento_converter_spec.rb +11 -9
  123. data/spec/performance/conversion/score_collator_spec.rb +59 -63
  124. data/spec/performance/midi/midi_util_spec.rb +22 -8
  125. data/spec/performance/midi/part_sequencer_spec.rb +2 -2
  126. data/spec/performance/midi/score_sequencer_spec.rb +12 -10
  127. data/spec/performance/midi/score_sequencing_spec.rb +2 -2
  128. data/spec/performance/model/note_sequence_spec.rb +41 -134
  129. data/spec/printing/note_engraving_spec.rb +204 -0
  130. data/spec/printing/score_engraver_spec.rb +40 -0
  131. data/spec/spec_helper.rb +1 -0
  132. metadata +69 -23
  133. data/examples/notation/hip.rb +0 -32
  134. data/examples/notation/missed_connection.rb +0 -26
  135. data/examples/notation/song1.rb +0 -33
  136. data/examples/notation/song2.rb +0 -32
  137. data/lib/musicality/notation/model/links.rb +0 -11
  138. data/lib/musicality/notation/packing/change_packing.rb +0 -56
  139. data/lib/musicality/notation/packing/part_packing.rb +0 -31
  140. data/lib/musicality/notation/packing/score_packing.rb +0 -123
  141. data/lib/musicality/performance/model/note_attacks.rb +0 -19
  142. data/lib/musicality/performance/util/note_linker.rb +0 -28
  143. data/spec/notation/packing/change_packing_spec.rb +0 -304
  144. data/spec/notation/packing/part_packing_spec.rb +0 -66
  145. data/spec/notation/packing/score_packing_spec.rb +0 -255
  146. 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: 1b76956290ba2ff351587624b43db12c84fc99a5
4
- data.tar.gz: 02460a5a7b390c335ffac5c8050b76bb280fd149
3
+ metadata.gz: a2ca1d5317ab9f47ee4a5a48391c529b6db3dc80
4
+ data.tar.gz: 61306cd02de6089beb8ebfd71617cefbafb7a1ee
5
5
  SHA512:
6
- metadata.gz: ed2d94a4bd155e24a072481ed45027b362475c68628d41be6cf1e565e08636564fd71375f01936fbb74a7fe13dfcd5bcd22649117b76e5d179ffa83d19031d53
7
- data.tar.gz: 05d65518d4f9d8abb5bda61490cdfa18d4458148648b46f6edc4ba518d10caaf6f12c9dea74522cc4615fd650441a0892e43057928d97b358dcdc2eacc6d540a
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 `Timed` and `TempoBased` scores.
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
- Raw notation objects can be created like this:
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
- twinkle = Score::Measured.new(TWO_FOUR, 120) do |s|
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
- p.notes += ("/4C4 "*2 + "/4G4 "*2 +
51
- "/4A4 "*2 + "/2G4").to_notes
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
- p.notes += ("/2C3,E3,G3 "*2 +
55
- "/2F2,A2,C3 /2C3,E3,G3").to_notes
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 using the `ScoreSequencer` class or `#to_midi_seq` method. To continue the previous example,
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'){ |fout| seq.write(fout) }
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
- measured_score FOUR_FOUR, 120 do
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 a Lilypond file for engraving.
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} <input> [PART TITLE] ... [options]
14
+ #{exe_name} SCORE [PART]... [options]
10
15
  #{exe_name} -h | --help
11
16
  #{exe_name} --version
12
17
 
13
18
  Arguments:
14
- input A musicality score file (may be packed as a hash) in YAML format
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
- --all Select all parts for engraving, and use part name as the title if not given
20
- -h --help Show this screen.
21
- --version Show version.
22
- --outfile=OUTF Name of output Lilypond file
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
- fin_name = args["<input>"]
46
- File.open(fin_name) do |fin|
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 = Score.unpack(score)
72
+ score = score.unpack
52
73
  end
53
74
  puts "done"
54
75
 
55
76
  if score.valid?
56
- part_names = args["PART"]
57
- part_titles = args["TITLE"]
58
- name_title_map =
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
- lilypond_text = engraver.make_lilypond(make_lilypond_args)
70
- puts "done"
85
+ outfiles = {}
71
86
 
72
- fout_name = args["--outfile"]
73
- if fout_name.nil?
74
- fout_name = "#{File.dirname(fin_name)}/#{File.basename(fin_name,File.extname(fin_name))}.ly"
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")