musicality 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +13 -3
  3. data/README.md +8 -8
  4. data/bin/auditions +241 -0
  5. data/bin/collidify +4 -2
  6. data/bin/musicality +13 -2
  7. data/examples/composition/auto_counterpoint.rb +4 -4
  8. data/examples/composition/part_generator.rb +6 -6
  9. data/examples/composition/scale_exercise.rb +5 -5
  10. data/examples/notation/scores.rb +2 -2
  11. data/examples/notation/twinkle.rb +6 -6
  12. data/examples/notation/twinkle.score +3 -3
  13. data/lib/musicality.rb +6 -4
  14. data/lib/musicality/composition/dsl/part_methods.rb +12 -0
  15. data/lib/musicality/composition/dsl/score_dsl.rb +4 -4
  16. data/lib/musicality/composition/dsl/score_methods.rb +8 -2
  17. data/lib/musicality/notation/model/audition.rb +16 -0
  18. data/lib/musicality/notation/model/score.rb +31 -30
  19. data/lib/musicality/performance/supercollider/conductor.rb +2 -2
  20. data/lib/musicality/performance/supercollider/synthdefs.rb +30 -29
  21. data/lib/musicality/project/auditions_task.rb +28 -0
  22. data/lib/musicality/project/create_tasks.rb +15 -9
  23. data/lib/musicality/project/file_cleaner.rb +22 -5
  24. data/lib/musicality/project/file_raker.rb +29 -21
  25. data/lib/musicality/project/project.rb +218 -32
  26. data/lib/musicality/version.rb +1 -1
  27. data/musicality.gemspec +6 -4
  28. data/spec/composition/dsl/part_methods_spec.rb +24 -0
  29. data/spec/notation/conversion/score_conversion_spec.rb +2 -1
  30. data/spec/notation/conversion/score_converter_spec.rb +23 -23
  31. data/spec/notation/model/score_spec.rb +66 -46
  32. data/spec/performance/conversion/score_collator_spec.rb +29 -29
  33. data/spec/performance/midi/score_sequencing_spec.rb +5 -5
  34. metadata +10 -8
  35. data/lib/musicality/project/load_config.rb +0 -58
@@ -1,3 +1,3 @@
1
1
  module Musicality
2
- VERSION = "0.10.1"
2
+ VERSION = "0.11.0"
3
3
  end
data/musicality.gemspec CHANGED
@@ -9,9 +9,11 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["James Tunnell"]
10
10
  spec.email = ["jamestunnell@gmail.com"]
11
11
  spec.summary = %q{Music notation, composition, and performance}
12
- spec.description = %q{The library is based around an abstract representation for music notation. \
13
- From here, functions are built up to make composing elaborate pieces in this notation representation more manageable. \
14
- Finally, music performance is supported by providing translation to common formats, like MIDI. }
12
+ spec.description = "The library is based around an abstract representation "
13
+ "for music notation, including pitch, note, dynamic, score, etc. A Ruby-based "
14
+ "DSL is provided to aid in composition. Scores can be converted to common "
15
+ "formats, like MIDI and LilyPond. Scores can also be rendered as audio via "
16
+ "SuperCollider."
15
17
  spec.homepage = "https://github.com/jamestunnell/musicality"
16
18
  spec.license = "MIT"
17
19
 
@@ -24,7 +26,7 @@ Gem::Specification.new do |spec|
24
26
  spec.add_development_dependency "rake", "~> 10.0"
25
27
  spec.add_development_dependency "rspec", "~> 2.9"
26
28
  spec.add_development_dependency "pry"
27
-
29
+
28
30
  spec.add_dependency "treetop", "~> 1.5"
29
31
  spec.add_dependency 'midilib', '~> 2.0'
