mtk 0.0.2 → 0.0.3

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.
Files changed (147) hide show
  1. data/.yardopts +3 -2
  2. data/DEVELOPMENT_NOTES.md +114 -0
  3. data/INTRO.md +64 -8
  4. data/LICENSE.txt +1 -1
  5. data/README.md +31 -102
  6. data/Rakefile +56 -18
  7. data/bin/mtk +215 -0
  8. data/examples/crescendo.rb +5 -5
  9. data/examples/drum_pattern1.rb +23 -0
  10. data/examples/dynamic_pattern.rb +8 -11
  11. data/examples/gets_and_play.rb +26 -0
  12. data/examples/notation.rb +22 -0
  13. data/examples/play_midi.rb +8 -10
  14. data/examples/random_tone_row.rb +2 -2
  15. data/examples/syntax_to_midi.rb +28 -0
  16. data/examples/test_output.rb +8 -0
  17. data/examples/tone_row_melody.rb +6 -6
  18. data/lib/mtk.rb +52 -40
  19. data/lib/mtk/chord.rb +55 -0
  20. data/lib/mtk/constants/durations.rb +57 -0
  21. data/lib/mtk/constants/intensities.rb +61 -0
  22. data/lib/mtk/constants/intervals.rb +73 -0
  23. data/lib/mtk/constants/pitch_classes.rb +29 -0
  24. data/lib/mtk/constants/pitches.rb +52 -0
  25. data/lib/mtk/duration.rb +211 -0
  26. data/lib/mtk/events/event.rb +119 -0
  27. data/lib/mtk/events/note.rb +112 -0
  28. data/lib/mtk/events/parameter.rb +54 -0
  29. data/lib/mtk/helpers/collection.rb +164 -0
  30. data/lib/mtk/helpers/convert.rb +36 -0
  31. data/lib/mtk/helpers/lilypond.rb +162 -0
  32. data/lib/mtk/helpers/output_selector.rb +67 -0
  33. data/lib/mtk/helpers/pitch_collection.rb +23 -0
  34. data/lib/mtk/helpers/pseudo_constants.rb +26 -0
  35. data/lib/mtk/intensity.rb +156 -0
  36. data/lib/mtk/interval.rb +155 -0
  37. data/lib/mtk/lang/mtk_grammar.citrus +190 -13
  38. data/lib/mtk/lang/parser.rb +29 -0
  39. data/lib/mtk/melody.rb +94 -0
  40. data/lib/mtk/midi/dls_synth_device.rb +144 -0
  41. data/lib/mtk/midi/dls_synth_output.rb +62 -0
  42. data/lib/mtk/midi/file.rb +67 -32
  43. data/lib/mtk/midi/input.rb +97 -0
  44. data/lib/mtk/midi/jsound_input.rb +36 -17
  45. data/lib/mtk/midi/jsound_output.rb +48 -46
  46. data/lib/mtk/midi/output.rb +195 -0
  47. data/lib/mtk/midi/unimidi_input.rb +117 -0
  48. data/lib/mtk/midi/unimidi_output.rb +121 -0
  49. data/lib/mtk/{_numeric_extensions.rb → numeric_extensions.rb} +12 -0
  50. data/lib/mtk/patterns/chain.rb +49 -0
  51. data/lib/mtk/{pattern → patterns}/choice.rb +14 -8
  52. data/lib/mtk/patterns/cycle.rb +18 -0
  53. data/lib/mtk/patterns/for_each.rb +71 -0
  54. data/lib/mtk/patterns/function.rb +39 -0
  55. data/lib/mtk/{pattern → patterns}/lines.rb +11 -17
  56. data/lib/mtk/{pattern → patterns}/palindrome.rb +11 -8
  57. data/lib/mtk/patterns/pattern.rb +171 -0
  58. data/lib/mtk/patterns/sequence.rb +20 -0
  59. data/lib/mtk/pitch.rb +7 -6
  60. data/lib/mtk/pitch_class.rb +124 -46
  61. data/lib/mtk/pitch_class_set.rb +58 -35
  62. data/lib/mtk/sequencers/event_builder.rb +131 -0
  63. data/lib/mtk/sequencers/legato_sequencer.rb +24 -0
  64. data/lib/mtk/sequencers/rhythmic_sequencer.rb +28 -0
  65. data/lib/mtk/{sequencer/abstract_sequencer.rb → sequencers/sequencer.rb} +37 -11
  66. data/lib/mtk/{sequencer → sequencers}/step_sequencer.rb +4 -4
  67. data/lib/mtk/timeline.rb +39 -22
  68. data/lib/mtk/variable.rb +32 -0
  69. data/spec/mtk/chord_spec.rb +83 -0
  70. data/spec/mtk/{_constants → constants}/durations_spec.rb +12 -41
  71. data/spec/mtk/{_constants → constants}/intensities_spec.rb +13 -37
  72. data/spec/mtk/{_constants → constants}/intervals_spec.rb +14 -32
  73. data/spec/mtk/{_constants → constants}/pitch_classes_spec.rb +8 -4
  74. data/spec/mtk/{_constants → constants}/pitches_spec.rb +5 -1
  75. data/spec/mtk/duration_spec.rb +372 -0
  76. data/spec/mtk/events/event_spec.rb +234 -0
  77. data/spec/mtk/events/note_spec.rb +174 -0
  78. data/spec/mtk/events/parameter_spec.rb +220 -0
  79. data/spec/mtk/{helper → helpers}/collection_spec.rb +86 -3
  80. data/spec/mtk/{helper → helpers}/pseudo_constants_spec.rb +2 -2
  81. data/spec/mtk/intensity_spec.rb +289 -0
  82. data/spec/mtk/interval_spec.rb +265 -0
  83. data/spec/mtk/lang/parser_spec.rb +597 -0
  84. data/spec/mtk/melody_spec.rb +223 -0
  85. data/spec/mtk/midi/file_spec.rb +16 -16
  86. data/spec/mtk/midi/jsound_input_spec.rb +11 -0
  87. data/spec/mtk/midi/jsound_output_spec.rb +11 -0
  88. data/spec/mtk/midi/output_spec.rb +102 -0
  89. data/spec/mtk/midi/unimidi_input_spec.rb +11 -0
  90. data/spec/mtk/midi/unimidi_output_spec.rb +11 -0
  91. data/spec/mtk/{_numeric_extensions_spec.rb → numeric_extensions_spec.rb} +1 -0
  92. data/spec/mtk/patterns/chain_spec.rb +110 -0
  93. data/spec/mtk/{pattern → patterns}/choice_spec.rb +20 -30
  94. data/spec/mtk/{pattern → patterns}/cycle_spec.rb +25 -35
  95. data/spec/mtk/patterns/for_each_spec.rb +136 -0
  96. data/spec/mtk/{pattern → patterns}/function_spec.rb +17 -30
  97. data/spec/mtk/{pattern → patterns}/lines_spec.rb +11 -27
  98. data/spec/mtk/{pattern → patterns}/palindrome_spec.rb +13 -29
  99. data/spec/mtk/patterns/pattern_spec.rb +132 -0
  100. data/spec/mtk/patterns/sequence_spec.rb +203 -0
  101. data/spec/mtk/pitch_class_set_spec.rb +23 -21
  102. data/spec/mtk/pitch_class_spec.rb +151 -39
  103. data/spec/mtk/pitch_spec.rb +22 -1
  104. data/spec/mtk/sequencers/event_builder_spec.rb +245 -0
  105. data/spec/mtk/sequencers/legato_sequencer_spec.rb +45 -0
  106. data/spec/mtk/sequencers/rhythmic_sequencer_spec.rb +84 -0
  107. data/spec/mtk/sequencers/sequencer_spec.rb +215 -0
  108. data/spec/mtk/{sequencer → sequencers}/step_sequencer_spec.rb +35 -13
  109. data/spec/mtk/timeline_spec.rb +109 -16
  110. data/spec/mtk/variable_spec.rb +52 -0
  111. data/spec/spec_coverage.rb +2 -0
  112. data/spec/spec_helper.rb +3 -0
  113. metadata +188 -91
  114. data/lib/mtk/_constants/durations.rb +0 -80
  115. data/lib/mtk/_constants/intensities.rb +0 -81
  116. data/lib/mtk/_constants/intervals.rb +0 -85
  117. data/lib/mtk/_constants/pitch_classes.rb +0 -35
  118. data/lib/mtk/_constants/pitches.rb +0 -49
  119. data/lib/mtk/event.rb +0 -70
  120. data/lib/mtk/helper/collection.rb +0 -114
  121. data/lib/mtk/helper/event_builder.rb +0 -85
  122. data/lib/mtk/helper/pseudo_constants.rb +0 -26
  123. data/lib/mtk/lang/grammar.rb +0 -17
  124. data/lib/mtk/note.rb +0 -63
  125. data/lib/mtk/pattern/abstract_pattern.rb +0 -132
  126. data/lib/mtk/pattern/cycle.rb +0 -51
  127. data/lib/mtk/pattern/enumerator.rb +0 -26
  128. data/lib/mtk/pattern/function.rb +0 -46
  129. data/lib/mtk/pattern/sequence.rb +0 -30
  130. data/lib/mtk/pitch_set.rb +0 -84
  131. data/lib/mtk/sequencer/rhythmic_sequencer.rb +0 -29
  132. data/lib/mtk/transform/invertible.rb +0 -15
  133. data/lib/mtk/transform/mappable.rb +0 -18
  134. data/lib/mtk/transform/set_theory_operations.rb +0 -34
  135. data/lib/mtk/transform/transposable.rb +0 -14
  136. data/spec/mtk/event_spec.rb +0 -139
  137. data/spec/mtk/helper/event_builder_spec.rb +0 -92
  138. data/spec/mtk/lang/grammar_spec.rb +0 -100
  139. data/spec/mtk/note_spec.rb +0 -115
  140. data/spec/mtk/pattern/abstract_pattern_spec.rb +0 -45
  141. data/spec/mtk/pattern/note_cycle_spec.rb.bak +0 -116
  142. data/spec/mtk/pattern/pitch_cycle_spec.rb.bak +0 -47
  143. data/spec/mtk/pattern/pitch_sequence_spec.rb.bak +0 -37
  144. data/spec/mtk/pattern/sequence_spec.rb +0 -151
  145. data/spec/mtk/pitch_set_spec.rb +0 -198
  146. data/spec/mtk/sequencer/abstract_sequencer_spec.rb +0 -159
  147. data/spec/mtk/sequencer/rhythmic_sequencer_spec.rb +0 -49
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+
3
+ describe MTK::Patterns::Chain do
4
+
5
+ CHAIN = MTK::Patterns::Chain
6
+
7
+ describe '#next' do
8
+ it 'combines 2 basic attributes together' do
9
+ chain = CHAIN.new [C,q]
10
+ chain.next.should == [C,q]
11
+ end
12
+
13
+ it 'combines 3 basic attributes together' do
14
+ chain = CHAIN.new [C,q,mp]
15
+ chain.next.should == [C,q,mp]
16
+ end
17
+
18
+ it 'combines many basic attributes together, including duplicate types' do
19
+ chain = CHAIN.new [C,q,D,h,s,mp,fff]
20
+ chain.next.should == [C,q,D,h,s,mp,fff]
21
+ end
22
+
23
+ it 'raises StopIteration after a basic-attribute-only chain has called #next more than once' do
24
+ chain = CHAIN.new [C,q]
25
+ chain.next
26
+ lambda{ chain.next }.should raise_error StopIteration
27
+ end
28
+
29
+ it 'combines a basic attribute with a pattern' do
30
+ chain = CHAIN.new [Patterns.Sequence(C,D,E), q]
31
+ chain.next.should == [C,q]
32
+ chain.next.should == [D,q]
33
+ chain.next.should == [E,q]
34
+ lambda{ chain.next }.should raise_error StopIteration
35
+ end
36
+
37
+ it 'combines 2 patterns' do
38
+ chain = CHAIN.new [Patterns.Sequence(C,D,E), Patterns.Sequence(w,h,q)]
39
+ chain.next.should == [C,w]
40
+ chain.next.should == [D,h]
41
+ chain.next.should == [E,q]
42
+ lambda{ chain.next }.should raise_error StopIteration
43
+ end
44
+
45
+ it 'combines 2 patterns, and returns #next until the last StopIteration of a nested Pattern occurs' do
46
+ chain = CHAIN.new [Patterns.Sequence(C,D,E), Patterns.Sequence(w,h,q,i)]
47
+ chain.next.should == [C,w]
48
+ chain.next.should == [D,h]
49
+ chain.next.should == [E,q]
50
+ chain.next.should == [C,i]
51
+ lambda{ chain.next }.should raise_error StopIteration
52
+ end
53
+
54
+
55
+ # TODO: more than 2 patterns, and more than 2 + basic attribute(s)
56
+
57
+
58
+ it 'combines Choice patterns with max_cycles' do
59
+ chain = CHAIN.new [Patterns.Choice(i,s), Patterns.Choice(C,D,E)], max_cycles:100
60
+ 100.times do |time|
61
+ attrs = chain.next
62
+ attrs.length.should == 2
63
+ (attrs[0]==i or attrs[0]==s).should be_true
64
+ (attrs[1]==C or attrs[1]==D or attrs[1]==E).should be_true
65
+ end
66
+ lambda{ chain.next }.should raise_error StopIteration
67
+ end
68
+
69
+ it 'combines Choice patterns and emits a only single combination of attributes by default' do
70
+ chain = CHAIN.new [Patterns.Choice(i,s), Patterns.Choice(C,D,E)]
71
+ chain.next
72
+ lambda{ chain.next }.should raise_error StopIteration
73
+ end
74
+
75
+ it 'flattens attribute lists with nested chains' do
76
+ chain = CHAIN.new( [1, 2, CHAIN.new([3, CHAIN.new([4,5])])] )
77
+ chain.next.should == [1,2,3,4,5]
78
+ end
79
+
80
+ it 'throws StopIteration when any subpattern throws StopIteration with max_elements_exceeded' do
81
+ chain = CHAIN.new [Patterns.Sequence(C,D,E,F,G), Patterns.Sequence(w,h,q,i, max_elements:3)]
82
+ chain.next.should == [C,w]
83
+ chain.next.should == [D,h]
84
+ chain.next.should == [E,q]
85
+ lambda{ chain.next }.should raise_error StopIteration
86
+ end
87
+
88
+ it 'throws StopIteration with max_elements_exceeded (edge case actual element length == max_elements)' do
89
+ chain = CHAIN.new [Patterns.Sequence(C,D,E,F,G), Patterns.Sequence(w,h,q, max_elements:3)]
90
+ chain.next.should == [C,w]
91
+ chain.next.should == [D,h]
92
+ chain.next.should == [E,q]
93
+ lambda{ chain.next }.should raise_error StopIteration
94
+ end
95
+ end
96
+
97
+ describe '#rewind' do
98
+ it 'resets the state of the Chain' do
99
+ # compare with the #next, raises StopIteration test above
100
+ chain = CHAIN.new [C,q]
101
+ chain.next
102
+ chain.rewind
103
+ lambda{ chain.next }.should_not raise_error StopIteration
104
+ lambda{ chain.next }.should raise_error StopIteration
105
+ end
106
+ end
107
+
108
+ # TODO: test the chain builder method in Patterns module
109
+
110
+ end
@@ -1,14 +1,20 @@
1
1
  require 'spec_helper'
