Class: MTK::Events::Timeline

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/mtk/events/timeline.rb

Overview

A collection of timed events. The core data structure used to interface with input and output.

Maps sorted floating point times to lists of events.

Enumerable as [time,event_list] pairs.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeTimeline

Returns a new instance of Timeline.



13
14
15
# File 'lib/mtk/events/timeline.rb', line 13

def initialize()
  @timeline = {}
end

Class Method Details

.from_a(enumerable) ⇒ Object Also known as: from_h



18
19
20
# File 'lib/mtk/events/timeline.rb', line 18

def from_a(enumerable)
  new.merge enumerable
end

.quantize_time(time, interval) ⇒ Object



227
228
229
230
231
# File 'lib/mtk/events/timeline.rb', line 227

def self.quantize_time time, interval
  upper = interval * (time.to_f/interval).ceil
  lower = upper - interval
  (time - lower) < (upper - time) ? lower : upper
end

Instance Method Details

#==(other) ⇒ Object



40
41
42
43
# File 'lib/mtk/events/timeline.rb', line 40

def == other
  other = other.to_h unless other.is_a? Hash
  @timeline == other
end

#[](time) ⇒ Object



45
46
47
# File 'lib/mtk/events/timeline.rb', line 45

def [](time)
  @timeline[time.to_f]
end

#[]=(time, events) ⇒ Object



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/mtk/events/timeline.rb', line 49

def []=(time, events)
  time = time.to_f unless time.is_a? Numeric
  case events
    when nil?
      @timeline.delete time.to_f
    when Array
      @timeline[time.to_f] = events
    else
      @timeline[time.to_f] = [events]
  end
end

#add(time, event) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/mtk/events/timeline.rb', line 61

def add(time, event)
  events = @timeline[time.to_f]
  if events
    if event.is_a? Array
      events.concat event
    else
      events << event
    end
  else
     self[time] = event
  end
end

#clearObject



31
32
33
34
# File 'lib/mtk/events/timeline.rb', line 31

def clear
  @timeline.clear
  self
end

#cloneObject



140
141
142
# File 'lib/mtk/events/timeline.rb', line 140

def clone
  self.class.from_h(to_h)
end

#compact!Object



144
145
146
# File 'lib/mtk/events/timeline.rb', line 144

def compact!
  @timeline.delete_if {|t,events| events.empty? }
end

#delete(time) ⇒ Object



74
75
76
# File 'lib/mtk/events/timeline.rb', line 74

def delete(time)
  @timeline.delete(time.to_f)
end

#eachObject



100
101
102
103
104
105
# File 'lib/mtk/events/timeline.rb', line 100

def each
  # this is similar to @timeline.each, but by iterating over #times, we yield the events in chronological order
  times.each do |time|
    yield time, @timeline[time]
  end
end

#empty?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/mtk/events/timeline.rb', line 92

def empty?
  @timeline.empty?
end

#enumerable_mapObject

the original Enumerable#map implementation, which returns an Array



108
# File 'lib/mtk/events/timeline.rb', line 108

alias enumerable_map map

#eventsObject



96
97
98
# File 'lib/mtk/events/timeline.rb', line 96

def events
  times.map{|t| @timeline[t] }.flatten
end

#flattenObject



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/mtk/events/timeline.rb', line 148

def flatten
  flattened = Timeline.new
  self.each do |time,events|
    events.each do |event|
      if event.is_a? Timeline
        event.flatten.each do |subtime,subevent|
          flattened.add(time+subtime, subevent)
        end
      else
        flattened.add(time,event)
      end
    end
  end
  flattened
end

#has_time?(time) ⇒ Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/mtk/events/timeline.rb', line 78

def has_time? time
  @timeline.has_key? time.to_f
end

#inspectObject



223
224
225
# File 'lib/mtk/events/timeline.rb', line 223

def inspect
  @timeline.inspect
end

#lengthObject



86
87
88
89
90
# File 'lib/mtk/events/timeline.rb', line 86

