mtk 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,100 +0,0 @@
1
- require 'spec_helper'
2
- require 'mtk/lang/grammar'
3
-
4
- describe MTK::Lang::Grammar do
5
-
6
- def parse syntax, root
7
- MTK::Lang::Grammar.parse(syntax, root)
8
- end
9
-
10
- describe ".parse" do
11
-
12
- it "should parse pitch sequences" do
13
- parse("C4 D4 E4", :pitch_sequence).should == Pattern.PitchSequence(C4, D4, E4)
14
- end
15
-
16
- it "should parse pitches" do
17
- for pitch_class_name in PitchClass::VALID_NAMES
18
- for octave in -1..9
19
- parse("#{pitch_class_name}#{octave}", :pitch).should == Pitch[PitchClass[pitch_class_name],octave]
20
- end
21
- end
22
- end
23
-
24
- it "should parse pitch classes" do
25
- for pitch_class_name in PitchClass::VALID_NAMES
26
- parse(pitch_class_name, :pitch_class).should == PitchClass[pitch_class_name]
27
- end
28
- end
29
-
30
- it "should parse intervals" do
31
- for interval_name in Intervals::INTERVAL_NAMES
32
- parse(interval_name, :interval).should == Intervals[interval_name]
33
- end
34
- end
35
-
36
- it "should parse intensities" do
37
- for intensity_name in Intensities::INTENSITY_NAMES
38
- parse(intensity_name, :intensity).should == Intensities[intensity_name]
39
- end
40
- end
41
-
42
- it "should parse intensities with + and - modifiers" do
43
- for intensity_name in Intensities::INTENSITY_NAMES
44
- name = "#{intensity_name}+"
45
- parse(name, :intensity).should == Intensities[name]
46
- name = "#{intensity_name}-"
47
- parse(name, :intensity).should == Intensities[name]
48
- end
49
- end
50
-
51
- it "should parse durations" do
52
- for duration in Durations::DURATION_NAMES
53
- parse(duration, :duration).should == Durations[duration]
54
- end
55
- end
56
-
57
- it "should parse durations with . and t modifiers" do
58
- for duration in Durations::DURATION_NAMES
59
- name = "#{duration}."
60
- parse(name, :duration).should == Durations[name]
61
- name = "#{duration}t"
62
- parse(name, :duration).should == Durations[name]
63
- name = "#{duration}..t.t"
64
- parse(name, :duration).should == Durations[name]
65
- end
66
- end
67
-
68
- it "should parse ints as numbers" do
69
- parse("123", :number).should == 123
70
- end
71
-
72
- it "should parse floats as numbers" do
73
- parse("1.23", :number).should == 1.23
74
- end
75
-
76
- it "should parse floats" do
77
- parse("1.23", :float).should == 1.23
78
- end
79
-
80
- it "should parse negative floats" do
81
- parse("-1.23", :float).should == -1.23
82
- end
83
-
84
- it "should parse ints" do
85
- parse("123", :int).should == 123
86
- end
87
-
88
- it "should parse negative ints" do
89
- parse("-123", :int).should == -123
90
- end
91
-
92
- it "should parse negative ints" do
93
- parse("-123", :int).should == -123
94
- end
95
-
96
- it "should give nil as the value for whitespace" do
97
- parse(" \t\n", :space).should == nil
98
- end
99
- end
100
- end
@@ -1,115 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MTK::Note do
4
-
5
- let(:pitch) { C4 }
6
- let(:intensity) { mf }
7
- let(:duration) { 2.5 }
8
- let(:note) { Note.new(pitch, intensity, duration) }
9
-
10
- describe "#pitch" do
11
- it "is the pitch used to create the Note" do
12
- note.pitch.should == pitch
13
- end
14
-
15
- it "is a read-only attribute" do
16
- lambda{ note.pitch = D4 }.should raise_error
17
- end
18
- end
19
-
20
- describe ".from_hash" do
21
- it "constructs a Note using a hash" do
22
- Note.from_hash({ :pitch => C4, :intensity => intensity, :duration => duration }).should == note
23
- end
24
- end
25
-
26
- describe '.from_midi' do
27
- it "constructs a Note using a MIDI pitch and velocity" do
28
- Note.from_midi(C4.to_i, mf*127, 2.5).should == note
29
- end
30
- end
31
-
32
- describe "#to_midi" do
33
- it "converts the Note to an Array of MIDI values: [pitch, velocity, duration]" do
34
- note.to_midi.should == [60, (mf*127).round, duration]
35
- end
36
- end
37
-
38
- describe "#to_hash" do
39
- it "is a hash containing all the attributes of the Note" do
40
- note.to_hash.should == { :pitch => pitch, :intensity => intensity, :duration => duration }
41
- end
42
- end
43
-
44
- describe '#transpose' do
45
- it 'adds the given interval to the @pitch' do
46
- (note.transpose 2.semitones).should == Note.new(D4, intensity, duration)
47
- end
48
- it 'does not affect the immutability of the Note' do
49
- (note.transpose 2.semitones).should_not == note
50
- end
51
- end
52
-
53
- describe "#invert" do
54
- context 'higher center pitch' do
55
- it 'inverts the pitch around the given center pitch' do
56
- note.invert(Pitch 66).should == Note.new(Pitch(72), intensity, duration)
57
- end
58
- end
59
-
60
- context 'lower center pitch' do
61
- it 'inverts the pitch around the given center pitch' do
62
- note.invert(Pitch 54).should == Note.new(Pitch(48), intensity, duration)
63
- end
64
- end
65
-
66
- it "returns the an equal note when given it's pitch as an argument" do
67
- note.invert(note.pitch).should == note
68
- end
69
- end
70
-
71
- describe "#==" do
72
- it "is true when the pitches, intensities, and durations are equal" do
73
- note.should == Note.new(pitch, intensity, duration)
74
- end
75
-
76
- it "is false when the pitches are not equal" do
77
- note.should_not == Note.new(pitch + 1, intensity, duration)
78
- end
79
-
80
- it "is false when the intensities are not equal" do
81
- note.should_not == Note.new(pitch, intensity * 0.5, duration)
82
- end
83
-
84
- it "is false when the durations are not equal" do
85
- note.should_not == Note.new(pitch, intensity, duration * 2)
86
- end
87
- end
88
-
89
- end
90
-
91
- describe MTK do
92
-
93
- describe '#Note' do
94
-
95
- it "acts like new for multiple arguments" do
96
- Note(C4,mf,1).should == Note.new(C4,mf,1)
97
- end
98
-
99
- it "acts like new for an Array of arguments by unpacking (splatting) them" do
100
- Note([C4,mf,1]).should == Note.new(C4,mf,1)
101
- end
102
-
103
- it "returns the argument if it's already a Note" do
104
- note = Note.new(C4,mf,1)
105
- Note(note).should be_equal note
106
- end
107
-
108
- it "raises an error for types it doesn't understand" do
109
- lambda{ Note({:not => :compatible}) }.should raise_error
110
- end
111
-
112
- end
113
-
114
- end
115
-
@@ -1,45 +0,0 @@
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
@@ -1,116 +0,0 @@
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
@@ -1,47 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MTK::Pattern::PitchCycle do
4
-
5
- describe "#next" do
6
- it "enumerates Pitches" do
7
- cycle = Pattern::PitchCycle.new [C4, D4, E4]
8
- cycle.next.should == C4
9
- cycle.next.should == D4
10
- cycle.next.should == E4
11
- end
12
-
13
- it "adds Numeric elements (intervals) to the previous pitch" do
14
- cycle = Pattern::PitchCycle.new [C4, 1, 2, 3]
15
- cycle.next.should == C4
16
- cycle.next.should == C4+1
17
- cycle.next.should == C4+1+2
18
- cycle.next.should == C4+1+2+3
19
- end
20
-
21
- it "returns a Pitch when encountering a Pitch after another type" do
22
- cycle = Pattern::PitchCycle.new [C4, 1, C4]
23
- cycle.next
24
- cycle.next
25
- cycle.next.should == C4
26
- end
27
-
28
- it "goes to the nearest Pitch for any PitchClasses in the pitch list" do
29
- cycle = Pattern::PitchCycle.new [C4, F, C, G, C]
30
- cycle.next.should == C4
31
- cycle.next.should == F4
32
- cycle.next.should == C4
33
- cycle.next.should == G3
34
- cycle.next.should == C4
35
- end
36
-
37
- it "does not endlessly ascend or descend when alternating between two pitch classes a tritone apart" do
38
- cycler = Pattern::PitchCycle.new [C4, Gb, C, Gb, C]
39
- cycler.next.should == C4
40
- cycler.next.should == Gb4
41
- cycler.next.should == C4
42
- cycler.next.should == Gb4
43
- cycler.next.should == C4
44
- end
45
-
46
- end
47
- end
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MTK::Pattern::PitchSequence do
4
-
5
- let(:pitches) { [C4,D4,E4] }
6
- let(:pitch_sequence) { Pattern::PitchSequence.new(pitches) }
7
-
8
-
9
- describe ".from_pitch_classes" do
10
- it "creates a pitch sequence from a list of pitch classes and starting point, selecting the nearest pitch to each pitch class" do
11
- Pattern::PitchSequence.from_pitch_classes([C,G,B,Eb,D,C], D3).should == [C3,G2,B2,Eb3,D3,C3]
12
- end
13
-
14
- it "defaults to a starting point of C4 (middle C)" do
15
- Pattern::PitchSequence.from_pitch_classes([C]).should == [C4]
16
- end
17
-
18
- it "doesn't travel within an octave above or below the starting point by default" do
19
- Pattern::PitchSequence.from_pitch_classes([C,F,Bb,D,A,E,B]).should == [C4,F4,Bb4,D4,A3,E3,B3]
20
- end
21
-
22
- it "allows max distance above or below the starting point to be set via the third argument" do
23
- Pattern::PitchSequence.from_pitch_classes([C,F,Bb,D,A,E,B], C4, 6).should == [C4,F4,Bb3,D4,A3,E4,B3]
24
- end
25
- end
26
-
27
-
28
- end
29
-
30
- describe MTK::Pattern do
31
-
32
- it "converts the arguments to Pitches when possible" do
33
- Pattern.PitchSequence(:C4,:D4,:E4).elements.should == [C4,D4,E4]
34
- end
35
- end
36
-
37
- end