2
2
  require 'set'
3
3
 
4
- describe MTK::Pattern::Choice do
4
+ describe MTK::Patterns::Choice do
5
5
 
6
- CHOICE = MTK::Pattern::Choice
6
+ CHOICE = MTK::Patterns::Choice
7
7
 
8
8
  let(:elements) { [1,2,3] }
9
- let(:choice) { CHOICE.new elements }
9
+ let(:choice) { CHOICE.new elements, max_cycles:500 }
10
10
 
11
11
  describe "#next" do
12
+ it "throws StopIteration on the second call to #next, by default" do
13
+ choice = CHOICE.new elements
14
+ choice.next
15
+ lambda{ choice.next }.should raise_error StopIteration
16
+ end
17
+
12
18
  it "randomly chooses one of the elements" do
13
19
  choosen = Set.new
14
20
  100.times do
@@ -19,7 +25,7 @@ describe MTK::Pattern::Choice do
19
25
  end
20
26
 
21
27
  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
28
+ choice = CHOICE.new elements, max_cycles:100, weights:[1,3,0] # only choose first 2 elements, and choose the second three times as often
23
29
  choosen = Set.new
24
30
  first_count, second_count = 0,0
25
31
  100.times do
@@ -33,7 +39,7 @@ describe MTK::Pattern::Choice do
33
39
  end
