musicality 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +30 -0
- data/lib/musicality/errors.rb +1 -0
- data/lib/musicality/notation/conversion/change_conversion.rb +63 -3
- data/lib/musicality/notation/conversion/note_time_converter.rb +23 -5
- data/lib/musicality/notation/conversion/score_conversion.rb +60 -0
- data/lib/musicality/notation/conversion/score_converter.rb +105 -0
- data/lib/musicality/notation/model/change.rb +98 -28
- data/lib/musicality/notation/model/part.rb +1 -1
- data/lib/musicality/notation/model/score.rb +4 -4
- data/lib/musicality/notation/packing/change_packing.rb +35 -25
- data/lib/musicality/notation/packing/score_packing.rb +2 -2
- data/lib/musicality/notation/util/function.rb +99 -0
- data/lib/musicality/notation/util/piecewise_function.rb +79 -99
- data/lib/musicality/notation/util/transition.rb +12 -0
- data/lib/musicality/notation/util/value_computer.rb +12 -152
- data/lib/musicality/performance/conversion/score_collator.rb +35 -20
- data/lib/musicality/performance/midi/part_sequencer.rb +2 -5
- data/lib/musicality/validatable.rb +6 -1
- data/lib/musicality/version.rb +1 -1
- data/lib/musicality.rb +4 -4
- data/musicality.gemspec +1 -0
- data/spec/notation/conversion/change_conversion_spec.rb +216 -9
- data/spec/notation/conversion/measure_note_map_spec.rb +2 -2
- data/spec/notation/conversion/note_time_converter_spec.rb +91 -9
- data/spec/notation/conversion/{measured_score_conversion_spec.rb → score_conversion_spec.rb} +44 -9
- data/spec/notation/conversion/score_converter_spec.rb +246 -0
- data/spec/notation/model/change_spec.rb +139 -36
- data/spec/notation/model/part_spec.rb +3 -3
- data/spec/notation/model/score_spec.rb +4 -4
- data/spec/notation/packing/change_packing_spec.rb +222 -71
- data/spec/notation/packing/part_packing_spec.rb +1 -1
- data/spec/notation/packing/score_packing_spec.rb +3 -2
- data/spec/notation/util/function_spec.rb +43 -0
- data/spec/notation/util/transition_spec.rb +51 -0
- data/spec/notation/util/value_computer_spec.rb +43 -87
- data/spec/performance/conversion/score_collator_spec.rb +46 -7
- data/spec/performance/midi/part_sequencer_spec.rb +2 -1
- metadata +29 -14
- data/lib/musicality/notation/conversion/measured_score_conversion.rb +0 -70
- data/lib/musicality/notation/conversion/measured_score_converter.rb +0 -95
- data/lib/musicality/notation/conversion/unmeasured_score_conversion.rb +0 -47
- data/lib/musicality/notation/conversion/unmeasured_score_converter.rb +0 -64
- data/spec/notation/conversion/measured_score_converter_spec.rb +0 -329
- data/spec/notation/conversion/unmeasured_score_conversion_spec.rb +0 -71
- data/spec/notation/conversion/unmeasured_score_converter_spec.rb +0 -116
@@ -0,0 +1,246 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe ScoreConverter::TempoBased do
|
4
|
+
|
5
|
+
end
|
6
|
+
|
7
|
+
describe ScoreConverter::Measured do
|
8
|
+
describe '#initialize' do
|
9
|
+
context 'current score is invalid' do
|
10
|
+
it 'should raise NotValidError' do
|
11
|
+
score = Score::Measured.new(1, 120)
|
12
|
+
expect { ScoreConverter::Measured.new(score,200) }.to raise_error(NotValidError)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#convert_parts' do
|
18
|
+
before :each do
|
19
|
+
@changeA = Change::Immediate.new(Dynamics::PP)
|
20
|
+
@changeB = Change::Gradual.linear(Dynamics::F, 2)
|
21
|
+
@score = Score::Measured.new(FOUR_FOUR, 120,
|
22
|
+
parts: {"simple" => Part.new(Dynamics::MP, dynamic_changes: { 1 => @changeA, 3 => @changeB })}
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should return Hash with original part names' do
|
27
|
+
parts = ScoreConverter::Measured.new(@score,200).convert_parts
|
28
|
+
parts.should be_a Hash
|
29
|
+
parts.keys.sort.should eq(@score.parts.keys.sort)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should convert part dynamic change offsets from measure-based to note-based' do
|
33
|
+
parts = ScoreConverter::Measured.new(@score,200).convert_parts
|
34
|
+
parts.should have_key("simple")
|
35
|
+
part = parts["simple"]
|
36
|
+
part.dynamic_changes.keys.sort.should eq([2,6])
|
37
|
+
change = part.dynamic_changes[2.0]
|
38
|
+
change.end_value.should eq(@changeA.end_value)
|
39
|
+
change = part.dynamic_changes[6.0]
|
40
|
+
change.end_value.should eq(@changeB.end_value)
|
41
|
+
change.duration.should eq(4)
|
42
|
+
|
43
|
+
#@score.start_meter = THREE_FOUR
|
44
|
+
#parts = ScoreConverter::Measured.new(@score,200).convert_parts
|
45
|
+
#parts.should have_key("simple")
|
46
|
+
#part = parts["simple"]
|
47
|
+
#part.dynamic_changes.keys.sort.should eq([Rational(3,4),Rational(9,4)])
|
48
|
+
#change = part.dynamic_changes[Rational(3,4)]
|
49
|
+
#change.end_value.should eq(@changeA.end_value)
|
50
|
+
#change.duration.should eq(0)
|
51
|
+
#change = part.dynamic_changes[Rational(9,4)]
|
52
|
+
#change.end_value.should eq(@changeB.end_value)
|
53
|
+
#change.duration.should eq(1.5)
|
54
|
+
end
|
55
|
+
|
56
|
+
#context 'gradual changes with positive elapsed and/or remaining' do
|
57
|
+
# it 'should change elapsed and remaining so they reflect note-based offsets' do
|
58
|
+
# score = Score::Measured.new(THREE_FOUR,120, parts: {
|
59
|
+
# "abc" => Part.new(Dynamics::P, dynamic_changes: {
|
60
|
+
# 2 => Change::Gradual.linear(Dynamics::F,2,1,3),
|
61
|
+
# 7 => Change::Gradual.linear(Dynamics::F,1,4,5)
|
62
|
+
# })
|
63
|
+
# })
|
64
|
+
# converter = ScoreConverter::Measured.new(score)
|
65
|
+
# parts = converter.convert_parts
|
66
|
+
# dcs = parts["abc"].dynamic_changes
|
67
|
+
#
|
68
|
+
# dcs.keys.should eq([Rational(6,4), Rational(21,4)])
|
69
|
+
# dcs[Rational(3,2)].should eq(Change::Gradual.linear(Dynamics::F,Rational(6,4),Rational(3,4),Rational(9,4)))
|
70
|
+
# dcs[Rational(21,4)].should eq(Change::Gradual.linear(Dynamics::F,Rational(3,4),Rational(12,4),Rational(15,4)))
|
71
|
+
# end
|
72
|
+
#end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#convert_program' do
|
76
|
+
before :each do
|
77
|
+
@prog = Program.new([0...4,2...5])
|
78
|
+
@score = Score::Measured.new(FOUR_FOUR, 120, program: @prog)
|
79
|
+
@converter = ScoreConverter::Measured.new(@score,200)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'shuld return Program with same number of segments' do
|
83
|
+
prog = @converter.convert_program
|
84
|
+
prog.should be_a Program
|
85
|
+
prog.segments.size.should eq(@score.program.segments.size)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should convert program segments offsets from measure-based to note-based' do
|
89
|
+
prog = ScoreConverter::Measured.new(@score,200).convert_program
|
90
|
+
prog.segments.size.should eq(2)
|
91
|
+
prog.segments[0].first.should eq(0)
|
92
|
+
prog.segments[0].last.should eq(8)
|
93
|
+
prog.segments[1].first.should eq(4)
|
94
|
+
prog.segments[1].last.should eq(10)
|
95
|
+
|
96
|
+
@score.start_meter = THREE_FOUR
|
97
|
+
prog = ScoreConverter::Measured.new(@score,200).convert_program
|
98
|
+
prog.segments.size.should eq(2)
|
99
|
+
prog.segments[0].first.should eq(0)
|
100
|
+
prog.segments[0].last.should eq(6)
|
101
|
+
prog.segments[1].first.should eq(3)
|
102
|
+
prog.segments[1].last.should eq(7.5)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#convert_score' do
|
107
|
+
it 'should return a timed score' do
|
108
|
+
score = Score::Measured.new(FOUR_FOUR, 120)
|
109
|
+
converter = ScoreConverter::Measured.new(score,200)
|
110
|
+
converter.convert_score.should be_a Score::Timed
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should use output from convert_program' do
|
114
|
+
prog = Program.new([0...4,2...5])
|
115
|
+
score = Score::Measured.new(FOUR_FOUR, 120, program: prog)
|
116
|
+
converter = ScoreConverter::Measured.new(score,200)
|
117
|
+
nscore = converter.convert_score
|
118
|
+
nscore.program.should eq(converter.convert_program)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should use output from convert_parts' do
|
122
|
+
changeA = Change::Immediate.new(Dynamics::PP)
|
123
|
+
changeB = Change::Gradual.linear(Dynamics::F, 2)
|
124
|
+
score = Score::Measured.new(FOUR_FOUR, 120,
|
125
|
+
parts: {"simple" => Part.new(Dynamics::MP, dynamic_changes: { 1 => changeA, 3 => changeB })}
|
126
|
+
)
|
127
|
+
converter = ScoreConverter::Measured.new(score,200)
|
128
|
+
nscore = converter.convert_score
|
129
|
+
nscore.parts.should eq(converter.convert_parts)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe ScoreConverter::Unmeasured do
|
135
|
+
describe '#initialize' do
|
136
|
+
context 'current score is invalid' do
|
137
|
+
it 'should raise NotValidError' do
|
138
|
+
score = Score::Unmeasured.new(-1)
|
139
|
+
expect { ScoreConverter::Unmeasured.new(score,200) }.to raise_error(NotValidError)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe '#convert_parts' do
|
145
|
+
before :each do
|
146
|
+
@changeA = Change::Immediate.new(Dynamics::PP)
|
147
|
+
@changeB = Change::Gradual.linear(Dynamics::F, 2)
|
148
|
+
@score = Score::Unmeasured.new(120,
|
149
|
+
parts: {
|
150
|
+
"normal" => Part.new(Dynamics::MP,
|
151
|
+
dynamic_changes: { 1 => @changeA, 3 => @changeB },
|
152
|
+
notes: "/4C2 /8D2 /8E2 /2C2".to_notes * 4),
|
153
|
+
"empty" => Part.new(Dynamics::PP)
|
154
|
+
}
|
155
|
+
)
|
156
|
+
@parts = ScoreConverter::Unmeasured.new(@score,200).convert_parts
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should return Hash with original part names' do
|
160
|
+
@parts.should be_a Hash
|
161
|
+
@parts.keys.sort.should eq(@score.parts.keys.sort)
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should convert part dynamic change offsets from note-based to time-based' do
|
165
|
+
part = @parts["normal"]
|
166
|
+
part.dynamic_changes.keys.sort.should eq([2,6])
|
167
|
+
change = part.dynamic_changes[2.0]
|
168
|
+
change.end_value.should eq(@changeA.end_value)
|
169
|
+
change = part.dynamic_changes[6.0]
|
170
|
+
change.end_value.should eq(@changeB.end_value)
|
171
|
+
change.duration.should eq(4.0)
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should convert note durations to time durations' do
|
175
|
+
part = @parts["normal"]
|
176
|
+
part.notes.map {|x| x.duration }.should eq([0.5,0.25,0.25,1]*4)
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'trimmed, gradual changes' do
|
180
|
+
it 'should change preceding and remaining so they reflect time-based duration' do
|
181
|
+
score = Score::Unmeasured.new(120, parts: {
|
182
|
+
"abc" => Part.new(Dynamics::P, dynamic_changes: {
|
183
|
+
2 => Change::Gradual.linear(Dynamics::F,4).to_trimmed(2,1),
|
184
|
+
7 => Change::Gradual.linear(Dynamics::F,5).to_trimmed(1,3)
|
185
|
+
})
|
186
|
+
})
|
187
|
+
converter = ScoreConverter::Unmeasured.new(score,200)
|
188
|
+
parts = converter.convert_parts
|
189
|
+
dcs = parts["abc"].dynamic_changes
|
190
|
+
|
191
|
+
dcs.keys.should eq([4,14])
|
192
|
+
dcs[4.0].should eq(Change::Gradual.linear(Dynamics::F,8).to_trimmed(4,2))
|
193
|
+
dcs[14.0].should eq(Change::Gradual.linear(Dynamics::F,10).to_trimmed(2,6))
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe '#convert_program' do
|
199
|
+
before :each do
|
200
|
+
@prog = Program.new([0...4,2...5])
|
201
|
+
@score = Score::Unmeasured.new(120, program: @prog)
|
202
|
+
@converter = ScoreConverter::Unmeasured.new(@score,200)
|
203
|
+
@prog2 = @converter.convert_program
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'should return Program with same number of segments' do
|
207
|
+
@prog2.should be_a Program
|
208
|
+
@prog2.segments.size.should eq(@prog.segments.size)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should convert program segments offsets from note-based to time-based' do
|
212
|
+
prog = @prog2
|
213
|
+
prog.segments[0].first.should eq(0)
|
214
|
+
prog.segments[0].last.should eq(8)
|
215
|
+
prog.segments[1].first.should eq(4)
|
216
|
+
prog.segments[1].last.should eq(10)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe '#convert_score' do
|
221
|
+
it 'should return an timed score' do
|
222
|
+
score = Score::Unmeasured.new(120)
|
223
|
+
converter = ScoreConverter::Unmeasured.new(score,200)
|
224
|
+
converter.convert_score.should be_a Score::Timed
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'should use output from convert_program' do
|
228
|
+
prog = Program.new([0...4,2...5])
|
229
|
+
score = Score::Unmeasured.new(120, program: prog)
|
230
|
+
converter = ScoreConverter::Unmeasured.new(score,200)
|
231
|
+
nscore = converter.convert_score
|
232
|
+
nscore.program.should eq(converter.convert_program)
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'should use output from convert_parts' do
|
236
|
+
changeA = Change::Immediate.new(Dynamics::PP)
|
237
|
+
changeB = Change::Gradual.linear(Dynamics::F, 2)
|
238
|
+
score = Score::Unmeasured.new(120,
|
239
|
+
parts: {"simple" => Part.new(Dynamics::MP, dynamic_changes: { 1 => changeA, 3 => changeB })}
|
240
|
+
)
|
241
|
+
converter = ScoreConverter::Unmeasured.new(score,200)
|
242
|
+
nscore = converter.convert_score
|
243
|
+
nscore.parts.should eq(converter.convert_parts)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
@@ -2,21 +2,17 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
2
|
|
3
3
|
describe Change::Immediate do
|
4
4
|
context '#initialize' do
|
5
|
-
it 'should set value to given' do
|
6
|
-
Change::Immediate.new(5).
|
7
|
-
end
|
8
|
-
|
9
|
-
it 'should set duration to 0' do
|
10
|
-
Change::Immediate.new(5).duration.should eq 0
|
5
|
+
it 'should set end value to given' do
|
6
|
+
Change::Immediate.new(5).end_value.should eq 5
|
11
7
|
end
|
12
8
|
end
|
13
9
|
|
14
10
|
describe '==' do
|
15
|
-
it 'should return true if two immediate changes have the same value' do
|
11
|
+
it 'should return true if two immediate changes have the same end value' do
|
16
12
|
Change::Immediate.new(5).should eq(Change::Immediate.new(5))
|
17
13
|
end
|
18
14
|
|
19
|
-
it 'should return false if two immediate changes do not have the same value' do
|
15
|
+
it 'should return false if two immediate changes do not have the same end value' do
|
20
16
|
Change::Immediate.new(5).should_not eq(Change::Immediate.new(4))
|
21
17
|
end
|
22
18
|
end
|
@@ -30,61 +26,168 @@ describe Change::Immediate do
|
|
30
26
|
end
|
31
27
|
|
32
28
|
describe Change::Gradual do
|
33
|
-
context '
|
34
|
-
it 'should set value to given
|
35
|
-
Change::Gradual.new(5,2)
|
29
|
+
context '#initialize' do
|
30
|
+
it 'should set end value and duration to given values' do
|
31
|
+
ch = Change::Gradual.new(5,2,Change::Gradual::LINEAR)
|
32
|
+
ch.end_value.should eq(5)
|
33
|
+
ch.duration.should eq(2)
|
36
34
|
end
|
37
35
|
|
38
|
-
it 'should set
|
39
|
-
|
40
|
-
c.duration.should eq 2
|
41
|
-
c.impending.should eq 2
|
36
|
+
it 'should set start_value to nil if not given' do
|
37
|
+
Change::Gradual.linear(5,2).start_value.should be nil
|
42
38
|
end
|
43
39
|
|
44
|
-
it 'should set
|
45
|
-
Change::Gradual.
|
40
|
+
it 'should set start_value if given' do
|
41
|
+
Change::Gradual.linear(5,2, start_value: 3).start_value.should eq(3)
|
46
42
|
end
|
47
43
|
|
48
|
-
it 'should
|
49
|
-
Change::Gradual.new(
|
44
|
+
it 'should raise NonPositiveError if duration is <= 0' do
|
45
|
+
expect { Change::Gradual.new(11,0,Change::Gradual::LINEAR) }.to raise_error(NonPositiveError)
|
46
|
+
expect { Change::Gradual.new(11,-1,Change::Gradual::LINEAR) }.to raise_error(NonPositiveError)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#relative?' do
|
51
|
+
context 'start_value is nil' do
|
52
|
+
it 'should return true' do
|
53
|
+
Change::Gradual.linear(25,3).relative?.should be true
|
54
|
+
end
|
50
55
|
end
|
51
56
|
|
52
|
-
|
53
|
-
|
57
|
+
context 'start_value is not nil' do
|
58
|
+
it 'should return false' do
|
59
|
+
Change::Gradual.linear(25,3, start_value: 10).relative?.should be false
|
60
|
+
end
|
54
61
|
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context '.linear' do
|
65
|
+
before(:all){ @change = Change::Gradual.linear(55,20, start_value: 25) }
|
55
66
|
|
56
|
-
it 'should
|
57
|
-
|
58
|
-
|
67
|
+
it 'should assign end_value, duration, and start_value as normal' do
|
68
|
+
@change.end_value.should eq(55)
|
69
|
+
@change.duration.should eq(20)
|
70
|
+
@change.start_value.should eq(25)
|
59
71
|
end
|
72
|
+
|
73
|
+
it 'should set transition to linear' do
|
74
|
+
@change.transition.should eq(Change::Gradual::LINEAR)
|
75
|
+
end
|
76
|
+
end
|
60
77
|
|
61
|
-
|
62
|
-
|
78
|
+
context '.sigmoid' do
|
79
|
+
before(:all){ @change = Change::Gradual.sigmoid(55,20, start_value: 25) }
|
80
|
+
|
81
|
+
it 'should assign end_value, duration, and start_value as normal' do
|
82
|
+
@change.end_value.should eq(55)
|
83
|
+
@change.duration.should eq(20)
|
84
|
+
@change.start_value.should eq(25)
|
63
85
|
end
|
64
86
|
|
65
|
-
it 'should
|
66
|
-
|
87
|
+
it 'should set transition to SIGMOID' do
|
88
|
+
@change.transition.should eq(Change::Gradual::SIGMOID)
|
67
89
|
end
|
68
90
|
end
|
69
|
-
|
91
|
+
|
70
92
|
describe '==' do
|
71
|
-
|
72
|
-
|
93
|
+
context 'two gradual changes have the same end value, duration, and start value' do
|
94
|
+
it 'should return true' do
|
95
|
+
Change::Gradual.linear(5,2).should eq(Change::Gradual.linear(5,2))
|
96
|
+
Change::Gradual.linear(5,2,start_value:0).should eq(Change::Gradual.linear(5,2,start_value:0))
|
97
|
+
end
|
73
98
|
end
|
74
99
|
|
75
|
-
|
76
|
-
|
100
|
+
context 'two gradual changes do not have the same end value' do
|
101
|
+
it 'should return false' do
|
102
|
+
Change::Gradual.linear(5,2).should_not eq(Change::Gradual.linear(4,2))
|
103
|
+
end
|
77
104
|
end
|
78
105
|
|
79
|
-
|
80
|
-
|
106
|
+
context 'two gradual changes do not have the same duration' do
|
107
|
+
it 'should return false' do
|
108
|
+
Change::Gradual.linear(5,2).should_not eq(Change::Gradual.linear(5,1))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'two gradual changes do not have the start value' do
|
113
|
+
it 'should return false' do
|
114
|
+
Change::Gradual.linear(5,2, start_value: 3).should_not eq(Change::Gradual.linear(5,1))
|
115
|
+
end
|
81
116
|
end
|
82
117
|
end
|
83
118
|
|
84
119
|
describe '#to_yaml' do
|
85
120
|
it 'should produce YAML that can be loaded' do
|
86
|
-
c = Change::Gradual.
|
121
|
+
c = Change::Gradual.linear(4,2)
|
87
122
|
YAML.load(c.to_yaml).should eq c
|
88
123
|
end
|
89
124
|
end
|
90
125
|
end
|
126
|
+
|
127
|
+
describe Change::Gradual::Trimmed do
|
128
|
+
it 'should be a Change::Gradual' do
|
129
|
+
Change::Gradual::Trimmed.new(35,1,Change::Gradual::LINEAR,preceding: 0, remaining: 0.5).should be_a Change::Gradual
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '.linear' do
|
133
|
+
before(:all){ @change = Change::Gradual::Trimmed.linear(55,20,preceding:5,remaining:6) }
|
134
|
+
|
135
|
+
it 'should assign end_value, duration, preceding, and remaining as normal' do
|
136
|
+
@change.end_value.should eq(55)
|
137
|
+
@change.duration.should eq(20)
|
138
|
+
@change.preceding.should eq(5)
|
139
|
+
@change.remaining.should eq(6)
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should set transition to linear' do
|
143
|
+
@change.transition.should eq(Change::Gradual::LINEAR)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe '.sigmoid' do
|
148
|
+
before(:all){ @change = Change::Gradual::Trimmed.sigmoid(55,20,preceding:5,remaining:6) }
|
149
|
+
|
150
|
+
it 'should assign end_value, duration, preceding, and remaining as normal' do
|
151
|
+
@change.end_value.should eq(55)
|
152
|
+
@change.duration.should eq(20)
|
153
|
+
@change.preceding.should eq(5)
|
154
|
+
@change.remaining.should eq(6)
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should set transition to SIGMOID' do
|
158
|
+
@change.transition.should eq(Change::Gradual::SIGMOID)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should raise NegativeError if preceding is < 0' do
|
163
|
+
expect { Change::Gradual::Trimmed.linear(11,1,preceding: -1,remaining: 0.5) }.to raise_error(NegativeError)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should raise NonPositiveError if remaining is <= 0' do
|
167
|
+
expect { Change::Gradual::Trimmed.linear(11,3,preceding: 1,remaining: 0) }.to raise_error(NonPositiveError)
|
168
|
+
expect { Change::Gradual::Trimmed.linear(11,3,preceding: 1,remaining: -1) }.to raise_error(NonPositiveError)
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '#untrim' do
|
172
|
+
before :all do
|
173
|
+
@trimmed = Change::Gradual.linear(51,12).trim(2,2)
|
174
|
+
@untrimmed = @trimmed.untrim
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should return a Change::Gradual' do
|
178
|
+
@untrimmed.should be_a Change::Gradual
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'should keep end_value, duration, and transition' do
|
182
|
+
@untrimmed.end_value.should eq(@trimmed.end_value)
|
183
|
+
@untrimmed.duration.should eq(@trimmed.duration)
|
184
|
+
@untrimmed.transition.should eq(@trimmed.transition)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe '#trailing' do
|
189
|
+
it 'should return the amount of transition unused at the end' do
|
190
|
+
Change::Gradual.linear(41,19).trim(4,9).trailing.should eq(9)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -13,7 +13,7 @@ describe Part do
|
|
13
13
|
p.start_dynamic.should eq Dynamics::PPP
|
14
14
|
|
15
15
|
notes = [Note::whole([A2]), Note::half]
|
16
|
-
dcs = { "1/2".to_r => Change::Immediate.new(Dynamics::P), 1 => Change::Gradual.
|
16
|
+
dcs = { "1/2".to_r => Change::Immediate.new(Dynamics::P), 1 => Change::Gradual.sigmoid(Dynamics::MF,1) }
|
17
17
|
p = Part.new(Dynamics::FF, notes: notes, dynamic_changes: dcs)
|
18
18
|
p.notes.should eq notes
|
19
19
|
p.dynamic_changes.should eq dcs
|
@@ -38,7 +38,7 @@ describe Part do
|
|
38
38
|
# :dynamic_changes => { -0.2 => Change::Immediate.new(0.5) }],
|
39
39
|
'dynamic change values outside 0..1' => [
|
40
40
|
0.5, :notes => [ Note::whole ],
|
41
|
-
:dynamic_changes => { 0.2 => Change::Immediate.new(-0.01), 0.3 => Change::Gradual.
|
41
|
+
:dynamic_changes => { 0.2 => Change::Immediate.new(-0.01), 0.3 => Change::Gradual.linear(1.01,0.2) }],
|
42
42
|
'notes with 0 duration' => [ 0.5, :notes => [ Note.new(0) ]],
|
43
43
|
'notes with negative duration' => [ 0.5, :notes => [ Note.new(-1) ]],
|
44
44
|
}.each do |context_str, args|
|
@@ -56,7 +56,7 @@ describe Part do
|
|
56
56
|
:notes => [ Note::whole([C4]), Note::quarter ],
|
57
57
|
:dynamic_changes => {
|
58
58
|
0.5 => Change::Immediate.new(Dynamics::MP),
|
59
|
-
1.2 => Change::Gradual.
|
59
|
+
1.2 => Change::Gradual.linear(Dynamics::FF, 0.05) } ],
|
60
60
|
}.each do |context_str, args|
|
61
61
|
context context_str do
|
62
62
|
it 'should return true' do
|
@@ -138,7 +138,7 @@ describe Score::Measured do
|
|
138
138
|
{
|
139
139
|
'valid start tempo' => [ FOUR_FOUR, 40 ],
|
140
140
|
'valid tempo changes' => [ FOUR_FOUR, 30,
|
141
|
-
:tempo_changes => { 1 => Change::Gradual.
|
141
|
+
:tempo_changes => { 1 => Change::Gradual.linear(40, 2), 2 => Change::Immediate.new(50) } ],
|
142
142
|
'valid meter changes' => [ FOUR_FOUR, 120,
|
143
143
|
:meter_changes => { 1 => Change::Immediate.new(TWO_FOUR) } ],
|
144
144
|
'valid part' => [ FOUR_FOUR, 120, :parts => { "piano" => Samples::SAMPLE_PART }],
|
@@ -161,7 +161,7 @@ describe Score::Measured do
|
|
161
161
|
'non-meter values in meter changes' => [ FOUR_FOUR, 120,
|
162
162
|
:meter_changes => { 1 => Change::Immediate.new(5) } ],
|
163
163
|
'non-immediate meter change' => [ FOUR_FOUR, 120,
|
164
|
-
:meter_changes => { 1 => Change::Gradual.
|
164
|
+
:meter_changes => { 1 => Change::Gradual.linear(TWO_FOUR,1) } ],
|
165
165
|
'non-integer meter change offset' => [ FOUR_FOUR, 120,
|
166
166
|
:meter_changes => { 1.1 => Change::Immediate.new(TWO_FOUR) } ],
|
167
167
|
'invalid part' => [ FOUR_FOUR, 120, :parts => { "piano" => Part.new(-0.1) }],
|
@@ -216,7 +216,7 @@ describe Score::Unmeasured do
|
|
216
216
|
{
|
217
217
|
'valid start tempo' => [ 40 ],
|
218
218
|
'valid tempo changes' => [ 30,
|
219
|
-
:tempo_changes => { 1 => Change::Gradual.
|
219
|
+
:tempo_changes => { 1 => Change::Gradual.linear(40, 2), 2 => Change::Immediate.new(50) } ],
|
220
220
|
'valid part' => [ 30, :parts => { "piano" => Samples::SAMPLE_PART }],
|
221
221
|
'valid program' => [ 30, :program => Program.new([0..2,0..2]) ]
|
222
222
|
}.each do |context_str,args|
|
@@ -231,7 +231,7 @@ describe Score::Unmeasured do
|
|
231
231
|
'start tempo valid is zero' => [ 0 ],
|
232
232
|
'start tempo valid is negative' => [ -1 ],
|
233
233
|
'tempo change value is not a valid value' => [ 30,
|
234
|
-
:tempo_changes => { 1 => Change::Gradual.
|
234
|
+
:tempo_changes => { 1 => Change::Gradual.linear(-1,1) } ],
|
235
235
|
'invalid part' => [ 30, :parts => { "piano" => Part.new(-0.1) }],
|
236
236
|
'invalid program' => [ 30, :program => Program.new([2..0]) ],
|
237
237
|
}.each do |context_str,args|
|