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
@@ -17,54 +17,38 @@ describe NoteSequenceExtractor do
17
17
  extr.notes.size.should eq 3
18
18
  end
19
19
 
20
- it 'should remove any bad ties (tying pitch does not exist in next note' do
20
+ it 'should remove any links where the source pitch does not exist in the note' do
21
21
  extr = NoteSequenceExtractor.new(
22
- [ Note.quarter([C4,E4], links: {C4 => Link::Tie.new}),
23
- Note.quarter([E4]) ]
22
+ [ Note.quarter([E4], links: {C4 => Link::Tie.new}),
23
+ Note.quarter([C4,E4]) ]
24
24
  )
25
25
  extr.notes[0].links.should_not have_key(C4)
26
- end
27
26
 
28
- it 'should replace any good ties with slurs' do
29
27
  extr = NoteSequenceExtractor.new(
30
- [ Note.quarter([C4,E4], links: {C4 => Link::Tie.new, E4 => Link::Tie.new}),
31
- Note.quarter([C4,E4]) ]
28
+ [ Note.quarter([E4], links: {C4 => Link::Glissando.new(G4)}),
29
+ Note.quarter([C4,E4,G4]) ]
32
30
  )
33
- extr.notes[0].links[C4].should be_a Link::Slur
34
- extr.notes[0].links[E4].should be_a Link::Slur
35
- end
31
+ extr.notes[0].links.should_not have_key(C4)
36
32
 
37
- it 'should remove dead slur/legato (where target pitch is non-existent)' do
38
33
  extr = NoteSequenceExtractor.new(
39
- [ Note.quarter([C4,E4], links: { C4 => Link::Slur.new(D4), E4 => Link::Legato.new(F4) }),
40
- Note.quarter([C4]) ]
34
+ [ Note.quarter([E4], links: {C4 => Link::Portamento.new(G4)}),
35
+ Note.quarter([C4,E4,G4]) ]
41
36
  )
42
- extr.notes[0].links.should be_empty
37
+ extr.notes[0].links.should_not have_key(C4)
43
38
  end
44
39
 
45
- it 'should remove any link where the source pitch is missing' do
40
+ it 'should keep glissando/portamento links even when the target pitch does not exist in the next note.' do
46
41
  extr = NoteSequenceExtractor.new(
47
- [ Note.quarter([C4,D4,E4,F4,G4], links: {
48
- Bb4 => Link::Tie.new, Db4 => Link::Slur.new(C4),
49
- Eb4 => Link::Legato.new(D4), Gb4 => Link::Glissando.new(E4),
50
- Ab5 => Link::Portamento.new(F4)
51
- }),
52
- Note.quarter([C4,D4,E4,F4,G4])
53
- ])
54
- extr.notes[0].links.should be_empty
55
- end
42
+ [ Note.quarter([C4], links: {C4 => Link::Glissando.new(G4)}),
43
+ Note.quarter([E4]) ]
44
+ )
45
+ extr.notes[0].links.should have_key(C4)
56
46
 
57
- it 'should not remove portamento and glissando with non-existent target pitches' do
58
47
  extr = NoteSequenceExtractor.new(
59
- [ Note.quarter([C4,D4]),
60
- Note.quarter([C4,D4,E4,F4,G4], links: {
61
- C4 => Link::Tie.new, D4 => Link::Slur.new(Eb4),
62
- E4 => Link::Legato.new(Gb4), F4 => Link::Glissando.new(A5),
63
- G4 => Link::Portamento.new(Bb5)}) ]
48
+ [ Note.quarter([C4], links: {C4 => Link::Portamento.new(G4)}),
49
+ Note.quarter([E4]) ]
64
50
  )
65
- extr.notes[-1].links.size.should eq 2
66
- extr.notes[-1].links.should have_key(F4)
67
- extr.notes[-1].links.should have_key(G4)
51
+ extr.notes[0].links.should have_key(C4)
68
52
  end
69
53
  end
70
54
 
@@ -94,18 +78,19 @@ describe NoteSequenceExtractor do
94
78
  @seqs.size.should eq 1
95
79
  end
96
80
 