34
40
 
35
41
  it "enumerates a choosen sub-sequence" do
36
- choice = CHOICE.new [MTK::Pattern.Sequence(4,5,6)]
42
+ choice = CHOICE.new [MTK::Patterns.Sequence(4,5,6)], max_cycles:10
37
43
  choice.next.should == 4
38
44
  choice.next.should == 5
39
45
  choice.next.should == 6
@@ -46,61 +52,45 @@ describe MTK::Pattern::Choice do
46
52
  end
47
53
 
48
54
 
49
- describe MTK::Pattern do
55
+ describe MTK::Patterns do
50
56
 
51
57
  describe "#Choice" do
52
58
  it "creates a Choice" do
53
- MTK::Pattern.Choice(1,2,3).should be_a MTK::Pattern::Choice
59
+ MTK::Patterns.Choice(1,2,3).should be_a MTK::Patterns::Choice
54
60
  end
55
61
 
56
62
  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
63
+ MTK::Patterns.Choice(1,2,3).elements.should == [1,2,3]
62
64
  end
63
65
  end
64
66
 
65
67
  describe "#PitchChoice" do
66
68
  it "creates a Choice" do
67
- MTK::Pattern.PitchChoice(1,2,3).should be_a MTK::Pattern::Choice
69
+ MTK::Patterns.PitchChoice(1,2,3).should be_a MTK::Patterns::Choice
68
70
  end
