musicality 0.11.1 → 0.12.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 +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
|