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.
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")