69
71
 
70
72
  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
73
+ MTK::Patterns.PitchChoice(1,2,3).elements.should == [Pitch(1),Pitch(2),Pitch(3)]
76
74
  end
77
75
  end
78
76
 
79
77
  describe "#IntensityChoice" do
80
78
  it "creates a Choice" do
81
- MTK::Pattern.IntensityChoice(1,2,3).should be_a MTK::Pattern::Choice
79
+ MTK::Patterns.IntensityChoice(1,2,3).should be_a MTK::Patterns::Choice
82
80
  end
83
81
 
84
82
  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
83
+ MTK::Patterns.IntensityChoice(1,2,3).elements.should == [Intensity(1),Intensity(2),Intensity(3)]
90
84
  end
91
85
  end
92
86
 
93
87
  describe "#DurationChoice" do
94
88
  it "creates a Choice" do
95
- MTK::Pattern.DurationChoice(1,2,3).should be_a MTK::Pattern::Choice
89
+ MTK::Patterns.DurationChoice(1,2,3).should be_a MTK::Patterns::Choice
96
90
  end
97
91
 
98
92
  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
93
+ MTK::Patterns.DurationChoice(1,2,3).elements.should == [q,h,h+q]
104
94
  end
105
95
  end
106
96
 
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe MTK::Pattern::Cycle do
3
+ describe MTK::Patterns::Cycle do
4
4
 