97
- it 'should start offset 0' do
81
+ it 'should have start offset of 0' do
98
82
  @seqs[0].start.should eq 0
99
83
  end
100
84
 
101
- it 'should stop offset <= note duration' do
85
+ it 'should have stop offset <= note duration' do
102
86
  @seqs[0].stop.should be <= @note.duration
103
87
  end
104
88
  end
105
89
 
106
90
  context 'array with two slurred notes, single pitch' do
107
91
  before :all do
108
- @notes = [ Note.quarter([C5], articulation: SLUR), Note.quarter([D5]) ]
92
+ @notes = [ Note.quarter([C5], marks: [BEGIN_SLUR]),
93
+ Note.quarter([D5], marks: [END_SLUR]) ]
109
94
  @seqs = NoteSequenceExtractor.new(@notes).extract_sequences
110
95
  end
111
96
 
@@ -113,11 +98,11 @@ describe NoteSequenceExtractor do
113
98
  @seqs.size.should eq 1
114
99
  end
115
100
 
116
- it 'should start offset 0' do
101
+ it 'should have start offset of 0' do
117
102
  @seqs[0].start.should eq 0
118
103
  end
119
104
 
120
- it 'should stop offset <= combined duration of the two notes' do
105
+ it 'should have stop offset <= combined duration of the two notes' do
121
106
  @seqs[0].stop.should be <= (@notes[0].duration + @notes[1].duration)
122
107
  end
123
108
  end
@@ -140,32 +125,42 @@ describe NoteSequenceExtractor do
140
125
  @seqs.each {|s| s.stop.should be <= @note.duration }
141
126
  end
142
127
 
143
- it 'should put one pitch in each seq' do
144
- @seqs.each {|s| s.pitches.size.should eq(1) }
128
+ it 'should put one element in each seq' do
129
+ @seqs.each {|s| s.elements.size.should eq(1) }
145
130
  end
146
131
 
147
132
  it 'should assign a different pitch to each' do
148
- @seqs.map {|seq| seq.pitches[0] }.sort.should eq @note.pitches.sort
133
+ @seqs.map {|seq| seq.elements.first.pitch }.sort.should eq @note.pitches.sort
149
134
  end
150
135
  end
151
136
 
152
137
  context 'array with multiple notes and links' do
153
138
  before :all do
154
- @notes = [ Note.quarter([C3,E3], links: {
155
- C3 => Link::Slur.new(D3), E3 => Link::Legato.new(F3)}),
156
- Note.eighth([D3,F3]) ]
139
+ @notes = [
140
+ Note.quarter([C3,E3], links: { C3 => Link::Tie.new,
141
+ E3 => Link::Glissando.new(G3)}),
142
+ Note.eighth([C3,G3])
143
+ ]
157
144
  @seqs = NoteSequenceExtractor.new(@notes).extract_sequences
158
145
  end
159
146
 
160
- it 'should create a sequence for linked notes' do
147
+ it 'should create a single sequence for linked notes' do
161
148
  @seqs.size.should eq(2)
162
149
  end
163
150
 
164
- it 'should add pitch at 0 from first note' do
165
- @seqs[0].pitches.should have_key(0)
166
- @notes[0].pitches.should include(@seqs[0].pitches[0])
167
- @seqs[1].pitches.should have_key(0)
168
- @notes[0].pitches.should include(@seqs[1].pitches[0])
151
+ it 'should set first element pitch to match first note' do
152
+ @seqs[0].elements.first.pitch.should eq(@notes[0].pitches[0])
153
+ @seqs[1].elements.first.pitch.should eq(@notes[0].pitches[1])
154
+ end
155
+
156
+ it 'should collapse tie link to a single element' do
157
+ @seqs[0].elements.size.should eq(1)
158
+ @seqs[0].duration.should be <= (@notes[0].duration + @notes[1].duration)
159
+ end
160
+
161
+ it 'should expand the glissando into multiple elements' do
162
+ @seqs[1].elements.size.should be > 2
163
+ @seqs[1].duration.should be <= (@notes[0].duration + @notes[1].duration)
169
164
  end
170
165
  end
171
166
 
@@ -180,7 +175,7 @@ describe NoteSequenceExtractor do
180
175
  end
181
176
 