30
32
  spec.add_dependency 'docopt', '~> 0.5'
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe Part do
4
+ describe '#dynamic_change' do
5
+ before :each do
6
+ @part = Part.new(Dynamics::MP, notes: "/4 /4D4 /8C3 /16C3".to_notes)
7
+ end
8
+
9
+ context 'transition_dur is 0' do
10
+ context 'offset is 0' do
11
+ it 'should create an immediate dynamic change at the end of the part' do
12
+ @part.dynamic_change Dynamics::PP
13
+ expect(@part.dynamic_changes.size).to eq(1)
14
+ expect(@part.dynamic_changes).to have_key(@part.duration)
15
+ expect(@part.dynamic_changes.values.first).to eq Change::Immediate.new(Dynamics::PP)
16
+ end
17
+ end
18
+
19
+ context 'offset is not 0'
20
+ end
21
+
22
+ context 'transition_dur is not 0'
23
+ end
24
+ end
@@ -23,7 +23,8 @@ describe Score::Tempo do
23
23
  1 => Change::Immediate.new(TWO_FOUR),
24
24
  3 => Change::Immediate.new(SIX_EIGHT)
25
25
  }
26
- @score = Score::Tempo.new(THREE_FOUR, 120,
26
+ @score = Score::Tempo.new(120,
27
+ start_meter: THREE_FOUR,
27
28
  parts: @parts,
28
29
  program: @prog,
29
30
  tempo_changes: tcs,
@@ -4,27 +4,27 @@ describe ScoreConverter do
4
4
  describe '#initialize' do
5
5
  context 'current score is invalid' do
6
6
  it 'should raise NotValidError' do
7
- score = Score::Tempo.new(1, 120)
7
+ score = Score::Tempo.new(120, start_meter: 1)
8
8
  expect { ScoreConverter.new(score,200) }.to raise_error(NotValidError)
9
9
  end
10
- end
10
+ end
11
11
  end
12
-
12
+
13
13
  describe '#convert_parts' do
14
14
  before :each do
15
15
  @changeA = Change::Immediate.new(Dynamics::PP)
16
16
  @changeB = Change::Gradual.linear(Dynamics::F, 2)
17
- @score = Score::Tempo.new(FOUR_FOUR, 120,
17
+ @score = Score::Tempo.new(120, start_meter: FOUR_FOUR,
18
18
  parts: {"simple" => Part.new(Dynamics::MP, dynamic_changes: { 1 => @changeA, 3 => @changeB })}
19
19
  )
20
20
  end
21
-
21
+
22
22
  it 'should return Hash with original part names' do
23
23
  parts = ScoreConverter.new(@score,200).convert_parts
24
24
  parts.should be_a Hash
25
25
  parts.keys.sort.should eq(@score.parts.keys.sort)
26
26
  end
27
-
27
+
28
28
  it 'should convert part dynamic change offsets from note-based to time-based' do
29
29
  parts = ScoreConverter.new(@score,200).convert_parts
30
30
  parts.should have_key("simple")
@@ -35,7 +35,7 @@ describe ScoreConverter do
35
35
  change = part.dynamic_changes[6.0]
36
36
  change.end_value.should eq(@changeB.end_value)
37
37
  change.duration.should eq(4)
38
-
38
+
39
39
  @score.start_meter = THREE_FOUR
40
40
  parts = ScoreConverter.new(@score,200).convert_parts
41
41
  parts.should have_key("simple")
@@ -48,10 +48,10 @@ describe ScoreConverter do
48
48
  change.end_value.should eq(@changeB.end_value)
49
49
  change.duration.should eq(4)
50
50
  end
51
-
51
+
52
52
  context 'gradual changes with positive elapsed and/or remaining' do
53
53
  it 'should change elapsed and remaining so they reflect time-based offsets' do
54
- score = Score::Tempo.new(THREE_FOUR,120, parts: {
54
+ score = Score::Tempo.new(120, start_meter: THREE_FOUR, parts: {
55
55
  "abc" => Part.new(Dynamics::P, dynamic_changes: {
56
56
  2 => Change::Gradual.linear(Dynamics::F,2).to_trimmed(1, 3),
57
57
  7 => Change::Gradual.linear(Dynamics::F,1).to_trimmed(4, 5)
@@ -60,27 +60,27 @@ describe ScoreConverter do
60
60
  converter = ScoreConverter.new(score, 200)
61
61
  parts = converter.convert_parts
62
62
  dcs = parts["abc"].dynamic_changes
63
-
63
+
64
64
  dcs.keys.should eq([4, 14])
65
65
  dcs[4.0].should eq(Change::Gradual.linear(Dynamics::F,4).to_trimmed(2,6))
66
66
  dcs[14.0].should eq(Change::Gradual.linear(Dynamics::F,2).to_trimmed(8,10))
67
67
  end
68
68
  end
69
69
  end
70
-
70
+
71
71
  describe '#convert_program' do
72
72
  before :each do
73
73
  @prog = [0...4,2...5]
74
- @score = Score::Tempo.new(FOUR_FOUR, 120, program: @prog)
74
+ @score = Score::Tempo.new(120, start_meter: FOUR_FOUR, program: @prog)
75
75
  @converter = ScoreConverter.new(@score,200)
76
76
  end
77
-
77
+
78
78
  it 'shuld return array with same size' do
79
79
  prog = @converter.convert_program
80
80
  prog.should be_a Array
81
81
  prog.size.should eq(@score.program.size)
82
82
  end
83
-
83
+
84
84
  it 'should convert program segments offsets from note-based to time-based' do
85
85
  prog = ScoreConverter.new(@score,200).convert_program
86
86
  prog.size.should eq(2)
@@ -88,7 +88,7 @@ describe ScoreConverter do
88
88
  prog[0].last.should eq(8)
89
89
  prog[1].first.should eq(4)
90
90
  prog[1].last.should eq(10)
91
-
91
+
92
92
  @score.start_meter = THREE_FOUR
93
93
  prog = ScoreConverter.new(@score,200).convert_program
94
94
  prog.size.should eq(2)
@@ -98,31 +98,31 @@ describe ScoreConverter do
98
98
  prog[1].last.should eq(10)
99
99
  end
100
100
  end
101
-
102
- describe '#convert_score' do
101
+
102
+ describe '#convert_score' do
103
103
  it 'should return a timed score' do
104
- score = Score::Tempo.new(FOUR_FOUR, 120)
104
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR)
105
105
  converter = ScoreConverter.new(score,200)
106
106
  converter.convert_score.should be_a Score::Timed
107
107
  end
108
-
108
+
109
109
  it 'should use output from convert_program' do
110
110
  prog =[0...4,2...5]
111
- score = Score::Tempo.new(FOUR_FOUR, 120, program: prog)
111
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR, program: prog)
112
112
  converter = ScoreConverter.new(score,200)
113
113
  nscore = converter.convert_score
114
114
  nscore.program.should eq(converter.convert_program)
115
115
  end
116
-
116
+
117
117
  it 'should use output from convert_parts' do
118
118
  changeA = Change::Immediate.new(Dynamics::PP)
119
119
  changeB = Change::Gradual.linear(Dynamics::F, 2)
120
- score = Score::Tempo.new(FOUR_FOUR, 120,
120
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR,
121
121
  parts: {"simple" => Part.new(Dynamics::MP, dynamic_changes: { 1 => changeA, 3 => changeB })}
122
122
  )
123
123
  converter = ScoreConverter.new(score,200)
124
124
  nscore = converter.convert_score
125
125
  nscore.parts.should eq(converter.convert_parts)
126
126
  end
127
- end
127
+ end
128
128
  end
@@ -38,24 +38,39 @@ describe Score do
38
38
  it 'should return false' do
39
39
  score = Score.new(program: [0..2,0..2])
40
40
  score.collated?.should be false
41
- end
41
+ end
42
42
  end
43
-
43
+
44
44
  context 'has program with 0 segments' do
45
45
  it 'should return false' do
46
46
  score = Score.new(program: [])
47
- score.collated?.should be false
47
+ score.collated?.should be false
48
48
  end
49
49
  end
50
-
50
+
51
51
  context 'has program with 1 segment' do
52
52
  context 'program segment starts at 0' do
53
- it 'should return true' do
54
- score = Score.new(program: [0..2])
55
- score.collated?.should be true
53
+ context 'program segment ends at score duration' do
54
+ it 'should return true' do
55
+ score = Score.new(program: [0..2],
56
+ parts: { "dummy" => Part.new(Dynamics::MP, notes: [Note.whole]*2)}
57
+ )
58
+ score.collated?.should be true
59
+ end
60
+ end
61
+
62
+ context 'program segment does not end at score duration' do
63
+ it 'should return false' do
64
+ score = Score.new(program: [0..1],
65
+ parts: { "dummy" => Part.new(Dynamics::MP, notes: [Note.whole]*2) }
66
+ )
67
+ score.collated?.should be false
68
+ score.program = [0..3]
69
+ score.collated?.should be false
70
+ end
56
71
  end
57
72
  end
58
-
73
+
59
74
  context 'program segment does not start at 0' do
60
75
  it 'should return false' do
61
76
  score = Score.new(program: [1..2])
@@ -64,20 +79,20 @@ describe Score do
64
79
  end
65
80
  end
66
81
  end
67
-
82
+
68
83
  describe '#valid?' do
69
84
  context 'non-Range objects' do
70
85
  it 'should return false' do
71
86
  Score.new(program: [1,2,3]).should_not be_valid
72
87
  end
73
88
  end
74
-
89
+
75
90
  context 'increasing, positive segments' do
76
91
  it 'should return true' do
77
92
  Score.new(program: [0..2,1..2,0..4]).should be_valid
78
93
  end
79
94
  end
80
-
95
+
81
96
  context 'decreasing, positive segments' do
82
97
  it 'should return false' do
83
98
  Score.new(program: [2..0,2..1,04..0]).should be_invalid
@@ -94,7 +109,8 @@ end
94
109
 
95
110
  describe Score::Tempo do
96
111
  before :all do
97
- @basic_score = Score::Tempo.new(TWO_FOUR, 120,
112
+ @basic_score = Score::Tempo.new(120,
113
+ start_meter: TWO_FOUR,
98
114
  meter_changes: {
99
115
  2 => Change::Immediate.new(FOUR_FOUR),
100
116
  4 => Change::Immediate.new(SIX_EIGHT),
@@ -109,52 +125,55 @@ describe Score::Tempo do
109
125
 
110
126
  describe '#initialize' do
111
127
  it 'should use empty containers for parameters not given' do
112
- s = Score::Tempo.new(FOUR_FOUR,120)
128
+ s = Score::Tempo.new(120)
113
129
  s.parts.should be_empty
114
130
  s.program.should be_empty
131
+ s.tempo_changes.should be_empty
132
+ s.meter_changes.should be_empty
115
133
  end
116
-
134
+
117
135
  it 'should assign given parameters' do
118
- m = FOUR_FOUR
119
- s = Score::Tempo.new(m,120)
120
- s.start_meter.should eq m
136
+ s = Score::Tempo.new(120)
121
137
  s.start_tempo.should eq 120
122
-
138
+
139
+ m = FOUR_FOUR
123
140
  parts = { "piano (LH)" => Samples::SAMPLE_PART }
124
141
  program = [0...0.75, 0...0.75]
125
142
  mcs = { 1 => Change::Immediate.new(THREE_FOUR) }
126
143
  tcs = { 1 => Change::Immediate.new(100) }
127
-
128
- s = Score::Tempo.new(m,120,
144
+
145
+ s = Score::Tempo.new(120,
146
+ start_meter: m,
129
147
  parts: parts,
130
148
  program: program,
131
149
  meter_changes: mcs,
132
150
  tempo_changes: tcs
133
151
  )
152
+ s.start_meter.should eq m
134
153
  s.parts.should eq parts
135
154
  s.program.should eq program
136
155
  s.meter_changes.should eq mcs
137
156
  s.tempo_changes.should eq tcs
138
157
  end
139
158
  end
140
-
159
+
141
160
  describe '#duration' do
142
161
  context 'with no parts' do
143
162
  it 'should return 0' do
144
- Score::Tempo.new(TWO_FOUR, 120).duration.should eq(0)
163
+ Score::Tempo.new(120).duration.should eq(0)
145
164
  end
146
165
  end
147
166
  context 'with one part' do
148
167
  it 'should return the duration of the part, in notes' do
149
- Score::Tempo.new(TWO_FOUR, 120, parts: {
168
+ Score::Tempo.new(120, parts: {
150
169
  "abc" => Part.new(Dynamics::MF, notes: "/4 /4 /2 3/4".to_notes)
151
170
  }).duration.should eq(1.75)
152
171
  end
153
172
  end
154
-
173
+
155
174
  context 'with two parts' do
156
175
  it 'should return the duration of the longest part, in notes' do
157
- Score::Tempo.new(TWO_FOUR, 120, parts: {
176
+ Score::Tempo.new(120, parts: {
158
177
  "abc" => Part.new(Dynamics::MF, notes: "/4 /4 /2 3/4".to_notes),
159
178
  "def" => Part.new(Dynamics::MF, notes: "/4 /4 /2 1".to_notes)
160
179
  }).duration.should eq(2)
@@ -164,13 +183,14 @@ describe Score::Tempo do
164
183
 
165
184
  describe '#valid?' do
166
185
  {
167
- 'valid start tempo' => [ FOUR_FOUR, 40 ],
168
- 'valid tempo changes' => [ FOUR_FOUR, 30,
186
+ 'valid start tempo' => [ 40 ],
187
+ 'valid tempo changes' => [ 30,
169
188
  :tempo_changes => { 1 => Change::Gradual.linear(40, 2), 2 => Change::Immediate.new(50) } ],
170
- 'valid meter changes' => [ FOUR_FOUR, 120,
189
+ 'valid start meter' => [80, :start_meter => FOUR_FOUR ],
190
+ 'valid meter changes' => [ 120,
171
191
  :meter_changes => { 1 => Change::Immediate.new(TWO_FOUR) } ],
172
- 'valid part' => [ FOUR_FOUR, 120, :parts => { "piano" => Samples::SAMPLE_PART }],
173
- 'valid program' => [ FOUR_FOUR, 120, :program => [0..2,0..2] ]
192
+ 'valid part' => [ 120, :parts => { "piano" => Samples::SAMPLE_PART }],
193
+ 'valid program' => [ 120, :program => [0..2,0..2] ]
174
194
  }.each do |context_str,args|
175
195
  context context_str do
176
196
  it 'should return true' do
@@ -178,26 +198,26 @@ describe Score::Tempo do
178
198
  end
179
199
  end
180
200
  end
181
-
201
+
182
202
  {
183
- 'start tempo object is negative' => [ FOUR_FOUR, -1],
184
- 'start tempo object is zero' => [ FOUR_FOUR, 0],
185
- 'invalid start meter' => [ Meter.new(-1,"1/4".to_r), 120],
186
- 'non-meter start meter' => [ 1, 120],
187
- 'invalid meter in change' => [ FOUR_FOUR, 120,
203
+ 'start tempo object is negative' => [ -1],
204
+ 'start tempo object is zero' => [ 0],
205
+ 'invalid start meter' => [ 120, :start_meter => Meter.new(-1,"1/4".to_r) ],
206
+ 'non-meter start meter' => [ 120, :start_meter => 1 ],
207
+ 'invalid meter in change' => [ 120,
188
208
  :meter_changes => { 1 => Change::Immediate.new(Meter.new(-2,"1/4".to_r)) } ],
189
- 'non-meter values in meter changes' => [ FOUR_FOUR, 120,
209
+ 'non-meter values in meter changes' => [ 120,
190
210
  :meter_changes => { 1 => Change::Immediate.new(5) } ],
191
- 'non-immediate meter change' => [ FOUR_FOUR, 120,
211
+ 'non-immediate meter change' => [ 120,
192
212
  :meter_changes => { 1 => Change::Gradual.linear(TWO_FOUR,1) } ],
193
- 'invalid part' => [ FOUR_FOUR, 120, :parts => { "piano" => Part.new(-0.1) }],
194
- 'invalid program' => [ FOUR_FOUR, 120, :program => [2..0] ],
213
+ 'invalid part' => [ 120, :parts => { "piano" => Part.new(-0.1) }],
214
+ 'invalid program' => [ 120, :program => [2..0] ],
195
215
  }.each do |context_str,args|
196
216
  context context_str do
197
217
  it 'should return false' do
198
218
  Score::Tempo.new(*args).should be_invalid
199
219
  end
200
- end
220
+ end
201
221
  end
202
222
  end
203
223
 
@@ -233,17 +253,17 @@ describe Score::Timed do
233
253
  s.parts.should be_empty
234
254
  s.program.should be_empty
235
255
  end
236
-
256
+
237
257
  it 'should assign given parameters' do
238
258
  parts = { "piano (LH)" => Samples::SAMPLE_PART }
239
259
  program = [0...0.75, 0...0.75]
240
-
260
+
241
261
  s = Score::Timed.new(parts: parts, program: program)
242
262
  s.parts.should eq parts
243
263
  s.program.should eq program
244
264
  end
245
265
  end
246
-
266
+
247
267
  describe '#duration' do
248
268
  it 'should return the duration of the longest part' do
249
269
  Score::Timed.new(parts: {
@@ -264,7 +284,7 @@ describe Score::Timed do
264
284
  end
265
285
  end
266
286
  end
267
-
287
+
268
288
  {
269
289
  'invalid part' => [ :parts => { "piano" => Part.new(-0.1) }],
270
290
  'invalid program' => [ :program => [2..0] ],
@@ -273,7 +293,7 @@ describe Score::Timed do
273
293
  it 'should return false' do
274
294
  Score::Timed.new(*args).should be_invalid
275
295
  end
276
- end
296
+ end
277
297
  end
278
298
  end
279
299
 
@@ -9,11 +9,11 @@ describe ScoreCollator do
9
9
  Note.half([E2])
10
10
  ])
11
11
  end
12
-
12
+
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::Tempo.new(FOUR_FOUR, 120,
16
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR,
17
17
  parts: {1 => @part},
18
18
  program: ["1/4".to_r..."5/4".to_r])
19
19
  collator = ScoreCollator.new(score)
@@ -24,10 +24,10 @@ describe ScoreCollator do
24
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::Tempo.new(FOUR_FOUR, 120,
30
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR,
31
31
  parts: {1 => @part},
32
32
  program: ["1/8".to_r..."5/4".to_r])
33
33
  collator = ScoreCollator.new(score)
@@ -41,11 +41,11 @@ describe ScoreCollator do
41
41
  end
42
42
  end
43
43
  end
44
-
44
+
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::Tempo.new(FOUR_FOUR, 120,
48
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR,
49
49
  parts: {1 => @part},
50
50
  program: [0.to_r..."3/4".to_r])
51
51
  collator = ScoreCollator.new(score)
@@ -54,10 +54,10 @@ describe ScoreCollator do
54
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::Tempo.new(FOUR_FOUR, 120,
60
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR,
61
61
  parts: {1 => @part},
62
62
  program: [0.to_r...1.to_r])
63
63
  collator = ScoreCollator.new(score)
@@ -67,10 +67,10 @@ describe ScoreCollator do
67
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::Tempo.new(FOUR_FOUR, 120,
73
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR,
74
74
  parts: {1 => @part},
75
75
  program: [0.to_r..."6/4".to_r])
76
76
  collator = ScoreCollator.new(score)
@@ -82,10 +82,10 @@ describe ScoreCollator do
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::Tempo.new(FOUR_FOUR, 120,
88
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR,
89
89
  parts: { 1 => Part.new(Dynamics::FF, dynamic_changes: {
90
90
  2 => Change::Gradual.linear(Dynamics::PP,5).trim(1,0)
91
91
  }) },
@@ -96,7 +96,7 @@ describe ScoreCollator do
96
96
  dcs = parts[1].dynamic_changes
97
97
  expect(dcs.size).to eq(0)
98
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
@@ -104,9 +104,9 @@ describe ScoreCollator do
104
104
  expect(dcs.size).to eq(0)
105
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::Tempo.new(FOUR_FOUR, 120,
109
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR,
110
110
  parts: { 1 => Part.new(Dynamics::FF, dynamic_changes: {
111
111
  2 => Change::Gradual.linear(Dynamics::PP,5).trim(1,1)
112
112
  }) },
@@ -119,17 +119,17 @@ describe ScoreCollator do
119
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
124
  notes = Note.split_parse("1Db4;Bb4")
125
125
  score = Score::Tempo.new(
126
- FOUR_FOUR,120,
126
+ 120, start_meter: FOUR_FOUR,
127
127
  parts: { "lead" => Part.new(Dynamics::MP, notes: notes) },
128
128
  program: [0..1,0..1],
129
129
  )
130
130
  collator = ScoreCollator.new(score)
131
131
  parts = collator.collate_parts
132
-
132
+
133
133
  notes = parts["lead"].notes
134
134
  expect(notes.size).to eq 2
135
135
  notes.each do |note|
@@ -138,17 +138,17 @@ describe ScoreCollator do
138
138
  end
139
139
  end
140
140
  end
141
-
141
+
142
142
  describe '#collate_tempo_changes' do
143
143
  before :all do
144
144
  @change0 = Change::Immediate.new(120)
145
145
  @change1 = Change::Immediate.new(200)
146
146
  @change2 = Change::Gradual.linear(100,1)
147
147
  end
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::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
151
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR, tempo_changes: {
152
152
  1 => @change1, 2 => @change2 }, program: [0...2])
153
153
  collator = ScoreCollator.new(score)
154
154
  st, tcs = collator.collate_tempo_changes
@@ -159,24 +159,24 @@ describe ScoreCollator do
159
159
 
160
160
  context 'tempo change starts and ends before segment' do
161
161
  before :all do
162
- score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
162
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR, tempo_changes: {
163
163
  2 => @change2 }, program: [4..5])
164
164
  collator = ScoreCollator.new(score)
165
165
  @st, @tcs = collator.collate_tempo_changes
166
166
  end
167
-
167
+
168
168
  it 'should not be included in the tempo changes' do
169
169
  expect(@tcs.size).to eq 0
170
170
  end
171
-
171
+
172
172
  it 'should be used as start tempo' do
173
173
  expect(@st).to be_within(1e-5).of @change2.end_value
174
174
  end
175
175
  end
176
-
176
+
177
177
  context 'tempo change starts before segment, but ends during segment' do
178
178
  it 'should e included in the tempo changes, but truncated' do
179
- score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
179
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR, tempo_changes: {
180
180
  1.5.to_r => @change2 }, program: [2..4])
181
181
  collator = ScoreCollator.new(score)
182
182
  st, tcs = collator.collate_tempo_changes
@@ -186,10 +186,10 @@ describe ScoreCollator do
186
186
  expect(tcs[0.to_r].remaining).to eq(0.5)
187
187
  end
188
188
  end
189
-
189
+
190
190
  context 'tempo change starts during segment, lasts until after' do
191
191
  it 'should be included in the tempo changes, but truncated' do
192
- score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
192
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR, tempo_changes: {
193
193
  1 => @change1, 2 => @change2 }, program: [0..2.5])
194
194
  collator = ScoreCollator.new(score)
195
195
  st, tcs = collator.collate_tempo_changes
@@ -207,7 +207,7 @@ describe ScoreCollator do
207
207
  change0 = Change::Immediate.new(FOUR_FOUR)
208
208
  change1 = Change::Immediate.new(THREE_FOUR)
209
209
  change2 = Change::Immediate.new(SIX_EIGHT)
210
- score = Score::Tempo.new(FOUR_FOUR, 120, meter_changes: {
210
+ score = Score::Tempo.new(120, start_meter: FOUR_FOUR, meter_changes: {
211
211
  1 => change1, 2 => change2 }, program: [0...2])
212
212
  collator = ScoreCollator.new(score)
213
213
  sm, mcs = collator.collate_meter_changes