5
- CYCLE = MTK::Pattern::Cycle
5
+ CYCLE = MTK::Patterns::Cycle
6
6
 
7
7
  let(:elements) { [1, 2, 3] }
8
8
  let(:cycle) { CYCLE.new elements }
@@ -22,14 +22,14 @@ describe MTK::Pattern::Cycle do
22
22
  end
23
23
 
24
24
  it "enumerates nested sequences" do
25
- cycle = CYCLE.new [1, MTK::Pattern.Sequence(2,3), 4]
25
+ cycle = CYCLE.new [1, MTK::Patterns.Sequence(2,3), 4]
26
26
  nexts = []
27
27
  6.times { nexts << cycle.next }
28
28
  nexts.should == [1,2,3,4,1,2]
29
29
  end
30
30
  end
31
31
 
32
- describe "#max_cycles" do
32
+ describe "@max_cycles" do
33
33
  it "is the :max_cycles option the pattern was constructed with" do
34
34
  CYCLE.new([], :max_cycles => 1).max_cycles.should == 1
35
35
  end
@@ -38,6 +38,10 @@ describe MTK::Pattern::Cycle do
38
38
  cycle.max_cycles.should be_nil
39
39
  end
40
40
 
41
+ it "loops indefinitely when it's nil" do
42
+ lambda { 100.times { cycle.next } }.should_not raise_error
43
+ end
44
+
41
45
  it "causes a StopIteration exception after the number of cycles has completed" do