def length
  last_time = times.last
  events = @timeline[last_time]
  last_time + events.map{|event| event.duration }.max
end

#map(&block) ⇒ Object

Constructs a new Timeline by mapping each [time,event_list] pair

See Also:



112
113
114
# File 'lib/mtk/events/timeline.rb', line 112

def map &block
  self.class.from_a enumerable_map(&block)
end

#map!(&block) ⇒ Object

Perform #map in place

See Also:



118
119
120
121
122
# File 'lib/mtk/events/timeline.rb', line 118

def map! &block
  mapped = enumerable_map(&block)
  clear
  merge mapped
end

#map_eventsObject

Map every individual event, without regard for the time at which is occurs



125
126
127
128
129
130
131
# File 'lib/mtk/events/timeline.rb', line 125

def map_events
  mapped_timeline = Timeline.new
  self.each do |time,events|
    mapped_timeline[time] = events.map{|event| yield event }
  end
  mapped_timeline
end

#map_events!Object

Map every individual event in place, without regard for the time at which is occurs



134
135
136
137
138
# File 'lib/mtk/events/timeline.rb', line 134

def map_events!
  each do |time,events|
    self[time] = events.map{|event| yield event }
  end
end

#merge(enumerable) ⇒ Object



24
25
26
27
28
29
# File 'lib/mtk/events/timeline.rb', line 24

def merge enumerable
  enumerable.each do |time,events|
    add(time,events)
  end
  self
end

#quantize(interval) ⇒ Object

Returns a new Timeline where all times have been quantized to multiples of the given interval.

Examples:

timeline.quantize(0.5) # quantize to eight notes (assuming the beat is a quarter note)

Returns:

  • a new Timeline where all times have been quantized to multiples of the given interval

See Also:



167
168
169
# File 'lib/mtk/events/timeline.rb', line 167

def quantize interval
  map{|time,events| [self.class.quantize_time(time,interval), events] }
end

#quantize!(interval) ⇒ Object



171
172
173
# File 'lib/mtk/events/timeline.rb', line 171

def quantize! interval
  map!{|time,events| [self.class.quantize_time(time,interval), events] }
end

#shift(time_delta) ⇒ Object

shifts all times by the given amount

See Also:



178
179
180
# File 'lib/mtk/events/timeline.rb', line 178

def shift time_delta
  map{|time,events| [time+time_delta, events] }
end

#shift!(time_delta) ⇒ Object

shifts all times in place by the given amount

See Also:



185
186
187
# File 'lib/mtk/events/timeline.rb', line 185

def shift! time_delta
  map!{|time,events| [time+time_delta, events] }
end

#shift_to(absolute_time) ⇒ Object

shifts the times so that the start of the timeline is at the given time

See Also:



192
193
194
195
196
197
198
199
# File 'lib/mtk/events/timeline.rb', line 192

def shift_to absolute_time
  start = times.first
  if start
    shift absolute_time - start
  else
    clone
  end
end

#shift_to!(absolute_time) ⇒ Object

shifts the times in place so that the start of the timeline is at the given time

See Also:



204
205
206
207
208
209
210
# File 'lib/mtk/events/timeline.rb', line 204

def shift_to! absolute_time
  start = times.first
  if start
    shift! absolute_time - start
  end
  self
end

#timesObject



82
83
84
# File 'lib/mtk/events/timeline.rb', line 82

def times
  @timeline.keys.sort
end

#to_hObject



36
37
38
# File 'lib/mtk/events/timeline.rb', line 36

def to_h
  @timeline
end

#to_sObject



212
213
214
215
216
217
218
219
220
221
# File 'lib/mtk/events/timeline.rb', line 212

def to_s
  times = self.times
  last = times.last
  if last
    width = sprintf("%d",last).length + 3 # nicely align the '=>' against the longest number
    times.map{|t| sprintf("%#{width}.2f",t)+" => #{@timeline[t].join ', '}" }.join "\n"
  else
    ''
  end
end