mtk 0.0.3.2 → 0.0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +2 -2
- data/DEVELOPMENT_NOTES.md +20 -0
- data/README.md +9 -3
- data/Rakefile +47 -13
- data/bin/mtk +55 -20
- data/examples/crescendo.rb +4 -4
- data/examples/{drum_pattern1.rb → drum_pattern.rb} +8 -8
- data/examples/dynamic_pattern.rb +5 -5
- data/examples/gets_and_play.rb +3 -2
- data/examples/notation.rb +3 -3
- data/examples/play_midi.rb +4 -4
- data/examples/print_midi.rb +2 -2
- data/examples/random_tone_row.rb +3 -3
- data/examples/syntax_to_midi.rb +2 -2
- data/examples/test_output.rb +4 -5
- data/examples/tone_row_melody.rb +7 -5
- data/lib/mtk/core/duration.rb +213 -0
- data/lib/mtk/core/intensity.rb +158 -0
- data/lib/mtk/core/interval.rb +157 -0
- data/lib/mtk/core/pitch.rb +154 -0
- data/lib/mtk/core/pitch_class.rb +194 -0
- data/lib/mtk/events/event.rb +4 -4
- data/lib/mtk/events/note.rb +12 -12
- data/lib/mtk/events/timeline.rb +232 -0
- data/lib/mtk/groups/chord.rb +56 -0
- data/lib/mtk/{helpers → groups}/collection.rb +33 -1
- data/lib/mtk/groups/melody.rb +96 -0
- data/lib/mtk/groups/pitch_class_set.rb +163 -0
- data/lib/mtk/{helpers → groups}/pitch_collection.rb +1 -1
- data/lib/mtk/{midi → io}/dls_synth_device.rb +3 -1
- data/lib/mtk/{midi → io}/dls_synth_output.rb +10 -10
- data/lib/mtk/{midi → io}/jsound_input.rb +2 -2
- data/lib/mtk/{midi → io}/jsound_output.rb +9 -9
- data/lib/mtk/{midi/file.rb → io/midi_file.rb} +13 -13
- data/lib/mtk/{midi/input.rb → io/midi_input.rb} +4 -4
- data/lib/mtk/{midi/output.rb → io/midi_output.rb} +8 -8
- data/lib/mtk/{helpers/lilypond.rb → io/notation.rb} +5 -5
- data/lib/mtk/{midi → io}/unimidi_input.rb +2 -2
- data/lib/mtk/{midi → io}/unimidi_output.rb +14 -9
- data/lib/mtk/{constants → lang}/durations.rb +11 -11
- data/lib/mtk/{constants → lang}/intensities.rb +11 -11
- data/lib/mtk/{constants → lang}/intervals.rb +17 -17
- data/lib/mtk/lang/mtk_grammar.citrus +9 -9
- data/lib/mtk/{constants → lang}/pitch_classes.rb +5 -5
- data/lib/mtk/{constants → lang}/pitches.rb +7 -7
- data/lib/mtk/{helpers → lang}/pseudo_constants.rb +1 -1
- data/lib/mtk/{variable.rb → lang/variable.rb} +1 -1
- data/lib/mtk/numeric_extensions.rb +40 -47
- data/lib/mtk/patterns/for_each.rb +1 -1
- data/lib/mtk/patterns/pattern.rb +3 -3
- data/lib/mtk/sequencers/event_builder.rb +16 -15
- data/lib/mtk/sequencers/legato_sequencer.rb +1 -1
- data/lib/mtk/sequencers/rhythmic_sequencer.rb +1 -1
- data/lib/mtk/sequencers/sequencer.rb +8 -8
- data/lib/mtk/sequencers/step_sequencer.rb +2 -2
- data/lib/mtk.rb +33 -39
- data/spec/mtk/{duration_spec.rb → core/duration_spec.rb} +3 -3
- data/spec/mtk/{intensity_spec.rb → core/intensity_spec.rb} +3 -3
- data/spec/mtk/{interval_spec.rb → core/interval_spec.rb} +1 -1
- data/spec/mtk/{pitch_class_spec.rb → core/pitch_class_spec.rb} +1 -1
- data/spec/mtk/{pitch_spec.rb → core/pitch_spec.rb} +8 -8
- data/spec/mtk/events/event_spec.rb +4 -4
- data/spec/mtk/events/note_spec.rb +8 -8
- data/spec/mtk/{timeline_spec.rb → events/timeline_spec.rb} +47 -47
- data/spec/mtk/{chord_spec.rb → groups/chord_spec.rb} +18 -16
- data/spec/mtk/{helpers → groups}/collection_spec.rb +3 -3
- data/spec/mtk/{melody_spec.rb → groups/melody_spec.rb} +36 -34
- data/spec/mtk/{pitch_class_set_spec.rb → groups/pitch_class_set_spec.rb} +57 -55
- data/spec/mtk/{midi/file_spec.rb → io/midi_file_spec.rb} +17 -17
- data/spec/mtk/{midi/output_spec.rb → io/midi_output_spec.rb} +6 -6
- data/spec/mtk/{constants → lang}/durations_spec.rb +1 -1
- data/spec/mtk/{constants → lang}/intensities_spec.rb +1 -1
- data/spec/mtk/{constants → lang}/intervals_spec.rb +1 -1
- data/spec/mtk/lang/parser_spec.rb +12 -6
- data/spec/mtk/{constants → lang}/pitch_classes_spec.rb +1 -1
- data/spec/mtk/{constants → lang}/pitches_spec.rb +1 -1
- data/spec/mtk/{helpers → lang}/pseudo_constants_spec.rb +2 -2
- data/spec/mtk/{variable_spec.rb → lang/variable_spec.rb} +4 -4
- data/spec/mtk/numeric_extensions_spec.rb +35 -55
- data/spec/mtk/patterns/for_each_spec.rb +1 -1
- data/spec/mtk/patterns/sequence_spec.rb +1 -1
- data/spec/mtk/sequencers/legato_sequencer_spec.rb +2 -2
- data/spec/mtk/sequencers/rhythmic_sequencer_spec.rb +4 -4
- data/spec/mtk/sequencers/step_sequencer_spec.rb +5 -5
- data/spec/spec_helper.rb +7 -6
- metadata +75 -61
- data/ext/mkrf_conf.rb +0 -25
- data/lib/mtk/chord.rb +0 -55
- data/lib/mtk/duration.rb +0 -211
- data/lib/mtk/helpers/convert.rb +0 -36
- data/lib/mtk/helpers/output_selector.rb +0 -67
- data/lib/mtk/intensity.rb +0 -156
- data/lib/mtk/interval.rb +0 -155
- data/lib/mtk/melody.rb +0 -94
- data/lib/mtk/pitch.rb +0 -152
- data/lib/mtk/pitch_class.rb +0 -192
- data/lib/mtk/pitch_class_set.rb +0 -161
- data/lib/mtk/timeline.rb +0 -230
- data/spec/mtk/midi/jsound_input_spec.rb +0 -11
- data/spec/mtk/midi/jsound_output_spec.rb +0 -11
- data/spec/mtk/midi/unimidi_input_spec.rb +0 -11
- data/spec/mtk/midi/unimidi_output_spec.rb +0 -11
@@ -1,24 +1,24 @@
|
|
1
1
|
module MTK
|
2
2
|
module Sequencers
|
3
3
|
|
4
|
-
# A Sequencer produces {Timeline}s from a collection of {Patterns::Pattern}s.
|
4
|
+
# A Sequencer produces {Events::Timeline}s from a collection of {Patterns::Pattern}s.
|
5
5
|
#
|
6
6
|
# @abstract Subclass and override {#advance} to implement a Sequencer.
|
7
7
|
#
|
8
8
|
class Sequencer
|
9
9
|
|
10
|
-
# The maximum number of [time,event_list] entries that will be generated for the {Timeline}.
|
10
|
+
# The maximum number of [time,event_list] entries that will be generated for the {Events::Timeline}.
|
11
11
|
# nil means no maximum (be careful of infinite loops!)
|
12
12
|
attr_accessor :max_steps
|
13
13
|
|
14
|
-
# The maximum time (key) that will be generated for the {Timeline}.
|
14
|
+
# The maximum time (key) that will be generated for the {Events::Timeline}.
|
15
15
|
# nil means no maximum (be careful of infinite loops!)
|
16
16
|
attr_accessor :max_time
|
17
17
|
|
18
18
|
# Used by {#to_timeline} to builds event lists from the results of {Patterns::Pattern#next} for the {Patterns::Pattern}s in this Sequencer.
|
19
19
|
attr_reader :event_builder
|
20
20
|
|
21
|
-
# The current time offset for the sequencer. Used for the {Timeline} times.
|
21
|
+
# The current time offset for the sequencer. Used for the {Events::Timeline} times.
|
22
22
|
attr_reader :time
|
23
23
|
|
24
24
|
# The current sequencer step index (the number of times-1 that {#next} has been called), or -1 if the sequencer has not yet started.
|
@@ -26,7 +26,7 @@ module MTK
|
|
26
26
|
|
27
27
|
attr_reader :patterns
|
28
28
|
|
29
|
-
# @param patterns [Array] the list of patterns to be sequenced into a {Timeline}
|
29
|
+
# @param patterns [Array] the list of patterns to be sequenced into a {Events::Timeline}
|
30
30
|
# @param options [Hash] the options to create a message with.
|
31
31
|
# @option options [String] :max_steps set {#max_steps}
|
32
32
|
# @option options [String] :max_time set {#max_time}
|
@@ -45,10 +45,10 @@ module MTK
|
|
45
45
|
end
|
46
46
|
|
47
47
|
|
48
|
-
# Produce a {Timeline} from the {Patterns::Pattern}s in this Sequencer.
|
48
|
+
# Produce a {Events::Timeline} from the {Patterns::Pattern}s in this Sequencer.
|
49
49
|
def to_timeline
|
50
50
|
rewind
|
51
|
-
timeline =
|
51
|
+
timeline = MTK::Events::Timeline.new
|
52
52
|
loop do
|
53
53
|
events = self.next
|
54
54
|
if events
|
@@ -89,7 +89,7 @@ module MTK
|
|
89
89
|
########################
|
90
90
|
protected
|
91
91
|
|
92
|
-
# Advance @time to the next time for the {Timeline} being produced by {#to_timeline}
|
92
|
+
# Advance @time to the next time for the {Events::Timeline} being produced by {#to_timeline}
|
93
93
|
def advance
|
94
94
|
@time += 1 # default behavior simply advances one beat at a time
|
95
95
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module MTK
|
2
2
|
module Sequencers
|
3
3
|
|
4
|
-
# A Sequencer which has a constant {#step_size} time between {Timeline} entries.
|
4
|
+
# A Sequencer which has a constant {#step_size} time between {Events::Timeline} entries.
|
5
5
|
class StepSequencer < Sequencer
|
6
6
|
|
7
|
-
# The time between entries in the {Timeline}.
|
7
|
+
# The time between entries in the {Events::Timeline}.
|
8
8
|
attr_accessor :step_size
|
9
9
|
|
10
10
|
def initialize(patterns, options={})
|
data/lib/mtk.rb
CHANGED
@@ -3,65 +3,61 @@
|
|
3
3
|
# The top level module for this library
|
4
4
|
module MTK
|
5
5
|
|
6
|
-
#
|
7
|
-
module
|
6
|
+
# Core data types
|
7
|
+
module Core
|
8
8
|
end
|
9
9
|
|
10
|
-
#
|
11
|
-
module Helpers
|
12
|
-
end
|
13
|
-
|
14
|
-
# Musical events, such as {Events::Note}s and {Events::Parameter} changes, that are arranged in time via a {Timeline}.
|
10
|
+
# Musical events, such as {MTK::Events::Note}s and {MTK::Events::Parameter} changes, that are arranged in time via a {MTK::Events::Timeline}.
|
15
11
|
module Events
|
16
12
|
end
|
17
13
|
|
18
|
-
#
|
19
|
-
module
|
14
|
+
# Collections of {MTK::Core} objects
|
15
|
+
module Groups
|
20
16
|
end
|
21
17
|
|
22
|
-
#
|
23
|
-
module
|
18
|
+
# Optional classes for MIDI {MTK::IO::File} and realtime MIDI {MTK::IO::Input} and {MTK::IO::Output}.
|
19
|
+
module IO
|
24
20
|
end
|
25
21
|
|
26
22
|
# Optional classes for the "MTK language", which let's you compose music via MTK without writing any Ruby code
|
27
23
|
module Lang
|
28
24
|
end
|
29
25
|
|
30
|
-
#
|
31
|
-
module
|
26
|
+
# Classes that emit elements one at a time. Used by {MTK::Sequencers::Sequencer}s to construct {MTK::Events::Timeline}s.
|
27
|
+
module Patterns
|
32
28
|
end
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
require 'mtk/pitch'
|
38
|
-
require 'mtk/duration'
|
39
|
-
require 'mtk/intensity'
|
40
|
-
|
41
|
-
require 'mtk/interval'
|
30
|
+
# Classes that assemble {MTK::Patterns::Pattern}s into {MTK::Events::Timeline}s.
|
31
|
+
module Sequencers
|
32
|
+
end
|
42
33
|
|
43
|
-
|
34
|
+
end
|
44
35
|
|
45
|
-
require 'mtk/
|
46
|
-
require 'mtk/
|
47
|
-
require 'mtk/
|
48
|
-
require 'mtk/
|
36
|
+
require 'mtk/core/pitch_class'
|
37
|
+
require 'mtk/core/pitch'
|
38
|
+
require 'mtk/core/duration'
|
39
|
+
require 'mtk/core/intensity'
|
40
|
+
require 'mtk/core/interval'
|
41
|
+
|
42
|
+
require 'mtk/lang/pseudo_constants'
|
43
|
+
require 'mtk/lang/pitch_classes'
|
44
|
+
require 'mtk/lang/pitches'
|
45
|
+
require 'mtk/lang/intervals'
|
46
|
+
require 'mtk/lang/intensities'
|
47
|
+
require 'mtk/lang/durations'
|
48
|
+
require 'mtk/lang/variable'
|
49
|
+
require 'mtk/lang/parser'
|
49
50
|
|
50
|
-
require 'mtk/
|
51
|
-
require 'mtk/
|
52
|
-
require 'mtk/
|
51
|
+
require 'mtk/groups/collection'
|
52
|
+
require 'mtk/groups/pitch_collection'
|
53
|
+
require 'mtk/groups/pitch_class_set'
|
54
|
+
require 'mtk/groups/melody'
|
55
|
+
require 'mtk/groups/chord'
|
53
56
|
|
54
57
|
require 'mtk/events/event'
|
55
58
|
require 'mtk/events/note'
|
56
59
|
require 'mtk/events/parameter'
|
57
|
-
|
58
|
-
require 'mtk/timeline'
|
59
|
-
|
60
|
-
require 'mtk/constants/pitch_classes'
|
61
|
-
require 'mtk/constants/pitches'
|
62
|
-
require 'mtk/constants/intervals'
|
63
|
-
require 'mtk/constants/intensities'
|
64
|
-
require 'mtk/constants/durations'
|
60
|
+
require 'mtk/events/timeline'
|
65
61
|
|
66
62
|
require 'mtk/patterns/pattern'
|
67
63
|
require 'mtk/patterns/sequence'
|
@@ -78,5 +74,3 @@ require 'mtk/sequencers/sequencer'
|
|
78
74
|
require 'mtk/sequencers/step_sequencer'
|
79
75
|
require 'mtk/sequencers/rhythmic_sequencer'
|
80
76
|
require 'mtk/sequencers/legato_sequencer'
|
81
|
-
|
82
|
-
require 'mtk/lang/parser'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MTK::Duration do
|
3
|
+
describe MTK::Core::Duration do
|
4
4
|
|
5
5
|
let(:one_beat) { Duration[1] }
|
6
6
|
let(:two_beats) { Duration[2] }
|
@@ -230,10 +230,10 @@ describe MTK::Duration do
|
|
230
230
|
end
|
231
231
|
|
232
232
|
describe '#inspect' do
|
233
|
-
it 'is "#<MTK::Duration:{object_id} @value={value}>"' do
|
233
|
+
it 'is "#<MTK::Core::Duration:{object_id} @value={value}>"' do
|
234
234
|
for value in [0, 60, 60.5, 127]
|
235
235
|
duration = Duration.new(value)
|
236
|
-
duration.inspect.should == "#<MTK::Duration:#{duration.object_id} @value=#{value}>"
|
236
|
+
duration.inspect.should == "#<MTK::Core::Duration:#{duration.object_id} @value=#{value}>"
|
237
237
|
end
|
238
238
|
end
|
239
239
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MTK::Intensity do
|
3
|
+
describe MTK::Core::Intensity do
|
4
4
|
|
5
5
|
let(:half_intensity) { Intensity[0.5] }
|
6
6
|
|
@@ -147,10 +147,10 @@ describe MTK::Intensity do
|
|
147
147
|
end
|
148
148
|
|
149
149
|
describe '#inspect' do
|
150
|
-
it 'is "#<MTK::Intensity:{object_id} @value={value}>"' do
|
150
|
+
it 'is "#<MTK::Core::Intensity:{object_id} @value={value}>"' do
|
151
151
|
for value in [0, 60, 60.5, 127]
|
152
152
|
intensity = Intensity.new(value)
|
153
|
-
intensity.inspect.should == "#<MTK::Intensity:#{intensity.object_id} @value=#{value}>"
|
153
|
+
intensity.inspect.should == "#<MTK::Core::Intensity:#{intensity.object_id} @value=#{value}>"
|
154
154
|
end
|
155
155
|
end
|
156
156
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MTK::Pitch do
|
3
|
+
describe MTK::Core::Pitch do
|
4
4
|
|
5
5
|
let(:middle_c) { Pitch.new(C, 4) }
|
6
6
|
let(:lowest) { Pitch.new(C, -1) }
|
@@ -16,7 +16,7 @@ describe MTK::Pitch do
|
|
16
16
|
Pitch.new(C,4).should_not be_equal Pitch[C,4]
|
17
17
|
end
|
18
18
|
|
19
|
-
it "can handle any type for the first argument that's supported by MTK::PitchClass()" do
|
19
|
+
it "can handle any type for the first argument that's supported by MTK::Core::PitchClass()" do
|
20
20
|
Pitch['C',4].should == Pitch[0, 4]
|
21
21
|
end
|
22
22
|
end
|
@@ -83,9 +83,9 @@ describe MTK::Pitch do
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
describe ".
|
86
|
+
describe ".from_h" do
|
87
87
|
it "constructs a Pitch from a hash of pitch attributes" do
|
88
|
-
Pitch.
|
88
|
+
Pitch.from_h({:pitch_class => C, :octave => 4, :offset => 0.5}).should == middle_c_and_50_cents
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
@@ -105,9 +105,9 @@ describe MTK::Pitch do
|
|
105
105
|
end
|
106
106
|
end
|
107
107
|
|
108
|
-
describe "#
|
108
|
+
describe "#to_h" do
|
109
109
|
it "converts to a Hash" do
|
110
|
-
middle_c_and_50_cents.
|
110
|
+
middle_c_and_50_cents.to_h.should == {:pitch_class => C, :octave => 4, :offset => 0.5}
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
@@ -142,10 +142,10 @@ describe MTK::Pitch do
|
|
142
142
|
end
|
143
143
|
|
144
144
|
describe '#inspect' do
|
145
|
-
it 'is "#<MTK::Pitch:{object_id} @value={value}>"' do
|
145
|
+
it 'is "#<MTK::Core::Pitch:{object_id} @value={value}>"' do
|
146
146
|
for value in [0, 60, 60.5, 127]
|
147
147
|
pitch = Pitch.from_f(value)
|
148
|
-
pitch.inspect.should == "#<MTK::Pitch:#{pitch.object_id} @value=#{value}>"
|
148
|
+
pitch.inspect.should == "#<MTK::Core::Pitch:#{pitch.object_id} @value=#{value}>"
|
149
149
|
end
|
150
150
|
end
|
151
151
|
end
|
@@ -166,15 +166,15 @@ describe MTK::Events::Event do
|
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
169
|
-
describe "
|
169
|
+
describe "from_h" do
|
170
170
|
it "constructs an Event using a hash" do
|
171
|
-
EVENT.
|
171
|
+
EVENT.from_h(hash).should == event
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
175
|
-
describe "#
|
175
|
+
describe "#to_h" do
|
176
176
|
it "is a hash containing all the attributes of the Event" do
|
177
|
-
event.
|
177
|
+
event.to_h.should == hash
|
178
178
|
end
|
179
179
|
end
|
180
180
|
|
@@ -52,9 +52,9 @@ describe MTK::Events::Note do
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
describe ".
|
55
|
+
describe ".from_h" do
|
56
56
|
it "constructs a Note using a hash" do
|
57
|
-
NOTE.
|
57
|
+
NOTE.from_h({ :pitch => pitch, :intensity => intensity, :duration => duration }).should == note
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
@@ -64,9 +64,9 @@ describe MTK::Events::Note do
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
describe "#
|
67
|
+
describe "#to_h" do
|
68
68
|
it "is a hash containing all the attributes of the Note" do
|
69
|
-
hash = note.
|
69
|
+
hash = note.to_h
|
70
70
|
# hash includes some extra "baggage" for compatibility with AbstractEvent,
|
71
71
|
# so we'll just check the fields we care about:
|
72
72
|
hash[:pitch].should == pitch
|
@@ -125,8 +125,8 @@ describe MTK::Events::Note do
|
|
125
125
|
|
126
126
|
describe "#inspect" do
|
127
127
|
it 'is "#<MTK::Events::Note:{object_id} @pitch={pitch.inspect}, @duration={duration.inspect}, @intensity={intensity.inspect}>"' do
|
128
|
-
duration = MTK
|
129
|
-
intensity = MTK
|
128
|
+
duration = MTK.Duration(1/8.0)
|
129
|
+
intensity = MTK.Intensity(1/8.0)
|
130
130
|
note = NOTE.new(C4, duration, intensity)
|
131
131
|
note.inspect.should == "#<MTK::Events::Note:#{note.object_id} @pitch=#{C4.inspect}, @duration=#{duration.inspect}, @intensity=#{intensity.inspect}>"
|
132
132
|
end
|
@@ -161,11 +161,11 @@ describe MTK do
|
|
161
161
|
end
|
162
162
|
|
163
163
|
it "fills in a missing duration type from an number" do
|
164
|
-
Note(C4,mf,5.25).should == NOTE.new(C4,MTK
|
164
|
+
Note(C4,mf,5.25).should == NOTE.new(C4,MTK.Duration(5.25),mf)
|
165
165
|
end
|
166
166
|
|
167
167
|
it '' do
|
168
|
-
Note(MTK::
|
168
|
+
Note(MTK::Lang::Pitches::C4, MTK::Lang::Intensities::o, 5.25).should == Note(C4, 5.25, 0.75)
|
169
169
|
end
|
170
170
|
|
171
171
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MTK::Timeline do
|
3
|
+
describe MTK::Events::Timeline do
|
4
4
|
|
5
5
|
let(:note1) { Note(C4, p, 1) }
|
6
6
|
let(:note2) { Note(G4, o, 2) }
|
7
7
|
let(:timeline_raw_data) { { 0.0 => note1, 1.0 => [note1, note2] } }
|
8
8
|
let(:timeline_hash) { { 0.0 => [note1], 1.0 => [note1, note2] } }
|
9
|
-
let(:timeline) { Timeline.
|
9
|
+
let(:timeline) { MTK::Events::Timeline.from_h(timeline_raw_data) }
|
10
10
|
|
11
11
|
let(:unquantized_data) { { 0.0 => [note1], 0.7 => [note1], 1.1 => [note2], 1.24 => [note1], 1.25 => [note1] } }
|
12
|
-
let(:unquantized_timeline) { Timeline.
|
12
|
+
let(:unquantized_timeline) { MTK::Events::Timeline.from_h(unquantized_data) }
|
13
13
|
let(:quantization_interval) { 0.5 }
|
14
14
|
let(:quantized_data) { { 0.0 => [note1], 0.5 => [note1], 1.0 => [note2, note1], 1.5 => [note1] } }
|
15
15
|
|
@@ -18,26 +18,26 @@ describe MTK::Timeline do
|
|
18
18
|
let(:shift_amount) { 5 }
|
19
19
|
|
20
20
|
it "is Enumerable" do
|
21
|
-
Timeline.new.should be_a Enumerable
|
21
|
+
MTK::Events::Timeline.new.should be_a Enumerable
|
22
22
|
end
|
23
23
|
|
24
24
|
it "wraps lone values in arrays" do
|
25
|
-
Timeline.
|
25
|
+
MTK::Events::Timeline.from_h(timeline_raw_data).should == MTK::Events::Timeline.from_h(timeline_hash)
|
26
26
|
end
|
27
27
|
|
28
|
-
describe "
|
28
|
+
describe "from_h" do
|
29
29
|
it "creates an empty timeline when the hash is empty" do
|
30
|
-
Timeline.
|
30
|
+
MTK::Events::Timeline.from_h({}).should be_empty
|
31
31
|
end
|
32
32
|
|
33
33
|
it "builds a Timeline from a map of times to single events" do
|
34
|
-
t = Timeline.
|
34
|
+
t = MTK::Events::Timeline.from_h({ 0 => note1, 1 => note2 })
|
35
35
|
t[0].should == [note1]
|
36
36
|
t[1].should == [note2]
|
37
37
|
end
|
38
38
|
|
39
39
|
it "builds a Timeline from a map of times to event lists" do
|
40
|
-
t = Timeline.
|
40
|
+
t = MTK::Events::Timeline.from_h({ 0 => [note1, note2], 1 => [note2] })
|
41
41
|
t[0].should == [note1, note2]
|
42
42
|
t[1].should == [note2]
|
43
43
|
end
|
@@ -45,13 +45,13 @@ describe MTK::Timeline do
|
|
45
45
|
|
46
46
|
describe "from_a" do
|
47
47
|
it "creates a timeline from an Enumerable" do
|
48
|
-
Timeline.from_a(timeline_hash.to_a).should == timeline
|
48
|
+
MTK::Events::Timeline.from_a(timeline_hash.to_a).should == timeline
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
describe "#
|
52
|
+
describe "#to_h" do
|
53
53
|
it "returns the underlying Hash" do
|
54
|
-
timeline.
|
54
|
+
timeline.to_h.should == timeline_hash
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -63,13 +63,13 @@ describe MTK::Timeline do
|
|
63
63
|
|
64
64
|
describe "#merge" do
|
65
65
|
it "merges all the time,event pairs in the given Enumerable into this Timeline" do
|
66
|
-
timeline.merge({ 3 => note2 }).should == Timeline.
|
66
|
+
timeline.merge({ 3 => note2 }).should == MTK::Events::Timeline.from_h( timeline_raw_data.merge({ 3 => note2 }) )
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
70
|
describe "#empty?" do
|
71
71
|
it "is true when the timeilne has no events" do
|
72
|
-
Timeline.new.empty?.should be_true
|
72
|
+
MTK::Events::Timeline.new.empty?.should be_true
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -109,7 +109,7 @@ describe MTK::Timeline do
|
|
109
109
|
end
|
110
110
|
|
111
111
|
it "coerces the argument to floating point for consistent lookup behavior" do
|
112
|
-
timeline =
|
112
|
+
timeline = MTK::Events::Timeline.new
|
113
113
|
timeline[nil] = note1
|
114
114
|
timeline[1] = note1
|
115
115
|
timeline[Rational(3,2)] = note1
|
@@ -136,7 +136,7 @@ describe MTK::Timeline do
|
|
136
136
|
end
|
137
137
|
|
138
138
|
it "coerces the argument to floating point for consistent lookup behavior" do
|
139
|
-
timeline =
|
139
|
+
timeline = MTK::Events::Timeline.new
|
140
140
|
timeline.add(nil, note1)
|
141
141
|
timeline.add(1, note1)
|
142
142
|
timeline.add(Rational(3,2), note1)
|
@@ -174,14 +174,14 @@ describe MTK::Timeline do
|
|
174
174
|
describe "length" do
|
175
175
|
it "is the lastest time + the longest duration of events at that time" do
|
176
176
|
len = timeline.length
|
177
|
-
len.should be_a ::MTK::Duration
|
177
|
+
len.should be_a ::MTK::Core::Duration
|
178
178
|
len.should == ::MTK.Duration(3)
|
179
179
|
end
|
180
180
|
end
|
181
181
|
|
182
182
|
describe "empty?" do
|
183
183
|
it "is true when there are no events in the timeline" do
|
184
|
-
|
184
|
+
MTK::Events::Timeline.new.empty?.should be_true
|
185
185
|
end
|
186
186
|
|
187
187
|
it "is false where there are events in the timeline" do
|
@@ -191,10 +191,10 @@ describe MTK::Timeline do
|
|
191
191
|
|
192
192
|
describe "#==" do
|
193
193
|
it "is true when the underlying Hashes are equal" do
|
194
|
-
timeline.should ==
|
194
|
+
timeline.should == MTK::Events::Timeline.from_h(timeline_hash)
|
195
195
|
end
|
196
196
|
it "is false when the underlying Hashes are not equal" do
|
197
|
-
timeline.should_not ==
|
197
|
+
timeline.should_not == MTK::Events::Timeline.from_h( {0 => [note2], 1 => [note1, note2]} )
|
198
198
|
end
|
199
199
|
it "allows for direct comparison to hashes" do
|
200
200
|
timeline.should == timeline_hash
|
@@ -216,13 +216,13 @@ describe MTK::Timeline do
|
|
216
216
|
end
|
217
217
|
|
218
218
|
describe "#map" do
|
219
|
-
it "returns a new
|
219
|
+
it "returns a new MTK::Events::Timeline where each [time,event] pair is replaced by the result of block" do
|
220
220
|
mapped = timeline.map{|time,events| [time+1, events.map{|e| e.transpose(time+2) }] }
|
221
221
|
mapped.should == { 1.0 => [note1.transpose(2)], 2.0 => [note1.transpose(3), note2.transpose(3)] }
|
222
222
|
end
|
223
223
|
|
224
224
|
it "handle events from different times being mapped to the same time" do
|
225
|
-
timeline = MTK::Timeline.
|
225
|
+
timeline = MTK::Events::Timeline.from_h({ 0.0 => [note1], 1.0 => [note1], 2.0 => [note2] })
|
226
226
|
mapped = timeline.map do |time,events|
|
227
227
|
if events == [note1]
|
228
228
|
[1.0, events]
|
@@ -233,33 +233,33 @@ describe MTK::Timeline do
|
|
233
233
|
mapped.should == { 1.0 => [note1,note1], 2.0 => [note2] }
|
234
234
|
end
|
235
235
|
|
236
|
-
it "does not modify this
|
236
|
+
it "does not modify this MTK::Events::Timeline" do
|
237
237
|
timeline.map{|t,e| [0,nil] }
|
238
238
|
timeline.should == timeline_hash
|
239
239
|
end
|
240
240
|
end
|
241
241
|
|
242
242
|
describe "#map!" do
|
243
|
-
it "maps the
|
243
|
+
it "maps the MTK::Events::Timeline in place" do
|
244
244
|
timeline.map! {|time,events| [time+1, events.map{|e| e.transpose(time+2) }] }
|
245
245
|
timeline.should == { 1.0 => [note1.transpose(2)], 2.0 => [note1.transpose(3), note2.transpose(3)] }
|
246
246
|
end
|
247
247
|
end
|
248
248
|
|
249
249
|
describe "#map_events" do
|
250
|
-
it "maps the
|
250
|
+
it "maps the MTK::Events::Timeline in place" do
|
251
251
|
mapped = timeline.map_events {|event| event.transpose(1) }
|
252
252
|
mapped.should == { 0.0 => [note1.transpose(1)], 1.0 => [note1.transpose(1), note2.transpose(1)] }
|
253
253
|
end
|
254
254
|
|
255
|
-
it "does not modify this
|
255
|
+
it "does not modify this MTK::Events::Timeline" do
|
256
256
|
timeline.map_events {|event| event.transpose(1) }
|
257
257
|
timeline.should == timeline_hash
|
258
258
|
end
|
259
259
|
end
|
260
260
|
|
261
261
|
describe "#map_events!" do
|
262
|
-
it "maps the
|
262
|
+
it "maps the MTK::Events::Timeline in place" do
|
263
263
|
timeline.map_events! {|event| event.transpose(1.0) }
|
264
264
|
timeline.should == { 0.0 => [note1.transpose(1)], 1.0 => [note1.transpose(1), note2.transpose(1)] }
|
265
265
|
end
|
@@ -278,7 +278,7 @@ describe MTK::Timeline do
|
|
278
278
|
it "maps all times to the nearest multiple of the given interval" do
|
279
279
|
unquantized_timeline.quantize(quantization_interval).should == quantized_data
|
280
280
|
end
|
281
|
-
it "returns a new
|
281
|
+
it "returns a new MTK::Events::Timeline and does not modify the original" do
|
282
282
|
unquantized_timeline.quantize(quantization_interval)
|
283
283
|
unquantized_timeline.should == unquantized_data
|
284
284
|
end
|
@@ -289,7 +289,7 @@ describe MTK::Timeline do
|
|
289
289
|
unquantized_timeline.quantize!(quantization_interval).should == quantized_data
|
290
290
|
end
|
291
291
|
|
292
|
-
it "modifies the
|
292
|
+
it "modifies the MTK::Events::Timeline in place" do
|
293
293
|
unquantized_timeline.quantize!(quantization_interval)
|
294
294
|
unquantized_timeline.should == quantized_data
|
295
295
|
end
|
@@ -308,7 +308,7 @@ describe MTK::Timeline do
|
|
308
308
|
timeline.shift(shift_amount).should be_a timeline.class
|
309
309
|
end
|
310
310
|
|
311
|
-
it "returns a new
|
311
|
+
it "returns a new MTK::Events::Timeline and does not modify the original" do
|
312
312
|
timeline.shift(shift_amount).should_not equal timeline
|
313
313
|
end
|
314
314
|
end
|
@@ -329,23 +329,23 @@ describe MTK::Timeline do
|
|
329
329
|
|
330
330
|
describe "#shift_to" do
|
331
331
|
it "shifts so the start is at the given time" do
|
332
|
-
|
333
|
-
|
332
|
+
MTK::Events::Timeline.from_h(shifted_data).shift_to(0).should == timeline
|
333
|
+
MTK::Events::Timeline.from_h(reverse_shifted_data).shift_to(0).should == timeline
|
334
334
|
end
|
335
335
|
|
336
336
|
it "returns an instance of the same type" do
|
337
337
|
timeline.shift_to(shift_amount).should be_a timeline.class
|
338
338
|
end
|
339
339
|
|
340
|
-
it "returns a new
|
340
|
+
it "returns a new MTK::Events::Timeline and does not modify the original" do
|
341
341
|
timeline.shift_to(shift_amount).should_not equal timeline
|
342
342
|
end
|
343
343
|
end
|
344
344
|
|
345
345
|
describe "#shift_to!" do
|
346
346
|
it "shifts so the start is at the given time" do
|
347
|
-
|
348
|
-
|
347
|
+
MTK::Events::Timeline.from_h(shifted_data).shift_to!(0).should == timeline
|
348
|
+
MTK::Events::Timeline.from_h(reverse_shifted_data).shift_to!(0).should == timeline
|
349
349
|
end
|
350
350
|
|
351
351
|
it "modifies the timeline in place" do
|
@@ -355,28 +355,28 @@ describe MTK::Timeline do
|
|
355
355
|
|
356
356
|
describe "#flatten" do
|
357
357
|
it "flattens nested timelines so that all nested subtimes are converted to absolute times in a single timeline" do
|
358
|
-
timeline[10] =
|
358
|
+
timeline[10] = MTK::Events::Timeline.from_h({ 0 => note2, 1 => note1 })
|
359
359
|
timeline.flatten.should == timeline_hash.merge({ 10.0 => [note2], 11.0 => [note1] })
|
360
360
|
end
|
361
361
|
|
362
362
|
it "handles nested timelines which have nested timelines inside of them" do
|
363
|
-
nested =
|
364
|
-
timeline[10] =
|
363
|
+
nested = MTK::Events::Timeline.from_h({ 0 => note1 })
|
364
|
+
timeline[10] = MTK::Events::Timeline.from_h({ 100 => nested })
|
365
365
|
timeline.flatten.should == timeline_hash.merge({ 110.0 => [note1] })
|
366
366
|
end
|
367
367
|
|
368
368
|
it "handles multiple nested timeslines at the same time point" do
|
369
|
-
timeline[10] = [Timeline.
|
369
|
+
timeline[10] = [ MTK::Events::Timeline.from_h({ 0 => note2, 1 => note1 }), MTK::Events::Timeline.from_h({ 2 => note1, 3 => note2 })]
|
370
370
|
timeline.flatten.should == timeline_hash.merge({ 10.0 => [note2], 11.0 => [note1], 12.0 => [note1], 13.0 => [note2] })
|
371
371
|
end
|
372
372
|
|
373
|
-
it "returns a new
|
373
|
+
it "returns a new MTK::Events::Timeline" do
|
374
374
|
timeline.flatten.should_not equal(timeline)
|
375
375
|
end
|
376
376
|
end
|
377
377
|
|
378
378
|
describe "#clone" do
|
379
|
-
it "creates an equal
|
379
|
+
it "creates an equal MTK::Events::Timeline" do
|
380
380
|
timeline.clone.should == timeline
|
381
381
|
end
|
382
382
|
|
@@ -387,17 +387,17 @@ describe MTK::Timeline do
|
|
387
387
|
|
388
388
|
describe ".quantize_time" do
|
389
389
|
it "takes a time and an interval, and returns the nearest multiple of the interval to the time" do
|
390
|
-
|
391
|
-
|
392
|
-
|
390
|
+
MTK::Events::Timeline.quantize_time(23,10).should == 20
|
391
|
+
MTK::Events::Timeline.quantize_time(27,10).should == 30
|
392
|
+
MTK::Events::Timeline.quantize_time(30,10).should == 30
|
393
393
|
end
|
394
394
|
|
395
395
|
it "rounds up when exactly between 2 intervals" do
|
396
|
-
|
396
|
+
MTK::Events::Timeline.quantize_time(25,10).should == 30
|
397
397
|
end
|
398
398
|
|
399
399
|
it "handles fractional intervals" do
|
400
|
-
|
400
|
+
MTK::Events::Timeline.quantize_time(13,2.5).should == 12.5
|
401
401
|
end
|
402
402
|
end
|
403
403
|
|
@@ -414,7 +414,7 @@ describe MTK::Timeline do
|
|
414
414
|
|
415
415
|
it "pretty prints the output by aligning all '=>' arrows" do
|
416
416
|
# alignment is only a factor when the times have different numbers of digits:
|
417
|
-
timeline =
|
417
|
+
timeline = MTK::Events::Timeline.new
|
418
418
|
timeline.add 0, note1
|
419
419
|
timeline.add 10, note1
|
420
420
|
timeline.add 1000, note1
|