musicality 0.11.1 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.coveralls.yml +1 -0
- data/.ruby-version +1 -1
- data/.travis.yml +4 -0
- data/ChangeLog.md +11 -0
- data/README.md +3 -0
- data/Rakefile +11 -3
- data/lib/musicality/composition/model/rhythm.rb +33 -0
- data/lib/musicality/composition/model/rhythm_class.rb +30 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_kit.rb +18 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_machine.rb +59 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_parts.rb +21 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_pattern.rb +66 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_patterns/pop_drum_patterns.rb +146 -0
- data/lib/musicality/composition/sequencing/note_array.rb +33 -0
- data/lib/musicality/composition/sequencing/note_fifo.rb +73 -0
- data/lib/musicality/composition/sequencing/sequenceable.rb +9 -0
- data/lib/musicality/composition/sequencing/sequencer.rb +35 -0
- data/lib/musicality/errors.rb +2 -2
- data/lib/musicality/notation/model/dynamics.rb +2 -2
- data/lib/musicality/notation/model/key.rb +42 -91
- data/lib/musicality/notation/model/keys.rb +35 -34
- data/lib/musicality/notation/model/note.rb +31 -9
- data/lib/musicality/notation/model/pitch.rb +2 -2
- data/lib/musicality/notation/parsing/convenience_methods.rb +23 -12
- data/lib/musicality/notation/parsing/duration_parsing.rb +3 -3
- data/lib/musicality/notation/parsing/key_parsing.rb +150 -0
- data/lib/musicality/notation/parsing/key_parsing.treetop +37 -0
- data/lib/musicality/notation/parsing/meter_parsing.rb +3 -3
- data/lib/musicality/notation/parsing/numbers/nonnegative_float_parsing.rb +3 -1
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +1 -0
- data/lib/musicality/notation/parsing/numbers/nonnegative_rational_parsing.rb +1 -1
- data/lib/musicality/notation/parsing/numbers/positive_float_parsing.rb +4 -1
- data/lib/musicality/notation/parsing/numbers/positive_rational_parsing.rb +1 -1
- data/lib/musicality/notation/parsing/parseable.rb +13 -17
- data/lib/musicality/notation/parsing/pitch_parsing.rb +7 -0
- data/lib/musicality/notation/parsing/segment_parsing.rb +3 -0
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +82 -134
- data/lib/musicality/performance/model/note_sequence.rb +22 -3
- data/lib/musicality/performance/supercollider/performer.rb +2 -2
- data/lib/musicality/performance/supercollider/sc_drum_kits.rb +29 -0
- data/lib/musicality/performance/supercollider/synthdefs/bass.rb +211 -0
- data/lib/musicality/performance/supercollider/synthdefs/claps.rb +80 -0
- data/lib/musicality/performance/supercollider/synthdefs/cymbals.rb +57 -0
- data/lib/musicality/performance/supercollider/synthdefs/hihats.rb +67 -0
- data/lib/musicality/performance/supercollider/synthdefs/kicks.rb +158 -0
- data/lib/musicality/performance/supercollider/synthdefs/mario.rb +49 -0
- data/lib/musicality/performance/supercollider/{synthdefs.rb → synthdefs/other.rb} +0 -767
- data/lib/musicality/performance/supercollider/synthdefs/pianos.rb +46 -0
- data/lib/musicality/performance/supercollider/synthdefs/snares.rb +169 -0
- data/lib/musicality/performance/supercollider/synthdefs/toms.rb +25 -0
- data/lib/musicality/performance/supercollider/synthdefs/volume.rb +20 -0
- data/lib/musicality/pitch_class.rb +1 -1
- data/lib/musicality/pitch_classes.rb +3 -5
- data/lib/musicality/version.rb +1 -1
- data/lib/musicality.rb +25 -1
- data/musicality.gemspec +3 -2
- data/spec/composition/convenience_methods_spec.rb +8 -8
- data/spec/composition/generation/random_rhythm_generator_spec.rb +5 -5
- data/spec/composition/model/pitch_class_spec.rb +22 -16
- data/spec/composition/model/pitch_classes_spec.rb +5 -5
- data/spec/composition/model/rhythm_class_spec.rb +42 -0
- data/spec/composition/model/rhythm_spec.rb +43 -0
- data/spec/composition/model/scale_class_spec.rb +26 -26
- data/spec/composition/model/scale_spec.rb +38 -38
- data/spec/composition/sequencing/drum_machine/drum_machine_spec.rb +67 -0
- data/spec/composition/sequencing/drum_machine/drum_pattern_spec.rb +58 -0
- data/spec/composition/sequencing/note_array_spec.rb +94 -0
- data/spec/composition/sequencing/note_fifo_spec.rb +183 -0
- data/spec/composition/sequencing/sequencer_spec.rb +76 -0
- data/spec/composition/util/adding_sequence_spec.rb +33 -33
- data/spec/composition/util/compound_sequence_spec.rb +6 -6
- data/spec/composition/util/note_generation_spec.rb +34 -34
- data/spec/composition/util/probabilities_spec.rb +7 -7
- data/spec/composition/util/random_sampler_spec.rb +3 -3
- data/spec/composition/util/repeating_sequence_spec.rb +28 -28
- data/spec/musicality_spec.rb +1 -1
- data/spec/notation/conversion/change_conversion_spec.rb +87 -87
- data/spec/notation/conversion/note_time_converter_spec.rb +22 -22
- data/spec/notation/conversion/score_conversion_spec.rb +1 -1
- data/spec/notation/conversion/score_converter_spec.rb +31 -31
- data/spec/notation/conversion/tempo_conversion_spec.rb +11 -11
- data/spec/notation/model/change_spec.rb +80 -80
- data/spec/notation/model/key_spec.rb +135 -69
- data/spec/notation/model/link_spec.rb +27 -27
- data/spec/notation/model/meter_spec.rb +28 -28
- data/spec/notation/model/note_spec.rb +68 -47
- data/spec/notation/model/part_spec.rb +19 -19
- data/spec/notation/model/pitch_spec.rb +69 -68
- data/spec/notation/model/score_spec.rb +50 -47
- data/spec/notation/parsing/articulation_parsing_spec.rb +4 -4
- data/spec/notation/parsing/convenience_methods_spec.rb +49 -10
- data/spec/notation/parsing/duration_nodes_spec.rb +13 -13
- data/spec/notation/parsing/duration_parsing_spec.rb +10 -10
- data/spec/notation/parsing/key_parsing_spec.rb +19 -0
- data/spec/notation/parsing/link_nodes_spec.rb +7 -7
- data/spec/notation/parsing/link_parsing_spec.rb +4 -4
- data/spec/notation/parsing/meter_parsing_spec.rb +5 -5
- data/spec/notation/parsing/note_node_spec.rb +19 -19
- data/spec/notation/parsing/note_parsing_spec.rb +4 -4
- data/spec/notation/parsing/numbers/nonnegative_float_spec.rb +8 -8
- data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +2 -2
- data/spec/notation/parsing/numbers/nonnegative_rational_spec.rb +1 -1
- data/spec/notation/parsing/numbers/positive_float_spec.rb +8 -8
- data/spec/notation/parsing/numbers/positive_integer_spec.rb +6 -6
- data/spec/notation/parsing/numbers/positive_rational_spec.rb +6 -6
- data/spec/notation/parsing/pitch_node_spec.rb +7 -7
- data/spec/notation/parsing/pitch_parsing_spec.rb +2 -2
- data/spec/notation/parsing/segment_parsing_spec.rb +3 -3
- data/spec/notation/util/function_spec.rb +15 -15
- data/spec/notation/util/transition_spec.rb +12 -12
- data/spec/notation/util/value_computer_spec.rb +35 -36
- data/spec/performance/conversion/glissando_converter_spec.rb +24 -24
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +39 -39
- data/spec/performance/conversion/portamento_converter_spec.rb +23 -23
- data/spec/performance/midi/midi_util_spec.rb +41 -41
- data/spec/performance/midi/part_sequencer_spec.rb +10 -10
- data/spec/performance/midi/score_sequencer_spec.rb +15 -15
- data/spec/performance/midi/score_sequencing_spec.rb +2 -2
- data/spec/performance/util/optimization_spec.rb +9 -9
- data/spec/printing/note_engraving_spec.rb +16 -16
- data/spec/printing/score_engraver_spec.rb +5 -5
- data/spec/spec_helper.rb +5 -0
- metadata +85 -30
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
describe Sequencer do
|
4
|
+
describe '#next_part_notes' do
|
5
|
+
context '1 part with NoteArray sequenceable' do
|
6
|
+
describe 'given target duration that occurs in between note boundaries' do
|
7
|
+
it 'should return the part notes with the last note being shortened but tied' do
|
8
|
+
@seq = Sequencer.new("X" => NoteArray.new([Note.half(Pitches::G2)]))
|
9
|
+
expect(@seq.next_part_notes(Rational(1,4))).to eq(
|
10
|
+
"X" => [ Note.quarter(Pitches::G2).tie_to(Pitches::G2) ]
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context '2 parts (X,Y) with NoteArray sequenceables, X twice as long as Y' do
|
17
|
+
before :each do
|
18
|
+
@x_note_array = NoteArray.new([ Note.quarter(Pitches::D3), Note.quarter(Pitches::C3),
|
19
|
+
Note.quarter(Pitches::G3), Note.quarter(Pitches::F3) ])
|
20
|
+
@y_note_array = NoteArray.new([ Note.half(Pitches::A3) ])
|
21
|
+
@seq = Sequencer.new("X" => @x_note_array, "Y" => @y_note_array)
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'target duration equal to X duration' do
|
25
|
+
context 'next_part_notes not called yet before' do
|
26
|
+
it 'should produce all the notes for X and double the notes for Y' do
|
27
|
+
expect(@seq.next_part_notes(@x_note_array.duration)).to eq(
|
28
|
+
{"X" => @x_note_array.notes, "Y" => @y_note_array.notes*2}
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'next_part_notes already called once with target duration equal to X duration' do
|
34
|
+
it 'should produce all the notes for X and double the notes for Y' do
|
35
|
+
@seq.next_part_notes(@x_note_array.duration)
|
36
|
+
expect(@seq.next_part_notes(@x_note_array.duration)).to eq(
|
37
|
+
{"X" => @x_note_array.notes, "Y" => @y_note_array.notes*2}
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'target duration equal to Y duration' do
|
44
|
+
context 'next_part_notes not called yet before' do
|
45
|
+
it 'should return first half of X notes and all of Y' do
|
46
|
+
expect(@seq.next_part_notes(Rational(@x_note_array.duration,2))).to eq(
|
47
|
+
{ "X" => @x_note_array.notes[0..1], "Y" => @y_note_array.notes }
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'next_part_notes already called once with half of X duration' do
|
53
|
+
it 'should return last half of X notes and all of Y' do
|
54
|
+
@seq.next_part_notes(Rational(@x_note_array.duration,2))
|
55
|
+
expect(@seq.next_part_notes(Rational(@x_note_array.duration,2))).to eq(
|
56
|
+
{ "X" => @x_note_array.notes[2..3], "Y" => @y_note_array.notes }
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#reset' do
|
65
|
+
it 'should reset each sequenceable' do
|
66
|
+
sequencable1 = instance_double("NoteArray")
|
67
|
+
sequencable2 = instance_double("NoteArray")
|
68
|
+
|
69
|
+
expect(sequencable1).to receive(:reset)
|
70
|
+
expect(sequencable2).to receive(:reset)
|
71
|
+
|
72
|
+
seq = Sequencer.new("X" => sequencable1, "Y" => sequencable2)
|
73
|
+
seq.reset
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -10,65 +10,65 @@ describe AddingSequence do
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
describe '#pattern_size' do
|
15
15
|
it 'should return the pattern size' do
|
16
|
-
AddingSequence.new([1,2,3,4,5]).pattern_size.
|
16
|
+
expect(AddingSequence.new([1,2,3,4,5]).pattern_size).to eq(5)
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
before :all do
|
21
21
|
@pattern = [2,-1,5,-4,3]
|
22
22
|
@start_value = 13
|
23
23
|
@seq = AddingSequence.new(@pattern,@start_value)
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
describe '#at' do
|
27
27
|
context 'given single offset' do
|
28
28
|
context 'given offset of 0' do
|
29
29
|
it 'should return the start value' do
|
30
30
|
[ 0, -3, 7].each do |start_val|
|
31
|
-
AddingSequence.new(@pattern,start_val).at(0).
|
31
|
+
expect(AddingSequence.new(@pattern,start_val).at(0)).to eq(start_val)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
context 'given offset > 0' do
|
37
37
|
it 'should keep adding on pattern elements to start_val until the given offset is reached' do
|
38
38
|
[1,2,3,5,8,15,45].each do |offset|
|
39
39
|
val = @seq.at(offset)
|
40
40
|
rep_seq = RepeatingSequence.new(@pattern)
|
41
41
|
val2 = rep_seq.take(offset).inject(@start_value,:+)
|
42
|
-
val.
|
42
|
+
expect(val).to eq(val2)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
context 'given offset < 0' do
|
48
48
|
it 'should keep suctracting pattern elements from start_val until the given offset is reached' do
|
49
49
|
[-1,-2,-3,-5,-8,-15,-45].each do |offset|
|
50
50
|
val = @seq.at(offset)
|
51
51
|
rep_seq = RepeatingSequence.new(@pattern)
|
52
52
|
val2 = rep_seq.take_back(-offset).inject(@start_value,:-)
|
53
|
-
val.
|
53
|
+
expect(val).to eq(val2)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
context 'given array of offsets' do
|
60
60
|
context 'not given block' do
|
61
61
|
it 'should return enumerator' do
|
62
|
-
@seq.at([1,2,3]).
|
62
|
+
expect(@seq.at([1,2,3])).to be_a Enumerator
|
63
63
|
end
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
context 'given block' do
|
67
67
|
it 'should yield sequence value for each offset' do
|
68
68
|
[ (0..@seq.pattern_size).to_a, (-@seq.pattern_size..0).to_a,
|
69
69
|
[-5,11,0,-33,2,15,-8] ].each do |offsets|
|
70
70
|
@seq.at(offsets).each_with_index do |val,i|
|
71
|
-
val.
|
71
|
+
expect(val).to eq(@seq.at(offsets[i]))
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
@@ -83,33 +83,33 @@ describe AddingSequence do
|
|
83
83
|
expect { @seq.take(-10) }.to raise_error(NegativeError)
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
context 'given 0' do
|
88
88
|
it 'should return empty array' do
|
89
|
-
@seq.take(0).to_a.
|
89
|
+
expect(@seq.take(0).to_a).to eq([])
|
90
90
|
end
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
context 'given positive integer' do
|
94
94
|
context 'given block' do
|
95
95
|
it 'should yield the given number of sequence elements in forward direction (repeating as necessary)' do
|
96
96
|
i, m = 0, @pattern.size*2+3
|
97
97
|
@seq.take(m) do |n|
|
98
|
-
n.
|
98
|
+
expect(n).to eq(@seq.at(i))
|
99
99
|
i += 1
|
100
100
|
end
|
101
|
-
i.
|
101
|
+
expect(i).to eq(m)
|
102
102
|
end
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
context 'no block given' do
|
106
106
|
it 'should return an enumerator' do
|
107
|
-
@seq.take(20).
|
107
|
+
expect(@seq.take(20)).to be_a Enumerator
|
108
108
|
end
|
109
109
|
end
|
110
110
|
end
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
describe '#take_back' do
|
114
114
|
context 'given negative integer' do
|
115
115
|
it 'should raise NegativeError' do
|
@@ -117,33 +117,33 @@ describe AddingSequence do
|
|
117
117
|
expect { @seq.take_back(-10) }.to raise_error(NegativeError)
|
118
118
|
end
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
context 'given 0' do
|
122
122
|
it 'should return empty array' do
|
123
|
-
@seq.take_back(0).to_a.
|
123
|
+
expect(@seq.take_back(0).to_a).to eq([])
|
124
124
|
end
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
127
|
context 'given positive integer' do
|
128
128
|
context 'given block' do
|
129
129
|
it 'should yield the given number of pattern elements in backward direction (repeating as necessary)' do
|
130
130
|
i, m = 0, @pattern.size*2+3
|
131
131
|
@seq.take_back(m) do |n|
|
132
|
-
n.
|
132
|
+
expect(n).to eq(@seq.at(i-1))
|
133
133
|
i -= 1
|
134
134
|
end
|
135
|
-
(-i).
|
135
|
+
expect(-i).to eq(m)
|
136
136
|
end
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
context 'no block given' do
|
140
140
|
it 'should return an enumerator' do
|
141
|
-
@seq.take_back(20).
|
141
|
+
expect(@seq.take_back(20)).to be_a Enumerator
|
142
142
|
end
|
143
143
|
end
|
144
144
|
end
|
145
145
|
end
|
146
|
-
|
146
|
+
|
147
147
|
describe '#over' do
|
148
148
|
context 'given empty (invalid) range' do
|
149
149
|
it 'should raise EmptyError' do
|
@@ -152,23 +152,23 @@ describe AddingSequence do
|
|
152
152
|
end
|
153
153
|
end
|
154
154
|
end
|
155
|
-
|
155
|
+
|
156
156
|
context 'given range over positive indices' do
|
157
157
|
it 'should return seq values at all offsets in range' do
|
158
158
|
[ 0..0, 0..2, 1...10, 4..17 ].each do |range|
|
159
159
|
vals = @seq.over(range).to_a
|
160
160
|
vals2 = range.map {|i| @seq.at(i) }
|
161
|
-
vals.
|
161
|
+
expect(vals).to eq(vals2)
|
162
162
|
end
|
163
163
|
end
|
164
164
|
end
|
165
|
-
|
165
|
+
|
166
166
|
context 'given negative min and/or max' do
|
167
167
|
it 'should return seq values at all offsets in range' do
|
168
168
|
[ -5..2, -10..-7, -1...1 ].each do |range|
|
169
169
|
vals = @seq.over(range).to_a
|
170
170
|
vals2 = range.map {|i| @seq.at(i) }
|
171
|
-
vals.
|
171
|
+
expect(vals).to eq(vals2)
|
172
172
|
end
|
173
173
|
end
|
174
174
|
end
|
@@ -3,7 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
3
3
|
describe CompoundSequence do
|
4
4
|
seqs = [ AddingSequence.new([1,1,0,2,-1]),
|
5
5
|
RepeatingSequence.new([0,1,0,5,-13]) ]
|
6
|
-
|
6
|
+
|
7
7
|
describe "#at" do
|
8
8
|
context 'given single offset' do
|
9
9
|
[ :+, :* ].each do |sym|
|
@@ -14,14 +14,14 @@ describe CompoundSequence do
|
|
14
14
|
vals = seqs.map {|s| s.at(offset) }
|
15
15
|
val = vals[1..-1].inject(vals.first,sym)
|
16
16
|
val2 = cseq.send(:at,offset)
|
17
|
-
val2.
|
17
|
+
expect(val2).to eq(val)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
{ :at => [[-5,1,33,2,0,-11], [-3,-2,-1,0,1,2,-3,-2,-1]],
|
26
26
|
:take => [ 0, 5, 10, 13 ],
|
27
27
|
:take_back => [ 0, 2, 6, 15 ],
|
@@ -34,17 +34,17 @@ describe CompoundSequence do
|
|
34
34
|
it "should get values from each sequence using #{method} and combine each set of values using #{sym}" do
|
35
35
|
args.each do |arg|
|
36
36
|
enums = seqs.map {|s| s.send(method,arg) }
|
37
|
-
n = arg.is_a?(
|
37
|
+
n = arg.is_a?(Integer) ? arg : arg.size
|
38
38
|
vals = Array.new(n) do |i|
|
39
39
|
_vals = enums.map {|e| e.next }
|
40
40
|
_vals[1..-1].inject(_vals.first,sym)
|
41
41
|
end
|
42
42
|
vals2 = cseq.send(method,arg).to_a
|
43
|
-
vals2.
|
43
|
+
expect(vals2).to eq(vals)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
48
|
-
end
|
48
|
+
end
|
49
49
|
end
|
50
50
|
end
|
@@ -2,32 +2,32 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
2
2
|
|
3
3
|
describe 'make_note' do
|
4
4
|
it 'should return a Note' do
|
5
|
-
make_note(0.3,C3).
|
5
|
+
expect(make_note(0.3,C3)).to be_a Note
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
context 'given single pitch' do
|
9
9
|
it 'should have the given duration and pitch' do
|
10
10
|
n = make_note(0.3,C3)
|
11
|
-
n.duration.
|
12
|
-
n.pitches.
|
11
|
+
expect(n.duration).to eq(0.3)
|
12
|
+
expect(n.pitches).to eq([C3])
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
context 'given pitch array' do
|
17
17
|
it 'should have the given duration and pitches' do
|
18
18
|
n = make_note(0.2,[C3,E3,Ab3])
|
19
|
-
n.duration.
|
20
|
-
n.pitches.
|
19
|
+
expect(n.duration).to eq(0.2)
|
20
|
+
expect(n.pitches).to eq([C3,E3,Ab3])
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
context 'given negative duration' do
|
25
25
|
it 'should have duration with same magnitude' do
|
26
|
-
make_note(-0.3,C3).duration.
|
26
|
+
expect(make_note(-0.3,C3).duration).to eq(0.3)
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
it 'should make a rest note (no pitches)' do
|
30
|
-
make_note(-0.3,[C3,E3]).pitches.
|
30
|
+
expect(make_note(-0.3,[C3,E3]).pitches).to be_empty
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -43,71 +43,71 @@ describe 'make_notes' do
|
|
43
43
|
end.to raise_error(EmptyError)
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
context 'given equal length rhtyhm and pitch_groups' do
|
48
48
|
it 'should produce same number of notes as both' do
|
49
|
-
make_notes([2,2,5],[A1,B1,C1]).size.
|
49
|
+
expect(make_notes([2,2,5],[A1,B1,C1]).size).to eq(3)
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
context 'given longer rhythm than pitch_groups' do
|
54
54
|
before :all do
|
55
55
|
@rhythm = [4,3,3,1]
|
56
56
|
@pitch_groups = [[C1],[E2,G2]]
|
57
57
|
@notes = make_notes(@rhythm,@pitch_groups)
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
it 'should produce same number of notes as rhythm.size' do
|
61
|
-
@notes.size.
|
61
|
+
expect(@notes.size).to eq(@rhythm.size)
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
it 'should follow entire rhythm once' do
|
65
|
-
@notes.map {|n| n.duration}.
|
65
|
+
expect(@notes.map {|n| n.duration}).to eq(@rhythm)
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
it 'should cycle through pitch groups as necesary' do
|
69
|
-
@notes.map {|n| n.pitches}.
|
69
|
+
expect(@notes.map {|n| n.pitches}).to eq(@pitch_groups*2)
|
70
70
|
end
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
context 'given longer pitch_groups than rhythm' do
|
74
74
|
before :all do
|
75
75
|
@rhythm = [4,3,1]
|
76
76
|
@pitch_groups = [[C1],[E2,G2],[F5,G5,A5],[F4],[Eb4],[G4]]
|
77
77
|
@notes = make_notes(@rhythm,@pitch_groups)
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
it 'should produce same number of notes as pitch_groups.size' do
|
81
|
-
@notes.size.
|
81
|
+
expect(@notes.size).to eq(@pitch_groups.size)
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
it 'should follow entire pitch_groups once' do
|
85
|
-
@notes.map {|n| n.pitches}.
|
85
|
+
expect(@notes.map {|n| n.pitches}).to eq(@pitch_groups)
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
it 'should cycle through rhythm as necesary' do
|
89
|
-
@notes.map {|n| n.duration}.
|
89
|
+
expect(@notes.map {|n| n.duration}).to eq(@rhythm*2)
|
90
90
|
end
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
context 'given same-length pitch_groups and rhythm' do
|
94
94
|
before :all do
|
95
95
|
@rhythm = [4,3,1]
|
96
96
|
@pitch_groups = [[F4],[Eb4],[G4]]
|
97
97
|
@notes = make_notes(@rhythm,@pitch_groups)
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
100
|
it 'should produce same number of notes as rhythm.size and pitch_groups.size' do
|
101
|
-
@notes.size.
|
102
|
-
@notes.size.
|
101
|
+
expect(@notes.size).to eq(@pitch_groups.size)
|
102
|
+
expect(@notes.size).to eq(@rhythm.size)
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
it 'should follow entire rhythm once' do
|
106
|
-
@notes.map {|n| n.pitches}.
|
106
|
+
expect(@notes.map {|n| n.pitches}).to eq(@pitch_groups)
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
it 'should follow entire pitch groups once' do
|
110
|
-
@notes.map {|n| n.duration}.
|
110
|
+
expect(@notes.map {|n| n.duration}).to eq(@rhythm)
|
111
111
|
end
|
112
112
|
end
|
113
113
|
end
|
@@ -9,29 +9,29 @@ describe Probabilities do
|
|
9
9
|
(1..10).step(2) do |n|
|
10
10
|
5.times do
|
11
11
|
x = Probabilities.send(class_method,n)
|
12
|
-
x.size.
|
13
|
-
x.inject(0,:+).
|
12
|
+
expect(x.size).to eq(n)
|
13
|
+
expect(x.inject(0,:+)).to eq(1)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
describe '.random' do
|
21
21
|
it 'should return array of all-different values' do
|
22
22
|
x = Probabilities.random(100)
|
23
|
-
Set.new(x).size.
|
23
|
+
expect(Set.new(x).size).to eq(100)
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
describe '.uniform' do
|
28
28
|
it 'should return array of all (or all-but-one) same values' do
|
29
29
|
[2,6,10,33,78,100].each do |n|
|
30
30
|
x = Probabilities.uniform(n)
|
31
31
|
y = Set.new(x)
|
32
|
-
(y.size == 1 || y.size == 2).
|
32
|
+
expect(y.size == 1 || y.size == 2).to eq(true)
|
33
33
|
if y.size == 2
|
34
|
-
y.entries[0].
|
34
|
+
expect(y.entries[0]).to be_within(1e-9).of(y.entries[1])
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -28,17 +28,17 @@ describe RandomSampler do
|
|
28
28
|
sampler.values.each_with_index do |val,i|
|
29
29
|
count = counts[val]
|
30
30
|
tgt_prob = sampler.probabilities[i]
|
31
|
-
(count / 1000.to_f).
|
31
|
+
expect(count / 1000.to_f).to be_within(0.1).of(tgt_prob)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
context 'given number of samples to take' do
|
38
38
|
it 'should return array with the given number of samples' do
|
39
39
|
@samplers.each do |sampler|
|
40
40
|
[1,2,5,10].each do |n|
|
41
|
-
sampler.sample(n).size.
|
41
|
+
expect(sampler.sample(n).size).to eq(n)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
@@ -10,41 +10,41 @@ describe RepeatingSequence do
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
describe '#pattern_size' do
|
15
15
|
it 'should return the pattern size' do
|
16
|
-
RepeatingSequence.new([1,2,3,4,5]).pattern_size.
|
16
|
+
expect(RepeatingSequence.new([1,2,3,4,5]).pattern_size).to eq(5)
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
before :all do
|
21
21
|
@pattern = [2,1,5,4,3]
|
22
22
|
@seq = RepeatingSequence.new(@pattern)
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
describe '#at' do
|
26
26
|
context 'given single offset' do
|
27
27
|
it 'should module index into pattern using given offset' do
|
28
28
|
n = @pattern.size
|
29
29
|
(0..n*2).each do |i|
|
30
|
-
@seq.at(i).
|
30
|
+
expect(@seq.at(i)).to eq(@pattern[i%n])
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
context 'given array of offsets' do
|
36
36
|
context 'not given block' do
|
37
37
|
it 'should return enumerator' do
|
38
|
-
@seq.at([1,2,3]).
|
38
|
+
expect(@seq.at([1,2,3])).to be_a Enumerator
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
context 'given block' do
|
43
43
|
it 'should yield sequence value for each offset' do
|
44
44
|
[ (0..@seq.pattern_size).to_a, (-@seq.pattern_size..0).to_a,
|
45
45
|
[-5,11,0,-33,2,15,-8] ].each do |offsets|
|
46
46
|
@seq.at(offsets).each_with_index do |val,i|
|
47
|
-
val.
|
47
|
+
expect(val).to eq(@seq.at(offsets[i]))
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
@@ -59,32 +59,32 @@ describe RepeatingSequence do
|
|
59
59
|
expect { @seq.take(-10) }.to raise_error(NegativeError)
|
60
60
|
end
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
context 'given 0' do
|
64
64
|
it 'should return empty array' do
|
65
|
-
@seq.take(0).to_a.
|
65
|
+
expect(@seq.take(0).to_a).to eq([])
|
66
66
|
end
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
context 'given positive integer' do
|
70
70
|
context 'given block' do
|
71
71
|
it 'should yield the given number of pattern elements in forward direction (repeating as necessary)' do
|
72
72
|
i = 0
|
73
73
|
@seq.take(@pattern.size*2+3) do |n|
|
74
|
-
n.
|
74
|
+
expect(n).to eq(@seq.at(i))
|
75
75
|
i += 1
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
context 'no block given' do
|
81
81
|
it 'should return an enumerator' do
|
82
|
-
@seq.take(20).
|
82
|
+
expect(@seq.take(20)).to be_a Enumerator
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
describe '#take_back' do
|
89
89
|
context 'given negative integer' do
|
90
90
|
it 'should raise NegativeError' do
|
@@ -92,33 +92,33 @@ describe RepeatingSequence do
|
|
92
92
|
expect { @seq.take_back(-10) }.to raise_error(NegativeError)
|
93
93
|
end
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
context 'given 0' do
|
97
97
|
it 'should return empty array' do
|
98
|
-
@seq.take_back(0).to_a.
|
98
|
+
expect(@seq.take_back(0).to_a).to eq([])
|
99
99
|
end
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
context 'given positive integer' do
|
103
103
|
context 'given block' do
|
104
104
|
it 'should yield the given number of pattern elements in backward direction (repeating as necessary)' do
|
105
105
|
i, m = 0, @pattern.size*2+3
|
106
106
|
@seq.take_back(m) do |n|
|
107
|
-
n.
|
107
|
+
expect(n).to eq(@seq.at(i-1))
|
108
108
|
i -= 1
|
109
109
|
end
|
110
|
-
(-i).
|
110
|
+
expect(-i).to eq(m)
|
111
111
|
end
|
112
112
|
end
|
113
|
-
|
113
|
+
|
114
114
|
context 'no block given' do
|
115
115
|
it 'should return an enumerator' do
|
116
|
-
@seq.take_back(20).
|
116
|
+
expect(@seq.take_back(20)).to be_a Enumerator
|
117
117
|
end
|
118
118
|
end
|
119
119
|
end
|
120
120
|
end
|
121
|
-
|
121
|
+
|
122
122
|
describe '#over' do
|
123
123
|
context 'given empty (invalid) range' do
|
124
124
|
it 'should raise EmptyError' do
|
@@ -127,23 +127,23 @@ describe RepeatingSequence do
|
|
127
127
|
end
|
128
128
|
end
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
context 'given range over positive indices' do
|
132
132
|
it 'should return seq values at all offsets in range' do
|
133
133
|
[ 0..0, 0..2, 1...10, 4..17 ].each do |range|
|
134
134
|
vals = @seq.over(range).to_a
|
135
135
|
vals2 = range.map {|i| @seq.at(i) }
|
136
|
-
vals.
|
136
|
+
expect(vals).to eq(vals2)
|
137
137
|
end
|
138
138
|
end
|
139
139
|
end
|
140
|
-
|
140
|
+
|
141
141
|
context 'given negative min and/or max' do
|
142
142
|
it 'should return seq values at all offsets in range' do
|
143
143
|
[ -5..2, -10..-7, -1...1 ].each do |range|
|
144
144
|
vals = @seq.over(range).to_a
|
145
145
|
vals2 = range.map {|i| @seq.at(i) }
|
146
|
-
vals.
|
146
|
+
expect(vals).to eq(vals2)
|
147
147
|
end
|
148
148
|
end
|
149
149
|
end
|