mtk 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +9 -0
- data/INTRO.md +73 -0
- data/LICENSE.txt +27 -0
- data/README.md +93 -18
- data/Rakefile +13 -1
- data/examples/crescendo.rb +20 -0
- data/examples/dynamic_pattern.rb +39 -0
- data/examples/play_midi.rb +19 -0
- data/examples/print_midi.rb +13 -0
- data/examples/random_tone_row.rb +18 -0
- data/examples/tone_row_melody.rb +21 -0
- data/lib/mtk/_constants/durations.rb +80 -0
- data/lib/mtk/_constants/intensities.rb +81 -0
- data/lib/mtk/{constants → _constants}/intervals.rb +10 -1
- data/lib/mtk/_constants/pitch_classes.rb +35 -0
- data/lib/mtk/_constants/pitches.rb +49 -0
- data/lib/mtk/{numeric_extensions.rb → _numeric_extensions.rb} +0 -0
- data/lib/mtk/event.rb +14 -5
- data/lib/mtk/helper/collection.rb +114 -0
- data/lib/mtk/helper/event_builder.rb +85 -0
- data/lib/mtk/{constants → helper}/pseudo_constants.rb +7 -6
- data/lib/mtk/lang/grammar.rb +17 -0
- data/lib/mtk/lang/mtk_grammar.citrus +60 -0
- data/lib/mtk/midi/file.rb +10 -15
- data/lib/mtk/midi/jsound_input.rb +68 -0
- data/lib/mtk/midi/jsound_output.rb +80 -0
- data/lib/mtk/note.rb +22 -3
- data/lib/mtk/pattern/abstract_pattern.rb +132 -0
- data/lib/mtk/pattern/choice.rb +25 -9
- data/lib/mtk/pattern/cycle.rb +51 -0
- data/lib/mtk/pattern/enumerator.rb +26 -0
- data/lib/mtk/pattern/function.rb +46 -0
- data/lib/mtk/pattern/lines.rb +60 -0
- data/lib/mtk/pattern/palindrome.rb +42 -0
- data/lib/mtk/pattern/sequence.rb +15 -50
- data/lib/mtk/pitch.rb +45 -6
- data/lib/mtk/pitch_class.rb +36 -35
- data/lib/mtk/pitch_class_set.rb +46 -14
- data/lib/mtk/pitch_set.rb +20 -31
- data/lib/mtk/sequencer/abstract_sequencer.rb +85 -0
- data/lib/mtk/sequencer/rhythmic_sequencer.rb +29 -0
- data/lib/mtk/sequencer/step_sequencer.rb +26 -0
- data/lib/mtk/timeline.rb +75 -22
- data/lib/mtk/transform/invertible.rb +15 -0
- data/lib/mtk/{util → transform}/mappable.rb +6 -2
- data/lib/mtk/transform/set_theory_operations.rb +34 -0
- data/lib/mtk/transform/transposable.rb +14 -0
- data/lib/mtk.rb +56 -22
- data/spec/mtk/_constants/durations_spec.rb +118 -0
- data/spec/mtk/{constants/dynamics_spec.rb → _constants/intensities_spec.rb} +48 -17
- data/spec/mtk/{constants → _constants}/intervals_spec.rb +21 -0
- data/spec/mtk/_constants/pitch_classes_spec.rb +58 -0
- data/spec/mtk/_constants/pitches_spec.rb +52 -0
- data/spec/mtk/{numeric_extensions_spec.rb → _numeric_extensions_spec.rb} +0 -0
- data/spec/mtk/event_spec.rb +19 -0
- data/spec/mtk/helper/collection_spec.rb +291 -0
- data/spec/mtk/helper/event_builder_spec.rb +92 -0
- data/spec/mtk/helper/pseudo_constants_spec.rb +20 -0
- data/spec/mtk/lang/grammar_spec.rb +100 -0
- data/spec/mtk/midi/file_spec.rb +41 -6
- data/spec/mtk/note_spec.rb +53 -3
- data/spec/mtk/pattern/abstract_pattern_spec.rb +45 -0
- data/spec/mtk/pattern/choice_spec.rb +89 -3
- data/spec/mtk/pattern/cycle_spec.rb +133 -0
- data/spec/mtk/pattern/function_spec.rb +133 -0
- data/spec/mtk/pattern/lines_spec.rb +93 -0
- data/spec/mtk/pattern/note_cycle_spec.rb.bak +116 -0
- data/spec/mtk/pattern/palindrome_spec.rb +124 -0
- data/spec/mtk/pattern/pitch_cycle_spec.rb.bak +47 -0
- data/spec/mtk/pattern/pitch_sequence_spec.rb.bak +37 -0
- data/spec/mtk/pattern/sequence_spec.rb +128 -31
- data/spec/mtk/pitch_class_set_spec.rb +240 -7
- data/spec/mtk/pitch_class_spec.rb +84 -18
- data/spec/mtk/pitch_set_spec.rb +45 -10
- data/spec/mtk/pitch_spec.rb +59 -0
- data/spec/mtk/sequencer/abstract_sequencer_spec.rb +159 -0
- data/spec/mtk/sequencer/rhythmic_sequencer_spec.rb +49 -0
- data/spec/mtk/sequencer/step_sequencer_spec.rb +71 -0
- data/spec/mtk/timeline_spec.rb +118 -15
- data/spec/spec_helper.rb +4 -3
- metadata +59 -22
- data/lib/mtk/chord.rb +0 -47
- data/lib/mtk/constants/dynamics.rb +0 -56
- data/lib/mtk/constants/pitch_classes.rb +0 -18
- data/lib/mtk/constants/pitches.rb +0 -24
- data/lib/mtk/pattern/note_sequence.rb +0 -60
- data/lib/mtk/pattern/pitch_sequence.rb +0 -22
- data/lib/mtk/patterns.rb +0 -4
- data/spec/mtk/chord_spec.rb +0 -74
- data/spec/mtk/constants/pitch_classes_spec.rb +0 -35
- data/spec/mtk/constants/pitches_spec.rb +0 -23
- data/spec/mtk/pattern/note_sequence_spec.rb +0 -121
- data/spec/mtk/pattern/pitch_sequence_spec.rb +0 -47
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Pattern::AbstractPattern do
|
4
|
+
|
5
|
+
PATTERN = MTK::Pattern::AbstractPattern
|
6
|
+
|
7
|
+
let(:elements) { [1,2,3] }
|
8
|
+
|
9
|
+
describe "#type" do
|
10
|
+
it "is the :type value from the constuctor's options hash" do
|
11
|
+
PATTERN.new([], :type => :my_type).type.should == :my_type
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#max_elements" do
|
16
|
+
it "is the :max_elements option the pattern was constructed with" do
|
17
|
+
PATTERN.new([], :max_elements => 1).max_elements.should == 1
|
18
|
+
end
|
19
|
+
|
20
|
+
it "is nil by default" do
|
21
|
+
PATTERN.new([]).max_elements.should be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "causes a StopIteration exception after the number of elements have been emitted" do
|
25
|
+
cycle = PATTERN.new([:anything], :max_elements => 5)
|
26
|
+
5.times { cycle.next }
|
27
|
+
lambda { cycle.next }.should raise_error
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#==" do
|
32
|
+
it "is true if the elements and types are equal" do
|
33
|
+
PATTERN.new(elements, :type => :some_type).should == PATTERN.new(elements, :type => :some_type)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "is false if the elements are not equal" do
|
37
|
+
PATTERN.new(elements, :type => :some_type).should_not == PATTERN.new(elements + [4], :type => :some_type)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "is false if the types are not equal" do
|
41
|
+
PATTERN.new(elements, :type => :some_type).should_not == PATTERN.new(elements, :type => :another_type)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -3,8 +3,10 @@ require 'set'
|
|
3
3
|
|
4
4
|
describe MTK::Pattern::Choice do
|
5
5
|
|
6
|
+
CHOICE = MTK::Pattern::Choice
|
7
|
+
|
6
8
|
let(:elements) { [1,2,3] }
|
7
|
-
let(:choice) {
|
9
|
+
let(:choice) { CHOICE.new elements }
|
8
10
|
|
9
11
|
describe "#next" do
|
10
12
|
it "randomly chooses one of the elements" do
|
@@ -12,10 +14,94 @@ describe MTK::Pattern::Choice do
|
|
12
14
|
100.times do
|
13
15
|
element = choice.next
|
14
16
|
choosen << element
|
15
|
-
elements.should include(element)
|
16
17
|
end
|
17
|
-
choosen.to_a.
|
18
|
+
choosen.to_a.should =~ elements
|
19
|
+
end
|
20
|
+
|
21
|
+
it "does a weighted random selection when a weights list is passed in via constructor options[:weights]" do
|
22
|
+
choice = CHOICE.new elements, :weights => [1,3,0] # only choose first 2 elements, and choose the second three times as often
|
23
|
+
choosen = Set.new
|
24
|
+
first_count, second_count = 0,0
|
25
|
+
100.times do
|
26
|
+
element = choice.next
|
27
|
+
choosen << element
|
28
|
+
first_count += 1 if element == elements[0]
|
29
|
+
second_count += 1 if element == elements[1]
|
30
|
+
end
|
31
|
+
choosen.to_a.should =~ elements[0..1]
|
32
|
+
(first_count + 10).should < second_count # this may occasional fail, but it seems unlikely
|
33
|
+
end
|
34
|
+
|
35
|
+
it "enumerates a choosen sub-sequence" do
|
36
|
+
choice = CHOICE.new [MTK::Pattern.Sequence(4,5,6)]
|
37
|
+
choice.next.should == 4
|
38
|
+
choice.next.should == 5
|
39
|
+
choice.next.should == 6
|
40
|
+
choice.next.should == 4 # now it will select a new choice, but there's only one, so it will be the same
|
41
|
+
choice.next.should == 5
|
42
|
+
choice.next.should == 6
|
18
43
|
end
|
19
44
|
end
|
20
45
|
|
21
46
|
end
|
47
|
+
|
48
|
+
|
49
|
+
describe MTK::Pattern do
|
50
|
+
|
51
|
+
describe "#Choice" do
|
52
|
+
it "creates a Choice" do
|
53
|
+
MTK::Pattern.Choice(1,2,3).should be_a MTK::Pattern::Choice
|
54
|
+
end
|
55
|
+
|
56
|
+
it "sets #elements from the varargs" do
|
57
|
+
MTK::Pattern.Choice(1,2,3).elements.should == [1,2,3]
|
58
|
+
end
|
59
|
+
|
60
|
+
it "does not set a type" do
|
61
|
+
MTK::Pattern.Choice(1,2,3).type.should be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#PitchChoice" do
|
66
|
+
it "creates a Choice" do
|
67
|
+
MTK::Pattern.PitchChoice(1,2,3).should be_a MTK::Pattern::Choice
|
68
|
+
end
|
69
|
+
|
70
|
+
it "sets #elements from the varargs" do
|
71
|
+
MTK::Pattern.PitchChoice(1,2,3).elements.should == [1,2,3]
|
72
|
+
end
|
73
|
+
|
74
|
+
it "sets #type to :pitch" do
|
75
|
+
MTK::Pattern.PitchChoice([]).type.should == :pitch
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#IntensityChoice" do
|
80
|
+
it "creates a Choice" do
|
81
|
+
MTK::Pattern.IntensityChoice(1,2,3).should be_a MTK::Pattern::Choice
|
82
|
+
end
|
83
|
+
|
84
|
+
it "sets #elements from the varargs" do
|
85
|
+
MTK::Pattern.IntensityChoice(1,2,3).elements.should == [1,2,3]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "sets #type to :pitch" do
|
89
|
+
MTK::Pattern.IntensityChoice([]).type.should == :intensity
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#DurationChoice" do
|
94
|
+
it "creates a Choice" do
|
95
|
+
MTK::Pattern.DurationChoice(1,2,3).should be_a MTK::Pattern::Choice
|
96
|
+
end
|
97
|
+
|
98
|
+
it "sets #elements from the varargs" do
|
99
|
+
MTK::Pattern.DurationChoice(1,2,3).elements.should == [1,2,3]
|
100
|
+
end
|
101
|
+
|
102
|
+
it "sets #type to :pitch" do
|
103
|
+
MTK::Pattern.DurationChoice([]).type.should == :duration
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Pattern::Cycle do
|
4
|
+
|
5
|
+
CYCLE = MTK::Pattern::Cycle
|
6
|
+
|
7
|
+
let(:elements) { [1, 2, 3] }
|
8
|
+
let(:cycle) { CYCLE.new elements }
|
9
|
+
|
10
|
+
describe "#next" do
|
11
|
+
it "iterates through the list of elements and emits them one at a time" do
|
12
|
+
cycle.next.should == elements[0]
|
13
|
+
cycle.next.should == elements[1]
|
14
|
+
cycle.next.should == elements[2]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "starts at the beginning of the list of elements after the end of the list is reached" do
|
18
|
+
elements.length.times do
|
19
|
+
cycle.next
|
20
|
+
end
|
21
|
+
cycle.next.should == elements.first
|
22
|
+
end
|
23
|
+
|
24
|
+
it "enumerates nested sequences" do
|
25
|
+
cycle = CYCLE.new [1, MTK::Pattern.Sequence(2,3), 4]
|
26
|
+
nexts = []
|
27
|
+
6.times { nexts << cycle.next }
|
28
|
+
nexts.should == [1,2,3,4,1,2]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#max_cycles" do
|
33
|
+
it "is the :max_cycles option the pattern was constructed with" do
|
34
|
+
CYCLE.new([], :max_cycles => 1).max_cycles.should == 1
|
35
|
+
end
|
36
|
+
|
37
|
+
it "is nil by default" do
|
38
|
+
cycle.max_cycles.should be_nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "causes a StopIteration exception after the number of cycles has completed" do
|
42
|
+
cycle = CYCLE.new(elements, :max_cycles => 2)
|
43
|
+
2.times do
|
44
|
+
elements.length.times { cycle.next } # one full cycle
|
45
|
+
end
|
46
|
+
lambda { cycle.next }.should raise_error
|
47
|
+
end
|
48
|
+
|
49
|
+
it "is maintained when applying Collection operations" do
|
50
|
+
CYCLE.new(elements, :max_cycles => 2).reverse.max_cycles.should == 2
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#max_elements" do
|
55
|
+
it "causes a StopIteration exception after the number of elements have been emitted" do
|
56
|
+
cycle = CYCLE.new(elements, :max_elements => 5)
|
57
|
+
5.times { cycle.next }
|
58
|
+
lambda { cycle.next }.should raise_error
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#rewind" do
|
63
|
+
it "restarts the cycle" do
|
64
|
+
(elements.length - 1).times do
|
65
|
+
cycle.next
|
66
|
+
end
|
67
|
+
cycle.rewind
|
68
|
+
cycle.next.should == elements.first
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
describe MTK::Pattern do
|
76
|
+
|
77
|
+
describe "#Cycle" do
|
78
|
+
it "creates a Cycle" do
|
79
|
+
MTK::Pattern.Cycle(1,2,3).should be_a MTK::Pattern::Cycle
|
80
|
+
end
|
81
|
+
|
82
|
+
it "sets #elements from the varargs" do
|
83
|
+
MTK::Pattern.Cycle(1,2,3).elements.should == [1,2,3]
|
84
|
+
end
|
85
|
+
|
86
|
+
it "does not set a type" do
|
87
|
+
MTK::Pattern.Cycle(1,2,3).type.should be_nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#PitchCycle" do
|
92
|
+
it "creates a Cycle" do
|
93
|
+
MTK::Pattern.PitchCycle(1,2,3).should be_a MTK::Pattern::Cycle
|
94
|
+
end
|
95
|
+
|
96
|
+
it "sets #elements from the varargs" do
|
97
|
+
MTK::Pattern.PitchCycle(1,2,3).elements.should == [1,2,3]
|
98
|
+
end
|
99
|
+
|
100
|
+
it "sets #type to :pitch" do
|
101
|
+
MTK::Pattern.PitchCycle([]).type.should == :pitch
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#IntensityCycle" do
|
106
|
+
it "creates a Cycle" do
|
107
|
+
MTK::Pattern.IntensityCycle(1,2,3).should be_a MTK::Pattern::Cycle
|
108
|
+
end
|
109
|
+
|
110
|
+
it "sets #elements from the varargs" do
|
111
|
+
MTK::Pattern.IntensityCycle(1,2,3).elements.should == [1,2,3]
|
112
|
+
end
|
113
|
+
|
114
|
+
it "sets #type to :pitch" do
|
115
|
+
MTK::Pattern.IntensityCycle([]).type.should == :intensity
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#DurationCycle" do
|
120
|
+
it "creates a Cycle" do
|
121
|
+
MTK::Pattern.DurationCycle(1,2,3).should be_a MTK::Pattern::Cycle
|
122
|
+
end
|
123
|
+
|
124
|
+
it "sets #elements from the varargs" do
|
125
|
+
MTK::Pattern.DurationCycle(1,2,3).elements.should == [1,2,3]
|
126
|
+
end
|
127
|
+
|
128
|
+
it "sets #type to :pitch" do
|
129
|
+
MTK::Pattern.DurationCycle([]).type.should == :duration
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Pattern::Function do
|
4
|
+
|
5
|
+
FUNCTION = MTK::Pattern::Function
|
6
|
+
|
7
|
+
describe "#next" do
|
8
|
+
it "calls a lambda to produce elements" do
|
9
|
+
function = FUNCTION.new lambda{ 1 + 1 }
|
10
|
+
function.next.should == 2
|
11
|
+
function.next.should == 2
|
12
|
+
end
|
13
|
+
|
14
|
+
it "calls a 1-arg lambda with the previous value" do
|
15
|
+
function = FUNCTION.new lambda{|prev| (prev || 0) + 1 }
|
16
|
+
function.next.should == 1
|
17
|
+
function.next.should == 2
|
18
|
+
function.next.should == 3
|
19
|
+
end
|
20
|
+
|
21
|
+
it "stops looping when the lambda raises StopIteration" do
|
22
|
+
function = FUNCTION.new lambda{|prev| raise StopIteration if prev == 2; (prev || 0) + 1 }
|
23
|
+
nexts = []
|
24
|
+
loop do
|
25
|
+
nexts << function.next
|
26
|
+
end
|
27
|
+
nexts.should == [1,2]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "calls a 2-arg lambda with the previous value and function call count (starting from 0)" do
|
31
|
+
function = FUNCTION.new lambda{|prev,index| [prev,index] }
|
32
|
+
function.next.should == [nil, 0]
|
33
|
+
function.next.should == [[nil,0], 1]
|
34
|
+
function.next.should == [[[nil,0],1], 2]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "calls a 3-arg lambda with the previous value, function call count (starting from 0), and element count (starting from 0)" do
|
38
|
+
function = FUNCTION.new lambda{|prev,call_index,elem_index| prev.nil? ? MTK::Pattern.Sequence(1,2,3,4) : [call_index,elem_index] }
|
39
|
+
function.next.should == 1
|
40
|
+
function.next.should == 2
|
41
|
+
function.next.should == 3
|
42
|
+
function.next.should == 4
|
43
|
+
function.next.should == [1,4]
|
44
|
+
end
|
45
|
+
|
46
|
+
it "can generate other Patterns, which will be iterated over before re-calling the function" do
|
47
|
+
function = FUNCTION.new lambda{|prev,index| MTK::Pattern.Sequence(index,2,3) }
|
48
|
+
function.next.should == 0
|
49
|
+
function.next.should == 2
|
50
|
+
function.next.should == 3
|
51
|
+
function.next.should == 1 # end of sequence, now a new one is generated, this time starting with 1
|
52
|
+
function.next.should == 2
|
53
|
+
function.next.should == 3
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#rewind" do
|
58
|
+
it "resets previous value and element count" do
|
59
|
+
function = FUNCTION.new lambda{|prev,index| [prev,index] }
|
60
|
+
function.next.should == [nil, 0]
|
61
|
+
function.next.should == [[nil,0], 1]
|
62
|
+
function.rewind
|
63
|
+
function.next.should == [nil, 0]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
describe MTK::Pattern do
|
71
|
+
|
72
|
+
describe "#Function" do
|
73
|
+
it "creates a Function" do
|
74
|
+
MTK::Pattern.Function(nil).should be_a MTK::Pattern::Function
|
75
|
+
end
|
76
|
+
|
77
|
+
it "sets #elements from the varargs" do
|
78
|
+
MTK::Pattern.Function(:mock_lambda).function.should == :mock_lambda
|
79
|
+
end
|
80
|
+
|
81
|
+
it "does not set a type" do
|
82
|
+
MTK::Pattern.Function(:mock_lambda).type.should be_nil
|
83
|
+
end
|
84
|
+
|
85
|
+
it "doesn't wrap a lambda in the varargs Array" do
|
86
|
+
function = MTK::Pattern.Function( lambda{ 1 + 1 } )
|
87
|
+
function.next.should == 2
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#PitchFunction" do
|
92
|
+
it "creates a Function" do
|
93
|
+
MTK::Pattern.PitchFunction(:mock_lambda).should be_a MTK::Pattern::Function
|
94
|
+
end
|
95
|
+
|
96
|
+
it "sets #elements from the varargs" do
|
97
|
+
MTK::Pattern.PitchFunction(:mock_lambda).function.should == :mock_lambda
|
98
|
+
end
|
99
|
+
|
100
|
+
it "sets #type to :pitch" do
|
101
|
+
MTK::Pattern.PitchFunction([]).type.should == :pitch
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#IntensityFunction" do
|
106
|
+
it "creates a Function" do
|
107
|
+
MTK::Pattern.IntensityFunction(:mock_lambda).should be_a MTK::Pattern::Function
|
108
|
+
end
|
109
|
+
|
110
|
+
it "sets #elements from the varargs" do
|
111
|
+
MTK::Pattern.IntensityFunction(:mock_lambda).function.should == :mock_lambda
|
112
|
+
end
|
113
|
+
|
114
|
+
it "sets #type to :pitch" do
|
115
|
+
MTK::Pattern.IntensityFunction([]).type.should == :intensity
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#DurationFunction" do
|
120
|
+
it "creates a Function" do
|
121
|
+
MTK::Pattern.DurationFunction(:mock_lambda).should be_a MTK::Pattern::Function
|
122
|
+
end
|
123
|
+
|
124
|
+
it "sets #elements from the varargs" do
|
125
|
+
MTK::Pattern.DurationFunction(:mock_lambda).function.should == :mock_lambda
|
126
|
+
end
|
127
|
+
|
128
|
+
it "sets #type to :pitch" do
|
129
|
+
MTK::Pattern.DurationFunction([]).type.should == :duration
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Pattern::Lines do
|
4
|
+
|
5
|
+
LINES = MTK::Pattern::Lines
|
6
|
+
|
7
|
+
let(:elements) { [0, [10,5], [5,10]] }
|
8
|
+
let(:lines) { LINES.new elements }
|
9
|
+
|
10
|
+
describe "#next" do
|
11
|
+
it "interpolates between values, treating each element as [value, steps_to_value] pairs" do
|
12
|
+
nexts = []
|
13
|
+
loop do
|
14
|
+
nexts << lines.next
|
15
|
+
end
|
16
|
+
nexts.should == [0, 2,4,6,8,10, 9.5,9,8.5,8,7.5,7,6.5,6,5.5,5]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#rewind" do
|
21
|
+
it "starts the pattern from the beginning" do
|
22
|
+
10.times { lines.next }
|
23
|
+
lines.rewind
|
24
|
+
nexts = []
|
25
|
+
loop do
|
26
|
+
nexts << lines.next
|
27
|
+
end
|
28
|
+
nexts.should == [0, 2,4,6,8,10, 9.5,9,8.5,8,7.5,7,6.5,6,5.5,5]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
describe MTK::Pattern do
|
36
|
+
|
37
|
+
describe "#Lines" do
|
38
|
+
it "creates a Lines" do
|
39
|
+
MTK::Pattern.Lines(1,2,3).should be_a MTK::Pattern::Lines
|
40
|
+
end
|
41
|
+
|
42
|
+
it "sets #elements from the varargs" do
|
43
|
+
MTK::Pattern.Lines(1,2,3).elements.should == [1,2,3]
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does not set a type" do
|
47
|
+
MTK::Pattern.Lines(1,2,3).type.should be_nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#PitchLines" do
|
52
|
+
it "creates a Lines" do
|
53
|
+
MTK::Pattern.PitchLines(1,2,3).should be_a MTK::Pattern::Lines
|
54
|
+
end
|
55
|
+
|
56
|
+
it "sets #elements from the varargs" do
|
57
|
+
MTK::Pattern.PitchLines(1,2,3).elements.should == [1,2,3]
|
58
|
+
end
|
59
|
+
|
60
|
+
it "sets #type to :pitch" do
|
61
|
+
MTK::Pattern.PitchLines([]).type.should == :pitch
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#IntensityLines" do
|
66
|
+
it "creates a Lines" do
|
67
|
+
MTK::Pattern.IntensityLines(1,2,3).should be_a MTK::Pattern::Lines
|
68
|
+
end
|
69
|
+
|
70
|
+
it "sets #elements from the varargs" do
|
71
|
+
MTK::Pattern.IntensityLines(1,2,3).elements.should == [1,2,3]
|
72
|
+
end
|
73
|
+
|
74
|
+
it "sets #type to :pitch" do
|
75
|
+
MTK::Pattern.IntensityLines([]).type.should == :intensity
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#DurationLines" do
|
80
|
+
it "creates a Lines" do
|
81
|
+
MTK::Pattern.DurationLines(1,2,3).should be_a MTK::Pattern::Lines
|
82
|
+
end
|
83
|
+
|
84
|
+
it "sets #elements from the varargs" do
|
85
|
+
MTK::Pattern.DurationLines(1,2,3).elements.should == [1,2,3]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "sets #type to :pitch" do
|
89
|
+
MTK::Pattern.DurationLines([]).type.should == :duration
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Pattern::NoteCycle do
|
4
|
+
|
5
|
+
def note(pitch, intensity=mf, duration=1)
|
6
|
+
Note(pitch, intensity, duration)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#new" do
|
10
|
+
it "allows default pitch to be specified" do
|
11
|
+
cycle = Pattern::NoteCycle.new [], [p], [1], :pitch => Gb4
|
12
|
+
cycle.next.should == Note(Gb4, p, 1)
|
13
|
+
end
|
14
|
+
it "allows default intensity to be specified" do
|
15
|
+
cycle = Pattern::NoteCycle.new [C4], [], [1], :intensity => ppp
|
16
|
+
cycle.next.should == Note(C4, ppp, 1)
|
17
|
+
end
|
18
|
+
it "allows default duration to be specified" do
|
19
|
+
cycle = Pattern::NoteCycle.new [C4], [mf], [], :duration => 12
|
20
|
+
cycle.next.should == Note(C4, mf, 12)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#next" do
|
25
|
+
it "iterates through the pitch, intensity, and duration list in parallel to emit Notes" do
|
26
|
+
cycle = Pattern::NoteCycle.new [C4, D4, E4], [p, f], [1,2,3,4]
|
27
|
+
cycle.next.should == Note(C4, p, 1)
|
28
|
+
cycle.next.should == Note(D4, f, 2)
|
29
|
+
cycle.next.should == Note(E4, p, 3)
|
30
|
+
cycle.next.should == Note(C4, f, 4)
|
31
|
+
cycle.next.should == Note(D4, p, 1)
|
32
|
+
cycle.next.should == Note(E4, f, 2)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "defaults to Pitch 'C4' when no pitches are given" do
|
36
|
+
cycle = Pattern::NoteCycle.new [], [p,f], [1,2,3]
|
37
|
+
cycle.next.should == Note(C4, p, 1)
|
38
|
+
cycle.next.should == Note(C4, f, 2)
|
39
|
+
cycle.next.should == Note(C4, p, 3)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "defaults to intensity 'mf' when no intensities are given" do
|
43
|
+
cycle = Pattern::NoteCycle.new [C4, D4, E4], nil, [2]
|
44
|
+
cycle.next.should == Note(C4, mf, 2)
|
45
|
+
cycle.next.should == Note(D4, mf, 2)
|
46
|
+
cycle.next.should == Note(E4, mf, 2)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "defaults to duration 1 when no durations are given" do
|
50
|
+
cycle = Pattern::NoteCycle.new [C4, D4, E4], [p, f]
|
51
|
+
cycle.next.should == Note(C4, p, 1)
|
52
|
+
cycle.next.should == Note(D4, f, 1)
|
53
|
+
cycle.next.should == Note(E4, p, 1)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "uses the previous pitch/intensity/duration when it encounters a nil value" do
|
57
|
+
cycle = Pattern::NoteCycle.new [C4, D4, E4, F4, nil], [mp, mf, f, nil], [1, 2, nil]
|
58
|
+
cycle.next.should == Note(C4, mp, 1)
|
59
|
+
cycle.next.should == Note(D4, mf, 2)
|
60
|
+
cycle.next.should == Note(E4, f, 2)
|
61
|
+
cycle.next.should == Note(F4, f, 1)
|
62
|
+
cycle.next.should == Note(F4, mp, 2)
|
63
|
+
cycle.next.should == Note(C4, mf, 2)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "adds Numeric intervals in the pitch list to the previous pitch" do
|
67
|
+
cycle = Pattern::NoteCycle.new [C4, 1, 2, 3]
|
68
|
+
cycle.next.should == note(C4)
|
69
|
+
cycle.next.should == note(C4+1)
|
70
|
+
cycle.next.should == note(C4+1+2)
|
71
|
+
cycle.next.should == note(C4+1+2+3)
|
72
|
+
cycle.next.should == note(C4)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "goes to the nearest Pitch for any PitchClasses in the pitch list" do
|
76
|
+
cycle = Pattern::NoteCycle.new [C4, F, C, G, C]
|
77
|
+
cycle.next.should == note(C4)
|
78
|
+
cycle.next.should == note(F4)
|
79
|
+
cycle.next.should == note(C4)
|
80
|
+
cycle.next.should == note(G3)
|
81
|
+
cycle.next.should == note(C4)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "does not endlessly ascend or descend when alternating between two pitch classes a tritone apart" do
|
85
|
+
cycle = Pattern::NoteCycle.new [C4, Gb, C, Gb, C]
|
86
|
+
cycle.next.should == note(C4)
|
87
|
+
cycle.next.should == note(Gb4)
|
88
|
+
cycle.next.should == note(C4)
|
89
|
+
cycle.next.should == note(Gb4)
|
90
|
+
cycle.next.should == note(C4)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "cycles Note Arrays for pitch list items that are PitchSets" do
|
94
|
+
cycle = Pattern::NoteCycle.new [PitchSet.new([C4, E4, G4]), C4, PitchSet.new([D4, F4, A4])]
|
95
|
+
cycle.next.should == [note(C4), note(E4), note(G4)]
|
96
|
+
cycle.next.should == note(C4)
|
97
|
+
cycle.next.should == [note(D4), note(F4), note(A4)]
|
98
|
+
end
|
99
|
+
|
100
|
+
it "adds numeric intervals to PitchSets" do
|
101
|
+
cycle = Pattern::NoteCycle.new [PitchSet.new([C4, E4, G4]), 2]
|
102
|
+
cycle.next.should == [note(C4), note(E4), note(G4)]
|
103
|
+
cycle.next.should == [note(D4), note(Gb4), note(A4)]
|
104
|
+
end
|
105
|
+
|
106
|
+
it "goes to the nearest Pitch relative to the lowest note in the PitchSet for any PitchClasses in the pitch list" do
|
107
|
+
cycle = Pattern::NoteCycle.new [PitchSet.new([C4, E4, G4]), F, D, Bb]
|
108
|
+
cycle.next.should == [note(C4), note(E4), note(G4)]
|
109
|
+
cycle.next.should == [note(F4), note(A4), note(C5)]
|
110
|
+
cycle.next.should == [note(D4), note(Gb4), note(A4)]
|
111
|
+
cycle.next.should == [note(Bb3), note(D4), note(F4)]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
end
|