42
46
  cycle = CYCLE.new(elements, :max_cycles => 2)
43
47
  2.times do
@@ -45,17 +49,19 @@ describe MTK::Pattern::Cycle do
45
49
  end
46
50
  lambda { cycle.next }.should raise_error
47
51
  end
52
+ end
48
53
 
49
- it "is maintained when applying Collection operations" do
50
- CYCLE.new(elements, :max_cycles => 2).reverse.max_cycles.should == 2
54
+ describe "@max_elements" do
55
+ it "causes a StopIteration exception after the number of elements have been emitted, with a higher max_cycles" do
56
+ cycle = CYCLE.new(elements, max_cycles:2, max_elements:5)
57
+ 5.times { cycle.next }
58
+ lambda { cycle.next }.should raise_error StopIteration
51
59
  end
52
- end
53
60
 
54
- describe "#max_elements" do
55
61
  it "causes a StopIteration exception after the number of elements have been emitted" do
56
- cycle = CYCLE.new(elements, :max_elements => 5)
62
+ cycle = CYCLE.new(elements, max_elements:5)
57
63
  5.times { cycle.next }
58
- lambda { cycle.next }.should raise_error
64
+ lambda { cycle.next }.should raise_error StopIteration
59
65
  end
60
66
  end
61
67
 
@@ -72,61 +78,45 @@ describe MTK::Pattern::Cycle do
72
78
  end
73
79
 
74
80
 
75
- describe MTK::Pattern do
81
+ describe MTK::Patterns do
76
82
 
77
83
  describe "#Cycle" do
78
84
  it "creates a Cycle" do
79
- MTK::Pattern.Cycle(1,2,3).should be_a MTK::Pattern::Cycle
85
+ MTK::Patterns.Cycle(1,2,3).should be_a MTK::Patterns::Cycle
80
86
  end
81
87
 
82
88
  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
89
+ MTK::Patterns.Cycle(1,2,3).elements.should == [1,2,3]
88
90
  end
89
91
  end
90
92
 
