mtk 0.0.1 → 0.0.2
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.
- 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
|