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,118 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Durations do
|
4
|
+
|
5
|
+
describe 'w' do
|
6
|
+
it 'is 4 beats' do
|
7
|
+
w.should == 4
|
8
|
+
end
|
9
|
+
it 'is available via a module property and via mixin' do
|
10
|
+
Durations::w.should == w
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'h' do
|
15
|
+
it 'is 2 beats' do
|
16
|
+
h.should == 2
|
17
|
+
end
|
18
|
+
it 'is available via a module property and via mixin' do
|
19
|
+
Durations::h.should == h
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'q' do
|
24
|
+
it 'is 1 beat' do
|
25
|
+
q.round.should == 1
|
26
|
+
end
|
27
|
+
it 'is available via a module property and via mixin' do
|
28
|
+
Durations::q.should == q
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'e' do
|
33
|
+
it 'is 1/2 of a beat' do
|
34
|
+
e.should == 1.0/2
|
35
|
+
end
|
36
|
+
it 'is available via a module property and via mixin' do
|
37
|
+
Durations::e.should == e
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 's' do
|
42
|
+
it 'is 1/4 of a beat' do
|
43
|
+
s.should == 1.0/4
|
44
|
+
end
|
45
|
+
it 'is available via a module property and via mixin' do
|
46
|
+
Durations::s.should == s
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'r' do
|
51
|
+
it 'is 1/8 of a beat' do
|
52
|
+
r.should == 1.0/8
|
53
|
+
end
|
54
|
+
it 'is available via a module property and via mixin' do
|
55
|
+
Durations::r.should == r
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'x' do
|
60
|
+
it 'is 1/16 of a beat' do
|
61
|
+
x.should == 1.0/16
|
62
|
+
end
|
63
|
+
it 'is available via a module property and via mixin' do
|
64
|
+
Durations::x.should == x
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "DURATIONS" do
|
69
|
+
it "contains all Durations pseudo-constants" do
|
70
|
+
Durations::DURATIONS.should =~ [w, h, q, e, s, r, x]
|
71
|
+
end
|
72
|
+
|
73
|
+
it "is immutable" do
|
74
|
+
lambda{ Durations::DURATIONS << :something }.should raise_error
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "DURATION_NAMES" do
|
79
|
+
it "contains all Durations pseudo-constants names as strings" do
|
80
|
+
Durations::DURATION_NAMES.should =~ ['w', 'h', 'q', 'e', 's', 'r', 'x']
|
81
|
+
end
|
82
|
+
|
83
|
+
it "is immutable" do
|
84
|
+
lambda{ Durations::DURATION_NAMES << :something }.should raise_error
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe ".[]" do
|
89
|
+
it "looks up the constant by name" do
|
90
|
+
for duration in Durations::DURATION_NAMES
|
91
|
+
Durations[duration].should == Durations.send(duration)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it "supports a '.' suffix, which multiples the value by 1.5" do
|
96
|
+
for duration in Durations::DURATION_NAMES
|
97
|
+
Durations["#{duration}."].should == Durations.send(duration) * 1.5
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "supports a 't' suffix, which multiples the value by 2/3" do
|
102
|
+
for duration in Durations::DURATION_NAMES
|
103
|
+
Durations["#{duration}t"].should == Durations.send(duration) * 2/3.0
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it "supports '.' and 't' suffixes in any combination" do
|
108
|
+
for duration in Durations::DURATION_NAMES
|
109
|
+
Durations["#{duration}.t"].should == Durations.send(duration) * 1.5 * 2/3.0
|
110
|
+
Durations["#{duration}t."].should == Durations.send(duration) * 1.5 * 2/3.0
|
111
|
+
Durations["#{duration}.."].should == Durations.send(duration) * 1.5 * 1.5
|
112
|
+
Durations["#{duration}..t.t."].should == Durations.send(duration) * 1.5**4 * (2/3.0)**2
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MTK::
|
3
|
+
describe MTK::Intensities do
|
4
4
|
|
5
5
|
describe 'ppp' do
|
6
6
|
it 'is equivalent to MIDI velocity 16' do
|
7
7
|
(ppp * 127).round.should == 16
|
8
8
|
end
|
9
9
|
it 'is available via a module property and via mixin' do
|
10
|
-
|
10
|
+
Intensities::ppp.should == ppp
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -16,7 +16,7 @@ describe MTK::Dynamics do
|
|
16
16
|
(pp * 127).round.should == 32
|
17
17
|
end
|
18
18
|
it 'is available via a module property and via mixin' do
|
19
|
-
|
19
|
+
Intensities::pp.should == pp
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -25,7 +25,7 @@ describe MTK::Dynamics do
|
|
25
25
|
(p * 127).round.should == 48
|
26
26
|
end
|
27
27
|
it 'is available via a module property and via mixin' do
|
28
|
-
|
28
|
+
Intensities::p.should == p
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -34,7 +34,7 @@ describe MTK::Dynamics do
|
|
34
34
|
(mp * 127).round.should == 64
|
35
35
|
end
|
36
36
|
it 'is available via a module property and via mixin' do
|
37
|
-
|
37
|
+
Intensities::mp.should == mp
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -43,7 +43,7 @@ describe MTK::Dynamics do
|
|
43
43
|
(mf * 127).round.should == 79
|
44
44
|
end
|
45
45
|
it 'is available via a module property and via mixin' do
|
46
|
-
|
46
|
+
Intensities::mf.should == mf
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -52,7 +52,7 @@ describe MTK::Dynamics do
|
|
52
52
|
(f * 127).round.should == 95
|
53
53
|
end
|
54
54
|
it 'is available via a module property and via mixin' do
|
55
|
-
|
55
|
+
Intensities::f.should == f
|
56
56
|
end
|
57
57
|
it "does not overwrite the PitchClass constant 'F'" do
|
58
58
|
F.should be_a PitchClass
|
@@ -64,7 +64,7 @@ describe MTK::Dynamics do
|
|
64
64
|
(ff * 127).round.should == 111
|
65
65
|
end
|
66
66
|
it 'is available via a module property and via mixin' do
|
67
|
-
|
67
|
+
Intensities::ff.should == ff
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -73,20 +73,51 @@ describe MTK::Dynamics do
|
|
73
73
|
(fff * 127).round.should == 127
|
74
74
|
end
|
75
75
|
it 'is available via a module property and via mixin' do
|
76
|
-
|
76
|
+
Intensities::fff.should == fff
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "INTENSITIES" do
|
81
|
+
it "contains all Intensities pseudo-constants" do
|
82
|
+
Intensities::INTENSITIES.should =~ [ppp, pp, p, mp, mf, f, ff, fff]
|
83
|
+
end
|
84
|
+
|
85
|
+
it "is immutable" do
|
86
|
+
lambda{ Intensities::INTENSITIES << :something }.should raise_error
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "INTENSITY_NAMES" do
|
91
|
+
it "contains all Intensities pseudo-constants names as strings" do
|
92
|
+
Intensities::INTENSITY_NAMES.should =~ ['ppp', 'pp', 'p', 'mp', 'mf', 'f', 'ff', 'fff']
|
93
|
+
end
|
94
|
+
|
95
|
+
it "is immutable" do
|
96
|
+
lambda{ Intensities::INTENSITY_NAMES << :something }.should raise_error
|
77
97
|
end
|
78
98
|
end
|
79
99
|
|
80
100
|
describe ".[]" do
|
81
101
|
it "looks up the constant by name" do
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
102
|
+
for name in INTENSITY_NAMES
|
103
|
+
Intensities[name].should == Intensities.send(name)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it "adds 1.0/24 when the name ends with '+', except for 'fff+' which is 1.0 like 'fff'" do
|
108
|
+
for name in INTENSITY_NAMES
|
109
|
+
if name == 'fff'
|
110
|
+
Intensities["#{name}+"].should == 1.0
|
111
|
+
else
|
112
|
+
Intensities["#{name}+"].should == Intensities.send(name)+1.0/24
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
it "subtracts 1.0/24 when the name ends with '-'" do
|
118
|
+
for name in INTENSITY_NAMES
|
119
|
+
Intensities["#{name}-"].should == Intensities.send(name)-1.0/24
|
120
|
+
end
|
90
121
|
end
|
91
122
|
end
|
92
123
|
|
@@ -119,6 +119,27 @@ describe MTK::Intervals do
|
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
+
|
123
|
+
describe "INTERVALS" do
|
124
|
+
it "contains all intervals constants/pseudo-constants" do
|
125
|
+
Intervals::INTERVALS.should =~ [P1, m2, M2, m3, M3, P4, TT, P5, m6, M6, m7, M7, P8]
|
126
|
+
end
|
127
|
+
|
128
|
+
it "is immutable" do
|
129
|
+
lambda{ Intervals::INTERVALS << :something }.should raise_error
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "INTERVAL_NAMES" do
|
134
|
+
it "contains all intervals constants/pseudo-constant names" do
|
135
|
+
Intervals::INTERVAL_NAMES.should =~ ['P1', 'm2', 'M2', 'm3', 'M3', 'P4', 'TT', 'P5', 'm6', 'M6', 'm7', 'M7', 'P8']
|
136
|
+
end
|
137
|
+
|
138
|
+
it "is immutable" do
|
139
|
+
lambda{ Intervals::INTERVAL_NAMES << :something }.should raise_error
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
122
143
|
describe ".[]" do
|
123
144
|
it "looks up the constant by name" do
|
124
145
|
Intervals['P1'].should == P1
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::PitchClasses do
|
4
|
+
let(:cases) {
|
5
|
+
[
|
6
|
+
[PitchClass['C'], 'C', 0],
|
7
|
+
[PitchClass['Db'], 'Db', 1],
|
8
|
+
[PitchClass['D'], 'D', 2],
|
9
|
+
[PitchClass['Eb'], 'Eb', 3],
|
10
|
+
[PitchClass['E'], 'E', 4],
|
11
|
+
[PitchClass['F'], 'F', 5],
|
12
|
+
[PitchClass['Gb'], 'Gb', 6],
|
13
|
+
[PitchClass['G'], 'G', 7],
|
14
|
+
[PitchClass['Ab'], 'Ab', 8],
|
15
|
+
[PitchClass['A'], 'A', 9],
|
16
|
+
[PitchClass['Bb'], 'Bb', 10],
|
17
|
+
[PitchClass['B'], 'B', 11],
|
18
|
+
]
|
19
|
+
}
|
20
|
+
|
21
|
+
it "defines constants for the 12 pitch classes in the twelve-tone octave" do
|
22
|
+
cases.length.should == 12
|
23
|
+
cases.each do |const, name, int_value|
|
24
|
+
const.name.should == name
|
25
|
+
const.to_i.should == int_value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "PITCH_CLASSES" do
|
30
|
+
it "contains the 12 pitch class constants" do
|
31
|
+
PitchClasses::PITCH_CLASSES.length.should == 12
|
32
|
+
PitchClasses::PITCH_CLASSES.should == cases.map{ |const,_,__| const }
|
33
|
+
end
|
34
|
+
|
35
|
+
it "is immutable" do
|
36
|
+
lambda{ PitchClasses::PITCH_CLASSES << :something }.should raise_error
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "PITCH_CLASS_NAMES" do
|
41
|
+
it "contains the names of the 12 pitch class constants" do
|
42
|
+
PitchClasses::PITCH_CLASS_NAMES.length.should == 12
|
43
|
+
PitchClasses::PITCH_CLASS_NAMES.should == cases.map{ |_,name,__| name }
|
44
|
+
end
|
45
|
+
|
46
|
+
it "is immutable" do
|
47
|
+
lambda{ PitchClasses::PITCH_CLASS_NAMES << :something }.should raise_error
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe ".[]" do
|
52
|
+
it "acts like PitchClas.[]" do
|
53
|
+
for name in PitchClasses::PITCH_CLASS_NAMES
|
54
|
+
PitchClasses[name].should == PitchClass[name]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Pitches do
|
4
|
+
|
5
|
+
it "defines constants for the 128 notes in MIDI" do
|
6
|
+
Pitches.constants.length.should == 130 # there's also the PITCHES and PITCH_NAMES constants
|
7
|
+
Pitches::C_1.should == Pitch.from_s('C-1')
|
8
|
+
Pitches::D0.should == Pitch.from_s('D0')
|
9
|
+
Pitches::Eb1.should == Pitch.from_s('Eb1')
|
10
|
+
Pitches::G9.should == Pitch.from_s('g9')
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "PITCHES" do
|
14
|
+
it "contains all 128 pitch constants" do
|
15
|
+
Pitches::PITCHES.length.should == 128
|
16
|
+
Pitches::PITCHES.should include Pitches::C_1
|
17
|
+
Pitches::PITCHES.should include Pitches::D0
|
18
|
+
Pitches::PITCHES.should include Pitches::Eb1
|
19
|
+
Pitches::PITCHES.should include Pitches::G9
|
20
|
+
end
|
21
|
+
|
22
|
+
it "is immutable" do
|
23
|
+
lambda{ Pitches::PITCHES << :something }.should raise_error
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "PITCH_NAMES" do
|
28
|
+
it "contains all 128 pitch constants" do
|
29
|
+
Pitches::PITCH_NAMES.length.should == 128
|
30
|
+
Pitches::PITCH_NAMES.should include 'C_1'
|
31
|
+
Pitches::PITCH_NAMES.should include 'D0'
|
32
|
+
Pitches::PITCH_NAMES.should include 'Eb1'
|
33
|
+
Pitches::PITCH_NAMES.should include 'G9'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "is immutable" do
|
37
|
+
lambda{ Pitches::PITCH_NAMES << :something }.should raise_error
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe ".[]" do
|
42
|
+
it "acts like Pitch.from_s for the names in PITCH_NAMES, and also treats '_' like '-'" do
|
43
|
+
for name in Pitches::PITCH_NAMES
|
44
|
+
Pitches[name].should == Pitch.from_s(name.sub('_','-')) # the constant names need to use underscores, but Pitch.from_s doesn't understand that
|
45
|
+
if name =~ /_/
|
46
|
+
Pitches[name.sub('_','-')].should == Pitch.from_s(name.sub('_','-')) # make sure '-' works too
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
File without changes
|
data/spec/mtk/event_spec.rb
CHANGED
@@ -24,6 +24,20 @@ describe MTK::Event do
|
|
24
24
|
it "is a read-only attribute" do
|
25
25
|
lambda{ event.duration = 0 }.should raise_error
|
26
26
|
end
|
27
|
+
|
28
|
+
it "is always positive (absolute value of the duration used to construct the Event)" do
|
29
|
+
Event.new(intensity, -duration).duration.should == duration
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#rest?" do
|
34
|
+
it "is true when the duration used to create the Event was negative" do
|
35
|
+
Event.new(intensity, -duration).rest?.should be_true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "is false when the duration used to create the Event was positive" do
|
39
|
+
event.rest?.should be_false
|
40
|
+
end
|
27
41
|
end
|
28
42
|
|
29
43
|
describe "from_hash" do
|
@@ -88,9 +102,14 @@ describe MTK::Event do
|
|
88
102
|
it "converts beats to pulses, given pulses_per_beat" do
|
89
103
|
Event.new(0,1).duration_in_pulses(60).should == 60
|
90
104
|
end
|
105
|
+
|
91
106
|
it "rounds to the nearest pulse" do
|
92
107
|
Event.new(0,1.5).duration_in_pulses(59).should == 89
|
93
108
|
end
|
109
|
+
|
110
|
+
it "is always positive (uses absolute value of the duration used to construct the Event)" do
|
111
|
+
Event.new(intensity, -1).duration_in_pulses(60).should == 60
|
112
|
+
end
|
94
113
|
end
|
95
114
|
|
96
115
|
describe "#==" do
|