91
93
  describe "#PitchCycle" do
92
94
  it "creates a Cycle" do
93
- MTK::Pattern.PitchCycle(1,2,3).should be_a MTK::Pattern::Cycle
95
+ MTK::Patterns.PitchCycle(1,2,3).should be_a MTK::Patterns::Cycle
94
96
  end
95
97
 
96
98
  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
99
+ MTK::Patterns.PitchCycle(1,2,3).elements.should == [Pitch(1),Pitch(2),Pitch(3)]
102
100
  end
103
101
  end
104
102
 
105
103
  describe "#IntensityCycle" do
106
104
  it "creates a Cycle" do
107
- MTK::Pattern.IntensityCycle(1,2,3).should be_a MTK::Pattern::Cycle
105
+ MTK::Patterns.IntensityCycle(1,2,3).should be_a MTK::Patterns::Cycle
108
106
  end
109
107
 
110
108
  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
109
+ MTK::Patterns.IntensityCycle(1,2,3).elements.should == [Intensity(1),Intensity(2),Intensity(3)]
116
110
  end
117
111
  end
118
112
 
119
113
  describe "#DurationCycle" do
120
114
  it "creates a Cycle" do
121
- MTK::Pattern.DurationCycle(1,2,3).should be_a MTK::Pattern::Cycle
115
+ MTK::Patterns.DurationCycle(1,2,3).should be_a MTK::Patterns::Cycle
122
116
  end
123
117
 
124
118
  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
119
+ MTK::Patterns.DurationCycle(1,2,3).elements.should == [Duration(1),Duration(2),Duration(3)]
130
120
  end
131
121
  end
132
122
 