182
177
  it 'should include pitches up to (not including) target pitch' do
183
- @seqs[0].pitches.values.should include(D3,Eb3,E3,F3,Gb3)
178
+ @seqs[0].elements.map{|e| e.pitch}.should include(D3,Eb3,E3,F3,Gb3)
184
179
  end
185
180
 
186
181
  it 'should produce sequence with duration <= note duration' do
@@ -199,7 +194,7 @@ describe NoteSequenceExtractor do
199
194
  end
200
195
 
201
196
  it 'should include pitches down to (not including) target pitch' do
202
- @seqs[0].pitches.values.should include(D3,Db3,C3,B2,Bb2)
197
+ @seqs[0].elements.map{|e| e.pitch}.should include(D3,Db3,C3,B2,Bb2)
203
198
  end
204
199
 
205
200
  it 'should produce sequence with duration <= note duration' do
@@ -219,7 +214,7 @@ describe NoteSequenceExtractor do
219
214
  end
220
215
 
221
216
  it 'should includes pitches up through target pitch' do
222
- @seqs[0].pitches.values.should include(D3,Eb3,E3,F3,Gb3,G3)
217
+ @seqs[0].elements.map{|e| e.pitch}.should include(D3,Eb3,E3,F3,Gb3,G3)
223
218
  end
224
219
 
225
220
  it 'should produce sequence with duration <= note1dur + note2dur' do
@@ -68,12 +68,12 @@ describe PortamentoConverter do
68
68
  describe '.portamento_elements' do
69
69
  before :all do
70
70
  @dur = Rational(3,2)
71
- @acc = false
72
- @els = PortamentoConverter.portamento_elements(C4,F4,25,@dur,@acc)
71
+ @att = Attack::NONE
72
+ @els = PortamentoConverter.portamento_elements(C4,F4,25,@dur,@att)
73
73
  end
74
74
 
75
- it 'should return an array of SlurredElement objects' do
76
- @els.each {|el| el.should be_a SlurredElement }
75
+ it 'should return an array of NoteSequence::Element objects' do
76
+ @els.each {|el| el.should be_a NoteSequence::Element }
77
77
  end
78
78
 
79
79
  it 'should split up duration among elements' do
@@ -81,11 +81,13 @@ describe PortamentoConverter do
81
81
  sum.should eq(@dur)
82
82
  end
83
83
 
84
- it 'should set accented as given' do
85
- els = PortamentoConverter.portamento_elements(C4,D4,10,1,false)
86
- els.each {|el| el.accented.should eq(false) }
87
- els = PortamentoConverter.portamento_elements(C4,D4,10,1,true)
88
- els.each {|el| el.accented.should eq(true) }
84
+ it 'should set attack as given for first element only and set others to NONE' do
85
+ els = PortamentoConverter.portamento_elements(C4,D4,10,1,Attack::ACCENT)
86
+ els.first.attack.should eq(Attack::ACCENT)
87
+ els[1..-1].each {|el| el.attack.should eq(Attack::NONE) }
88
+ els = PortamentoConverter.portamento_elements(C4,D4,10,1,Attack::TENUTO)
89
+ els.first.attack.should eq(Attack::TENUTO)
90
+ els[1..-1].each {|el| el.attack.should eq(Attack::NONE) }
89
91
  end
90
92
  end
91
93
  end
@@ -13,31 +13,31 @@ describe ScoreCollator do
13
13
  context 'first note starts before the segment start' do
14
14
  context 'first note ends right at segment start' do
15
15
  it 'should not be included in the part' do
