mtk 0.0.3.2 → 0.0.3.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.
- 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
|