@@ -0,0 +1,136 @@
1
+ require 'spec_helper'
2
+
3
+ describe MTK::Patterns::ForEach do
4
+
5
+ FOREACH = ::MTK::Patterns::ForEach
6
+
7
+ def var(name)
8
+ ::MTK::Variable.new(name)
9
+ end
10
+
11
+ def seq(*args)
12
+ ::MTK::Patterns.Sequence(*args)
13
+ end
14
+
15
+ def chain(*args)
16
+ ::MTK::Patterns.Chain(*args)
17
+ end
18
+
19
+
20
+ describe "#elements" do
21
+ it "is the array the sequence was constructed with" do
22
+ FOREACH.new([seq(1,2),seq(3,4)]).elements.should == [seq(1,2),seq(3,4)]
23
+ end
24
+ end
25
+
26
+ describe "#next" do
27
+ it "enumerates each element in the second pattern for each element in the first, with variable '$' as the first pattern's current element" do
28
+ foreach = FOREACH.new [ seq(C,D,E), seq(var('$'),G,A) ]
29
+ vals = []
30
+ 9.times{ vals << foreach.next }
31
+ lambda{ foreach.next }.should raise_error StopIteration
32
+ vals.should == [C,G,A,D,G,A,E,G,A]
33
+ end
34
+
35
+ it "enumerates the foreach construct with a variable in the middle of the second pattern" do
36
+ foreach = FOREACH.new [ seq(C,D,E), seq(G,var('$'),A) ]
37
+ vals = []
38
+ 9.times{ vals << foreach.next }
39
+ lambda{ foreach.next }.should raise_error StopIteration
40
+ vals.should == [G,C,A,G,D,A,G,E,A]
41
+ end
42
+
43
+ it "enumerates the foreach construct with multiple variables" do
44
+ foreach = FOREACH.new [ seq(C,D,E), seq(G,var('$'),A,var('$')) ]
45
+ vals = []
46
+ 12.times{ vals << foreach.next }
47
+ lambda{ foreach.next }.should raise_error StopIteration
48
+ vals.should == [G,C,A,C,G,D,A,D,G,E,A,E]
49
+ end
50
+
51
+ it "handles 3-level nesting" do
52
+ foreach = FOREACH.new [ seq(C,D), seq(var('$'),F), seq(G,var('$')) ]
53
+ vals = []
54
+ 8.times{ vals << foreach.next }
55
+ lambda{ foreach.next }.should raise_error StopIteration
56
+ vals.should == [G,C,G,F,G,D,G,F]
57
+ end
58
+
59
+ it "handles 4-level nesting" do
60
+ foreach = FOREACH.new [ seq(C,D), seq(var('$'),E), seq(F,var('$')), seq(var('$'),G) ]
61
+ vals = []
62
+ 16.times{ vals << foreach.next }
63
+ lambda{ foreach.next }.should raise_error StopIteration
64
+ vals.should == [F,G,C,G,F,G,E,G,F,G,D,G,F,G,E,G]
65
+ end
66
+
67
+ it "evaluates the '$$' var by going back 2 levels in the variables stack" do
68
+ foreach = FOREACH.new [ seq(C,D), seq(E,F), seq(var('$$'),var('$')) ]
69
+ vals = []
70
+ 8.times{ vals << foreach.next }
71
+ lambda{ foreach.next }.should raise_error StopIteration
72
+ vals.should == [C,E,C,F,D,E,D,F]
73
+ end
74
+
75
+
76
+ it "evaluates the '$$$' var by going back 3 levels in the variables stack" do
77
+ foreach = FOREACH.new [ seq(C,D), seq(E,F), seq(G,A), seq(var('$$$'),var('$$'),var('$')) ]
78
+ vals = []
79
+ 24.times{ vals << foreach.next }
80
+ lambda{ foreach.next }.should raise_error StopIteration
81
+ vals.should == [C,E,G,C,E,A,C,F,G,C,F,A,D,E,G,D,E,A,D,F,G,D,F,A]
82
+ end
83
+
84
+ it "evaluates nested variables" do
85
+ # (C4 Bb Ab G)@( (C D C $):(q i i)*4:(mp mf) )
86
+ foreach = FOREACH.new( [seq(G,A), chain(seq(C,D,var('$')),seq(q,i,s))] )
87
+ vals = []
88
+ 6.times{ vals << foreach.next }
89
+ lambda{ foreach.next }.should raise_error StopIteration
90
+ vals.should == [[C,q],[D,i],[G,s],[C,q],[D,i],[A,s]]
91
+ end
92
+
93
+ end
94
+
95
+
96
+
97
+ describe "#rewind" do
98
+ it "restarts at the beginning of the sequence" do
99
+ foreach = FOREACH.new [ seq(C,D,E), seq(var('$'),G,A) ]
100
+ 6.times{ foreach.next }
101
+ foreach.next.should == E
102
+ foreach.rewind
103
+ vals = []
104
+ 9.times{ vals << foreach.next }
105
+ lambda{ foreach.next }.should raise_error StopIteration
106
+ vals.should == [C,G,A,D,G,A,E,G,A]
107
+ end
108
+
109
+ it "returns self, so it can be chained to #next" do
110
+ foreach = FOREACH.new [ seq(C,D,E), seq(var('$'),G,A) ]
111
+ first = foreach.next
112
+ foreach.rewind.next.should == first
113
+ foreach.rewind.next.should == first
114
+ end
115
+ end
116
+
117
+ end
118
+
119
+
120
+ describe MTK::Patterns do
121
+
122
+ def seq(*args)
123
+ ::MTK::Patterns.Sequence(*args)
124
+ end
125
+
126
+ describe "#ForEach" do
127
+ it "creates a Sequence" do
128
+ MTK::Patterns.ForEach(seq(1,2),seq(3,4)).should be_a MTK::Patterns::ForEach
129
+ end
130
+
131
+ it "sets #elements from the varargs" do
132
+ MTK::Patterns.ForEach(seq(1,2),seq(3,4)).elements.should == [seq(1,2),seq(3,4)]
133
+ end
134
+ end
135
+
136
+ end