16
- score = Score::Measured.new(FOUR_FOUR, 120,
16
+ score = Score::Tempo.new(FOUR_FOUR, 120,
17
17
  parts: {1 => @part},
18
18
  program: ["1/4".to_r..."5/4".to_r])
19
19
  collator = ScoreCollator.new(score)
20
20
  parts = collator.collate_parts
21
21
  notes = parts[1].notes
22
- notes.size.should eq(@part.notes.size - 1)
23
- notes[0].pitches[0].should eq D2
24
- notes[1].pitches[0].should eq E2
22
+ expect(notes.size).to eq(@part.notes.size - 1)
23
+ expect(notes[0].pitches[0]).to eq D2
24
+ expect(notes[1].pitches[0]).to eq E2
25
25
  end
26
26
  end
27
27
 
28
28
  context 'first note ends after segment start' do
29
29
  it 'should not be included in the part, and a rest is inserted' do
30
- score = Score::Measured.new(FOUR_FOUR, 120,
30
+ score = Score::Tempo.new(FOUR_FOUR, 120,
31
31
  parts: {1 => @part},
32
32
  program: ["1/8".to_r..."5/4".to_r])
33
33
  collator = ScoreCollator.new(score)
34
34
  parts = collator.collate_parts
35
35
  notes = parts[1].notes
36
- notes.size.should eq(@part.notes.size)
37
- notes[0].pitches.should be_empty
38
- notes[0].duration.should eq "1/8".to_r
39
- notes[1].pitches[0].should eq D2
40
- notes[2].pitches[0].should eq E2
36
+ expect(notes.size).to eq(@part.notes.size)
37
+ expect(notes[0].pitches).to be_empty
38
+ expect(notes[0].duration).to eq "1/8".to_r
39
+ expect(notes[1].pitches[0]).to eq D2
40
+ expect(notes[2].pitches[0]).to eq E2
41
41
  end
42
42
  end
43
43
  end
@@ -45,47 +45,47 @@ describe ScoreCollator do
45
45
  context 'first note starts at segment start' do
46
46
  context 'last note starts at program end' do
47
47
  it 'should not be included in the part' do
48
- score = Score::Measured.new(FOUR_FOUR, 120,
48
+ score = Score::Tempo.new(FOUR_FOUR, 120,
49
49
  parts: {1 => @part},
50
50
  program: [0.to_r..."3/4".to_r])
51
51
  collator = ScoreCollator.new(score)
52
52
  parts = collator.collate_parts
53
53
  notes = parts[1].notes
54
- notes.size.should eq(@part.notes.size - 1)
54
+ expect(notes.size).to eq(@part.notes.size - 1)
55
55
  end
56
56
  end
57
57
 
58
58
  context 'last note start before program end, but lasts until after' do
59
59
  it 'should be included in the part, but truncated' do
60
- score = Score::Measured.new(FOUR_FOUR, 120,
60
+ score = Score::Tempo.new(FOUR_FOUR, 120,
61
61
  parts: {1 => @part},
62
62
  program: [0.to_r...1.to_r])
63
63
  collator = ScoreCollator.new(score)
64
64
  parts = collator.collate_parts
65
65
  notes = parts[1].notes
66
- notes.size.should eq(@part.notes.size)
67
- notes[-1].duration.should eq("1/4".to_r)
66
+ expect(notes.size).to eq(@part.notes.size)
67
+ expect(notes[-1].duration).to eq("1/4".to_r)
68
68
  end
69
69
  end
70
70
 
71
71
  context 'last note ends before program segment end' do
72
72
  it 'should insert a rest between last note end and segment end' do
73
- score = Score::Measured.new(FOUR_FOUR, 120,
73
+ score = Score::Tempo.new(FOUR_FOUR, 120,
74
74
  parts: {1 => @part},
75
75
  program: [0.to_r..."6/4".to_r])
76
76
  collator = ScoreCollator.new(score)
77
77
  parts = collator.collate_parts
78
78
  notes = parts[1].notes
79
- notes.size.should eq(@part.notes.size + 1)
80
- notes[-1].pitches.should be_empty
81
- notes[-1].duration.should eq("1/4".to_r)
79
+ expect(notes.size).to eq(@part.notes.size + 1)
80
+ expect(notes[-1].pitches).to be_empty
81
+ expect(notes[-1].duration).to eq("1/4".to_r)
82
82
  end
83
83
  end
84
84
  end
85
85
 
86
86
  context 'part contains trimmed gradual changes' do
87
87
  it 'should exclude the change when it is not at all in a program segment' do
88
- score = Score::Measured.new(FOUR_FOUR, 120,
88
+ score = Score::Tempo.new(FOUR_FOUR, 120,
89
89
  parts: { 1 => Part.new(Dynamics::FF, dynamic_changes: {
90
90
  2 => Change::Gradual.linear(Dynamics::PP,5).trim(1,0)
91
91
  }) },
@@ -94,19 +94,19 @@ describe ScoreCollator do
94
94
  collator = ScoreCollator.new(score)
95
95
  parts = collator.collate_parts
96
96
  dcs = parts[1].dynamic_changes
97
- dcs.size.should eq(1)
98
- dcs[0.to_r].should eq(Change::Immediate.new(Dynamics::PP))
97
+ expect(dcs.size).to eq(0)
98
+ expect(parts[1].start_dynamic).to be_within(1e-5).of(Dynamics::PP)
99
99
 
100
100
  score.program = [0...1]
101
101
  collator = ScoreCollator.new(score)
102
102
  parts = collator.collate_parts
103
103
  dcs = parts[1].dynamic_changes
104
- dcs.size.should eq(1)
105
- dcs[0.to_r].should eq(Change::Immediate.new(Dynamics::FF))
104
+ expect(dcs.size).to eq(0)
105
+ expect(parts[1].start_dynamic).to be_within(1e-5).of(Dynamics::FF)
106
106
  end
107
107
 
108
108
  it 'should trim the change further if needed' do
109
- score = Score::Measured.new(FOUR_FOUR, 120,
109
+ score = Score::Tempo.new(FOUR_FOUR, 120,
110
110
  parts: { 1 => Part.new(Dynamics::FF, dynamic_changes: {
111
111
  2 => Change::Gradual.linear(Dynamics::PP,5).trim(1,1)
112
112
  }) },
@@ -115,14 +115,14 @@ describe ScoreCollator do
115
115
  collator = ScoreCollator.new(score)
116
116
  parts = collator.collate_parts
117
117
  dcs = parts[1].dynamic_changes
118
- dcs.size.should eq(1)
119
- dcs[0.to_r].should eq(Change::Gradual.linear(Dynamics::PP,5).trim(2,2))
118
+ expect(dcs.size).to eq(1)
119
+ expect(dcs[0.to_r]).to eq(Change::Gradual.linear(Dynamics::PP,5).trim(2,2))
120
120
  end
121
121
  end
122
122
 
123
123
  it 'should preserve links' do
124
- notes = Note.split_parse("1Db4~Bb4")
125
- score = Score::Measured.new(
124
+ notes = Note.split_parse("1Db4;Bb4")
125
+ score = Score::Tempo.new(
126
126
  FOUR_FOUR,120,
127
127
  parts: { "lead" => Part.new(Dynamics::MP, notes: notes) },
128
128
  program: [0..1,0..1],
@@ -131,10 +131,10 @@ describe ScoreCollator do
131
131
  parts = collator.collate_parts
132
132
 
133
133
  notes = parts["lead"].notes
134
- notes.size.should eq 2
134
+ expect(notes.size).to eq 2
135
135
  notes.each do |note|
136
- note.links.should have_key(Db4)
137
- note.links[Db4].should be_a Link::Glissando
136
+ expect(note.links).to have_key(Db4)
137
+ expect(note.links[Db4]).to be_a Link::Glissando
138
138
  end
139
139
  end
140
140
  end
@@ -148,59 +148,56 @@ describe ScoreCollator do
148
148
 
149
149
  context 'tempo change starts at end of program segment' do
150
150
  it 'should not be included in the tempo changes' do
151
- score = Score::Measured.new(FOUR_FOUR, 120, tempo_changes: {
152
- 1 => @change1, 2 => @change2 }, program: [0..2])
151
+ score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
152
+ 1 => @change1, 2 => @change2 }, program: [0...2])
153
153
  collator = ScoreCollator.new(score)
154
- tcs = collator.collate_tempo_changes
155
- tcs.size.should eq 2
156
- tcs[0.to_r].should eq @change0
157
- tcs[1.to_r].should eq @change1
154
+ st, tcs = collator.collate_tempo_changes
155
+ expect(tcs.size).to eq 1
156
+ expect(tcs[1.to_r]).to eq @change1
158
157
  end
159
158
  end
160
159
 
161
160
  context 'tempo change starts and ends before segment' do
162
161
  before :all do
163
- score = Score::Measured.new(FOUR_FOUR, 120, tempo_changes: {
162
+ score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
164
163
  2 => @change2 }, program: [4..5])
165
164
  collator = ScoreCollator.new(score)
166
- @tcs = collator.collate_tempo_changes
165
+ @st, @tcs = collator.collate_tempo_changes
167
166
  end
168
167
 
169
168
  it 'should not be included in the tempo changes' do
170
- @tcs.size.should eq 1
171
- @tcs[0.to_r].should be_a Change::Immediate
169
+ expect(@tcs.size).to eq 0
172
170
  end
173
171
 
174
- it 'should be used as starting tempo change end_value' do
175
- @tcs[0.to_r].end_value.should eq @change2.end_value
172
+ it 'should be used as start tempo' do
173
+ expect(@st).to be_within(1e-5).of @change2.end_value
176
174
  end
177
175
  end
178
176
 
179
177
  context 'tempo change starts before segment, but ends during segment' do
180
178
  it 'should e included in the tempo changes, but truncated' do
181
- score = Score::Measured.new(FOUR_FOUR, 120, tempo_changes: {
179
+ score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
182
180
  1.5.to_r => @change2 }, program: [2..4])
183
181
  collator = ScoreCollator.new(score)
184
- tcs = collator.collate_tempo_changes
185
- tcs.size.should eq 1
186
- tcs[0.to_r].should be_a Change::Gradual::Trimmed
187
- tcs[0.to_r].end_value.should eq @change2.end_value
188
- tcs[0.to_r].remaining.should eq(0.5)
182
+ st, tcs = collator.collate_tempo_changes
183
+ expect(tcs.size).to eq 1
184
+ expect(tcs[0.to_r]).to be_a Change::Gradual::Trimmed
185
+ expect(tcs[0.to_r].end_value).to eq @change2.end_value
186
+ expect(tcs[0.to_r].remaining).to eq(0.5)
189
187
  end
190
188
  end
191
189
 
192
190
  context 'tempo change starts during segment, lasts until after' do
193
191
  it 'should be included in the tempo changes, but truncated' do
194
- score = Score::Measured.new(FOUR_FOUR, 120, tempo_changes: {
192
+ score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
195
193
  1 => @change1, 2 => @change2 }, program: [0..2.5])
196
194
  collator = ScoreCollator.new(score)
197
- tcs = collator.collate_tempo_changes
198
- tcs.size.should eq 3
199
- tcs[0.to_r].should eq @change0
200
- tcs[1.to_r].should eq @change1
201
- tcs[2.to_r].should be_a Change::Gradual::Trimmed
202
- tcs[2.to_r].end_value.should eq @change2.end_value
203
- tcs[2.to_r].remaining.should eq(0.5)
195
+ st, tcs = collator.collate_tempo_changes
196
+ expect(tcs.size).to eq 2
197
+ expect(tcs[1.to_r]).to eq @change1
198
+ expect(tcs[2.to_r]).to be_a Change::Gradual::Trimmed
199
+ expect(tcs[2.to_r].end_value).to eq @change2.end_value
200
+ expect(tcs[2.to_r].remaining).to eq(0.5)
204
201
  end
205
202
  end
206
203
  end
@@ -210,13 +207,12 @@ describe ScoreCollator do
210
207
  change0 = Change::Immediate.new(FOUR_FOUR)
211
208
  change1 = Change::Immediate.new(THREE_FOUR)
212
209
  change2 = Change::Immediate.new(SIX_EIGHT)
213
- score = Score::Measured.new(FOUR_FOUR, 120, meter_changes: {
210
+ score = Score::Tempo.new(FOUR_FOUR, 120, meter_changes: {
214
211
  1 => change1, 2 => change2 }, program: [0...2])
215
212
  collator = ScoreCollator.new(score)
216
- tcs = collator.collate_meter_changes
217
- tcs.size.should eq 2
218
- tcs[0.to_r].should eq change0
219
- tcs[1.to_r].should eq change1
213
+ sm, mcs = collator.collate_meter_changes
214
+ expect(mcs.size).to eq 1
215
+ expect(mcs[1.to_r]).to eq change1
220
216
  end
221
217
  end
222
218
  end