musicality 0.2.0 → 0.3.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.
- 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|
|