tef-animation 0.1.0 → 0.1.1
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.
- checksums.yaml +4 -4
- data/lib/tef/Animation/Animatable.rb +155 -2
- data/lib/tef/Animation/Animation_Handler.rb +81 -3
- data/lib/tef/Animation/Color.rb +70 -0
- data/lib/tef/Animation/Coordinate.rb +10 -0
- data/lib/tef/Animation/Eyes.rb +2 -0
- data/lib/tef/Animation/Value.rb +75 -1
- data/lib/tef/ParameterStack/Override.rb +47 -0
- data/lib/tef/ParameterStack/Stack.rb +64 -0
- data/lib/tef/ProgramSelection/ProgramID.rb +46 -0
- data/lib/tef/ProgramSelection/ProgramSelector.rb +54 -0
- data/lib/tef/ProgramSelection/SequenceCollection.rb +70 -4
- data/lib/tef/ProgramSelection/SoundCollection.rb +59 -22
- data/lib/tef/Sequencing/BaseSequence.rb +44 -2
- data/lib/tef/Sequencing/EventCollector.rb +74 -0
- data/lib/tef/Sequencing/SequencePlayer.rb +41 -1
- data/lib/tef/Sequencing/Sheet.rb +48 -0
- data/lib/tef/Sequencing/SheetSequence.rb +49 -1
- metadata +1 -1
@@ -4,9 +4,22 @@ require_relative 'ProgramID.rb'
|
|
4
4
|
|
5
5
|
module TEF
|
6
6
|
module ProgramSelection
|
7
|
+
# Sheet Sequence collection
|
8
|
+
#
|
9
|
+
# This class is meant as a convenient container for
|
10
|
+
# {Sequencing::Sheet}s. It automatically registers
|
11
|
+
# used {ID}s with the used {Selector}, and is also
|
12
|
+
# responsible for easily registering {ProgramSheet}s.
|
7
13
|
class SequenceCollection
|
14
|
+
# @return [Hash<ID, Hash>] Options to pass to
|
15
|
+
# specific sheets when instantiating them.
|
16
|
+
# Useful when re-using a {Sequencing::Sheet} for
|
17
|
+
# different programs.
|
8
18
|
attr_reader :sheet_opts
|
9
19
|
|
20
|
+
# @return [SequenceCollection] Last Collection that
|
21
|
+
# was instantiated. Used by {ProgramSelection} to
|
22
|
+
# register itself.
|
10
23
|
def self.current_collection
|
11
24
|
@current_collection
|
12
25
|
end
|
@@ -14,6 +27,26 @@ module TEF
|
|
14
27
|
@current_collection = n_collection
|
15
28
|
end
|
16
29
|
|
30
|
+
# Initialize a collection.
|
31
|
+
#
|
32
|
+
# The passed {Selector} is used to register Sheet {ID}s, while
|
33
|
+
# the passed {Sequencing::Player} is used to start
|
34
|
+
# playing Sheets when using {#play}
|
35
|
+
#
|
36
|
+
# Will set {SequenceCollection#current_collection} to self
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
# sheet_collection = SequenceCollection.new(programs, player);
|
40
|
+
#
|
41
|
+
# ProgramSheet.new() do |s|
|
42
|
+
# s.add_key 'hello', ['portal', 'turret']
|
43
|
+
#
|
44
|
+
# # Write sheet contents here.
|
45
|
+
# # The ProgramSheet will self-register to the
|
46
|
+
# # created sheet collection.
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# sheet_collection.play(programs.fetch_string('hello'));
|
17
50
|
def initialize(program_selector, sequence_runner)
|
18
51
|
@program_selector = program_selector
|
19
52
|
@sequence_runner = sequence_runner
|
@@ -24,14 +57,36 @@ module TEF
|
|
24
57
|
self.class.current_collection = self
|
25
58
|
end
|
26
59
|
|
60
|
+
# @return [nil, Sequencing::Sheet, ProgramSheet] Sheet matching
|
61
|
+
# the given {ID}, or nil.
|
27
62
|
def [](key)
|
28
63
|
@known_programs[key]
|
29
64
|
end
|
65
|
+
|
66
|
+
# Register a given program.
|
67
|
+
#
|
68
|
+
# @param [ID] key {ID} to register the program under.
|
69
|
+
# Will be registered with the {Selector} passed to the
|
70
|
+
# constructor.
|
71
|
+
# @param [Sequencing::Sheet, ProgramSheet] n_program New program
|
72
|
+
# to register.
|
30
73
|
def []=(key, n_program)
|
31
74
|
key = @program_selector.register_ID key
|
32
75
|
@known_programs[key] = n_program
|
33
76
|
end
|
34
77
|
|
78
|
+
# Start playing the {Sequencing::Sheet} matching the given {ID}
|
79
|
+
#
|
80
|
+
# This function will instantiate a new {Sequencing::SheetSequence} if
|
81
|
+
# the registered program was a {ProgramSheet}. It will pass the
|
82
|
+
# {#sheet_opts} matching its ID to the SheetSequence, and will
|
83
|
+
# additionally set the option's :program_key value to the {ID} used
|
84
|
+
# here.
|
85
|
+
# This allows easy re-using of sheets by passing parameters via
|
86
|
+
# the sheet options.
|
87
|
+
#
|
88
|
+
# The created sheet is then passed to {Sequencing::Player#[]=}, using
|
89
|
+
# either {ProgramSheet#program_key} or 'default' as key.
|
35
90
|
def play(key)
|
36
91
|
prog = @known_programs[key]
|
37
92
|
return unless prog
|
@@ -51,7 +106,14 @@ module TEF
|
|
51
106
|
end
|
52
107
|
end
|
53
108
|
|
109
|
+
# Convenience class.
|
110
|
+
# Mainly extends {Sequencing::Sheet} with an {#add_key} function, which
|
111
|
+
# self-registers this program under the last created {SequenceCollection}.
|
54
112
|
class ProgramSheet < TEF::Sequencing::Sheet
|
113
|
+
|
114
|
+
# Optional key to use when passing to {Sequencing::Player#[]=}.
|
115
|
+
# Different keys are necessary to not overwrite the previous running
|
116
|
+
# program.
|
55
117
|
attr_accessor :program_key
|
56
118
|
|
57
119
|
def initialize()
|
@@ -59,16 +121,20 @@ module TEF
|
|
59
121
|
|
60
122
|
yield(self) if block_given?
|
61
123
|
end
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
124
|
+
|
125
|
+
# Register this sheet under a given key.
|
126
|
+
# Syntax is the same as {Selector#register_ID}, with a default
|
127
|
+
# variant of '.mp3' to comply with the default variant set by
|
128
|
+
# {SoundCollection}.
|
129
|
+
def add_key(title, groups = [], variation = '.mp3', options = nil)
|
66
130
|
prog_collection = SequenceCollection.current_collection
|
67
131
|
raise "No program collection was instantiated yet!" unless prog_collection
|
68
132
|
|
69
133
|
id = ID.new(title, groups, variation)
|
70
134
|
|
71
135
|
prog_collection[id] = self
|
136
|
+
|
137
|
+
prog_collection.sheet_opts[id] = options if options.is_a? Hash
|
72
138
|
end
|
73
139
|
end
|
74
140
|
end
|
@@ -5,11 +5,59 @@ require 'yaml'
|
|
5
5
|
|
6
6
|
module TEF
|
7
7
|
module ProgramSelection
|
8
|
+
|
9
|
+
# Sound-File collection.
|
10
|
+
#
|
11
|
+
# This class is meant as convenient container for sound-filenames.
|
12
|
+
# It will automatically scan the current directory for any file ending
|
13
|
+
# with '.mp3', '.ogg' or '.wav', and will construct a unique {ID} for
|
14
|
+
# it based on the filepath.
|
15
|
+
# Paths can then be retrieved by using {#soundmap}.
|
16
|
+
#
|
17
|
+
# Additionally, it keeps a list of silences, the {#silence_maps}. They
|
18
|
+
# are auto-generated lists of silences or loud sections of the file,
|
19
|
+
# useful for auto-generating programs.
|
20
|
+
# They can be retrieved via {#silence_maps}
|
21
|
+
#
|
22
|
+
# Note that to play a sound, this should be done via
|
23
|
+
# {Sequencing::SheetSequence#play}, to ensure that the sound is killed
|
24
|
+
# in synch with the program.
|
8
25
|
class SoundCollection
|
26
|
+
# @return [Hash<String, Hash<Numeric, Numeric>>] List of noise levels
|
27
|
+
# for a given file-path. Is in the format { timestamp (in s) => 0 to 1 }
|
28
|
+
# It is ensured that a 0 is inserted at the beginning and end of the
|
29
|
+
# sound track, and it is ensured that the hash keys are sorted.
|
30
|
+
#
|
31
|
+
# @see #silences_for
|
9
32
|
attr_reader :silence_maps
|
33
|
+
|
34
|
+
# @return [Hash<ID, String>] Map of {ID}s to matching file-paths
|
10
35
|
attr_reader :soundmap
|
36
|
+
|
37
|
+
# @return [Hash] Config loaded from './sounds/soundconfig.yml'
|
11
38
|
attr_reader :load_config
|
12
39
|
|
40
|
+
# Initialize a SoundCollection
|
41
|
+
#
|
42
|
+
# This will scan the current directory for any sound files. Found
|
43
|
+
# files will auto-generate a ID based on their path, and are
|
44
|
+
# registered with the passed {Selector}.
|
45
|
+
#
|
46
|
+
# Paths are deconstructed as follows:
|
47
|
+
# - The path is split along any '/' or '-'. Each element up to
|
48
|
+
# the last is taken as a group. The last element in the list
|
49
|
+
# is taken as title.
|
50
|
+
# - The variant is generated by taking the sequence (-\d+)?\.(mp3|ogg|wav)
|
51
|
+
# from the end. This means that variants can be specified by appending
|
52
|
+
# a '-1234' to the title.
|
53
|
+
#
|
54
|
+
# './sounds/portal/announcer-hello-4.mp3' is registered as:
|
55
|
+
# {Selector#register_ID}('hello', ['sounds', 'portal', 'announcer'], '-4.mp3');
|
56
|
+
#
|
57
|
+
# Also note that a custom config file, {#load_config}, is loaded from
|
58
|
+
# a YAML file './sounds/soundconfig.yml', if present.
|
59
|
+
# Additionally, the {#silence_maps} are loaded from, and saved to,
|
60
|
+
# './sounds/silence_maps.yml'
|
13
61
|
def initialize(program_handler)
|
14
62
|
@handler = program_handler
|
15
63
|
@soundmap = {}
|
@@ -28,11 +76,11 @@ module TEF
|
|
28
76
|
`find ./`.split("\n").each { |fn| add_file fn };
|
29
77
|
|
30
78
|
File.write('./sounds/silence_maps.yml', YAML.dump(@silence_maps));
|
31
|
-
|
32
|
-
@play_pids = {};
|
33
79
|
end
|
34
80
|
|
35
|
-
|
81
|
+
# Internal function. Generates a list
|
82
|
+
# of silences/loud sections with ffmpeg.
|
83
|
+
private def generate_silences(fname)
|
36
84
|
return if @silence_maps[fname]
|
37
85
|
|
38
86
|
ffmpeg_str = `ffmpeg -i #{fname} -af silencedetect=n=0.1:d=0.1 -f null - 2>&1`
|
@@ -65,6 +113,10 @@ module TEF
|
|
65
113
|
@silence_maps[fname] = out_event
|
66
114
|
end
|
67
115
|
|
116
|
+
# Add a file to the collection of files.
|
117
|
+
#
|
118
|
+
# Will auto-generate silences and a matching {ID} as described
|
119
|
+
# in {#initialize}.
|
68
120
|
def add_file(fname)
|
69
121
|
rMatch = /^\.\/sounds\/(?<groups>(?:[a-z_]+[\/-])*)(?<title>[a-z_]+)(?<variant>(?:-\d+)?\.(?:ogg|mp3|wav))/.match fname;
|
70
122
|
return unless rMatch;
|
@@ -81,28 +133,13 @@ module TEF
|
|
81
133
|
generate_silences fname
|
82
134
|
end
|
83
135
|
|
136
|
+
# @return [Hash<Numeric, Numeric>, nil] The silence map for
|
137
|
+
# the passed {ID}, or nil if none was found.
|
138
|
+
#
|
139
|
+
# @see #silence_maps
|
84
140
|
def silences_for(key)
|
85
141
|
@silence_maps[@soundmap[key]]
|
86
142
|
end
|
87
|
-
|
88
|
-
def play(id, collection_id = 'default')
|
89
|
-
sound_name = @soundmap[id]
|
90
|
-
return if sound_name.nil?
|
91
|
-
|
92
|
-
collection_id ||= id;
|
93
|
-
|
94
|
-
if old_pid = @play_pids[collection_id]
|
95
|
-
Process.kill('QUIT', old_pid)
|
96
|
-
end
|
97
|
-
|
98
|
-
Thread.new do
|
99
|
-
fork_pid = spawn(*%W{play -q --volume 0.3 #{sound_name}});
|
100
|
-
|
101
|
-
@play_pids[collection_id] = fork_pid;
|
102
|
-
Process.waitpid fork_pid;
|
103
|
-
@play_pids.delete collection_id
|
104
|
-
end
|
105
|
-
end
|
106
143
|
end
|
107
144
|
end
|
108
145
|
end
|
@@ -1,17 +1,50 @@
|
|
1
1
|
|
2
2
|
require_relative 'EventCollector.rb'
|
3
3
|
|
4
|
+
# TheElectricFursuits module.
|
5
|
+
# @see https://github.com/TheElectricFursuits
|
4
6
|
module TEF
|
5
7
|
module Sequencing
|
8
|
+
# Base sequence class.
|
9
|
+
#
|
10
|
+
# It implements the minium necessary tools to make different Sequences
|
11
|
+
# work together nicely. It's main function is to provide {#append_events},
|
12
|
+
# which is used by a {Player} to fetch the next queued event for execution.
|
6
13
|
class BaseSequence
|
14
|
+
# @return [Numeric] Start time of this sequence, in local time.
|
15
|
+
# Specifies when to call {#setup}
|
7
16
|
attr_reader :start_time
|
17
|
+
# @return [Numeric, nil] End time of this sequence, in local time.
|
18
|
+
# Specifies when to call {#teardown}. Can be left as nil for no
|
19
|
+
# automatic teardown.
|
8
20
|
attr_reader :end_time
|
9
21
|
|
22
|
+
# @return [Numeric, Time] The offset to apply to this Sequence,
|
23
|
+
# used when converting between local-time and parent-time.
|
24
|
+
#
|
25
|
+
# This MAY be modified during runtime, though this may cause some
|
26
|
+
# events to be skipped!
|
10
27
|
attr_reader :offset
|
28
|
+
# @return [Numeric] Slope to apply to this sequence.
|
29
|
+
# @see #offset
|
11
30
|
attr_reader :slope
|
12
31
|
|
32
|
+
# @return [Symbol] State of this Sequence. Mainly used for internal
|
33
|
+
# purposes. Can be:
|
34
|
+
# - :uninitialized (right after construction)
|
35
|
+
# - :running (after having called setup())
|
36
|
+
# - :torn_down (after teardown() was called)
|
13
37
|
attr_reader :state
|
14
38
|
|
39
|
+
# Initialize a BaseSequence.
|
40
|
+
#
|
41
|
+
# @param [Numeric, Time] offset Provide a offset for time-conversion.
|
42
|
+
# @see #offset
|
43
|
+
# @param [Numeric] slope Provide a slope for time-conversion.
|
44
|
+
# @see #slope
|
45
|
+
#
|
46
|
+
# @param [Numeric] :start_time Local time to begin playing at.
|
47
|
+
# @param [Numeric] :end_time Local time to tear down at.
|
15
48
|
def initialize(offset, slope, **options)
|
16
49
|
@start_time ||= options[:start_time] || 0;
|
17
50
|
@end_time ||= options[:end_time];
|
@@ -40,6 +73,15 @@ module TEF
|
|
40
73
|
@opts_hash = nil;
|
41
74
|
end
|
42
75
|
|
76
|
+
# Look for the next possible event that this sequence wants to
|
77
|
+
# execute.
|
78
|
+
# Will ensure that this sequence's {#setup} and {#teardown} blocks
|
79
|
+
# are called at the appropriate time.
|
80
|
+
#
|
81
|
+
# Should only be called by a {Player} or another sequence!
|
82
|
+
#
|
83
|
+
# @note When using BaseSequence as base class, the user
|
84
|
+
# shall overload {#overload_append_events} rather than this function!
|
43
85
|
def append_events(collector)
|
44
86
|
local_collector = collector.offset_collector(@offset, @slope);
|
45
87
|
|
@@ -49,7 +91,7 @@ module TEF
|
|
49
91
|
|
50
92
|
if @state == :uninitialized
|
51
93
|
local_collector.add_event({
|
52
|
-
time: @start_time,
|
94
|
+
time: [@start_time, local_collector.start_time + 0.01].max,
|
53
95
|
code: proc { self.setup() }
|
54
96
|
});
|
55
97
|
end
|
@@ -61,7 +103,7 @@ module TEF
|
|
61
103
|
if !@end_time.nil?
|
62
104
|
local_collector.add_event({
|
63
105
|
time: @end_time,
|
64
|
-
code: proc { self.teardown }
|
106
|
+
code: proc { self.teardown() }
|
65
107
|
})
|
66
108
|
end
|
67
109
|
end
|
@@ -1,43 +1,83 @@
|
|
1
1
|
|
2
2
|
require 'xasin_logger'
|
3
3
|
|
4
|
+
# TheElectricFursuits module.
|
5
|
+
# @see https://github.com/TheElectricFursuits
|
4
6
|
module TEF
|
7
|
+
# Program Sequencing module.
|
8
|
+
#
|
9
|
+
# This module contains all components necessary to define how and when
|
10
|
+
# a animation or program will execute. It provides a base class
|
11
|
+
# to define how execution information is passed along between code, as well
|
12
|
+
# as a more user friendly interface to define a fixed sequence of events,
|
13
|
+
# a so called {Sheet}.
|
14
|
+
#
|
15
|
+
# {Sheet}s are designed to be as reuseable as possible,
|
16
|
+
# with dynamic creation to let the same sheet be adapted to different
|
17
|
+
# situations, as well as Sheet and Event nesting that makes it easy to
|
18
|
+
# re-use other {Sheet}s, for example to define segments of a song or
|
19
|
+
# generic beat-segments.
|
5
20
|
module Sequencing
|
21
|
+
# Purely internal class
|
22
|
+
#
|
23
|
+
# Used by {BaseSequence} when fetching the next event from child
|
24
|
+
# sequences. It wraps {EventCollector} and automatically applies
|
25
|
+
# a sequence's offset and slope, converting between the timeframe
|
26
|
+
# of the parent and the child.
|
27
|
+
#
|
28
|
+
# This collector is created in the child, within {BaseSequence#append_events}
|
6
29
|
class OffsetCollector
|
30
|
+
# @return [EventCollector] Top-Level collector
|
7
31
|
attr_reader :parent
|
8
32
|
|
33
|
+
# @return [Time] Offset of the conversion. Used as follows:
|
34
|
+
# local_time = (Time.at(x) - total_offset) * total_slope
|
9
35
|
attr_reader :total_offset
|
36
|
+
# @return [Numeric] Slope of the time conversion.
|
37
|
+
# @see #total_offset
|
10
38
|
attr_reader :total_slope
|
11
39
|
|
40
|
+
# Initialize a new offset collector.
|
41
|
+
# This should only be done via {EventCollector#offset_collector}!
|
12
42
|
def initialize(parent, total_offset, total_slope)
|
13
43
|
@parent = parent
|
14
44
|
@total_offset = total_offset
|
15
45
|
@total_slope = total_slope
|
16
46
|
end
|
17
47
|
|
48
|
+
# @param [Time, nil] global_time Time to convert
|
49
|
+
# @return [Numeric, nil] Converted time
|
18
50
|
def convert_to_local(global_time)
|
19
51
|
return nil if global_time.nil?
|
20
52
|
|
21
53
|
(global_time - @total_offset) * @total_slope
|
22
54
|
end
|
55
|
+
|
56
|
+
# @param [Numeric, nil] local_time Time (abstract) to convert back
|
57
|
+
# into the global frame.
|
58
|
+
# @return [Time, nil] Time (as Time object) of the event
|
23
59
|
def convert_to_global(local_time)
|
24
60
|
return nil if local_time.nil?
|
25
61
|
|
26
62
|
@total_offset + (local_time.to_f / @total_slope)
|
27
63
|
end
|
28
64
|
|
65
|
+
# (see EventCollector#start_time)
|
29
66
|
def start_time
|
30
67
|
convert_to_local @parent.start_time
|
31
68
|
end
|
32
69
|
|
70
|
+
# (see EventCollector#event_time)
|
33
71
|
def event_time
|
34
72
|
convert_to_local @parent.event_time
|
35
73
|
end
|
36
74
|
|
75
|
+
# (see EventCollector#has_events?)
|
37
76
|
def has_events?
|
38
77
|
return @parent.has_events?
|
39
78
|
end
|
40
79
|
|
80
|
+
# (see EventCollector#add_event)
|
41
81
|
def add_event(event)
|
42
82
|
event = event.clone
|
43
83
|
|
@@ -46,21 +86,36 @@ module TEF
|
|
46
86
|
@parent.add_event event
|
47
87
|
end
|
48
88
|
|
89
|
+
# (see EventCollector#add_events)
|
49
90
|
def add_events(list)
|
50
91
|
list.each { |event| add_event event }
|
51
92
|
end
|
52
93
|
|
94
|
+
# (see EventCollector#offset_collector)
|
53
95
|
def offset_collector(offset, slope)
|
54
96
|
OffsetCollector.new(@parent, convert_to_global(offset), @total_slope * slope)
|
55
97
|
end
|
56
98
|
end
|
57
99
|
|
100
|
+
# Event Collector class
|
101
|
+
#
|
102
|
+
# This class provides the means to efficiently fetch the next event
|
103
|
+
# from a list of {BaseSequence}s, and is mainly meant for
|
104
|
+
# internal purposes. It is created by {Player}
|
58
105
|
class EventCollector
|
59
106
|
include XasLogger::Mix
|
60
107
|
|
108
|
+
# @return [Time] The Time to start looking for an event.
|
109
|
+
# Any event earlier than this will be discarded!
|
61
110
|
attr_accessor :start_time
|
111
|
+
|
112
|
+
# @return [nil, Time] The Time of the current event, or nil if
|
113
|
+
# there is no event. Any event later than this will be
|
114
|
+
# discarded. Any event equal to this time will be appended to
|
115
|
+
# {#current_events}
|
62
116
|
attr_reader :event_time
|
63
117
|
|
118
|
+
# @return [Array<Hash>] List of current events to execute.
|
64
119
|
attr_reader :current_events
|
65
120
|
|
66
121
|
def initialize()
|
@@ -71,6 +126,12 @@ module TEF
|
|
71
126
|
init_x_log("Sequence Player")
|
72
127
|
end
|
73
128
|
|
129
|
+
# Internal function to add an event.
|
130
|
+
# The event will be discarded if it is earlier than or equal to
|
131
|
+
# start time, or later than the event time.
|
132
|
+
# It if it is earlier than event time it will set the new event time
|
133
|
+
# and set the event list to [event], else append the event
|
134
|
+
# to the event list.
|
74
135
|
def add_event(event)
|
75
136
|
return if event[:time] <= @start_time
|
76
137
|
return if (!@event_time.nil?) && (event[:time] > @event_time)
|
@@ -83,10 +144,14 @@ module TEF
|
|
83
144
|
end
|
84
145
|
end
|
85
146
|
|
147
|
+
# @return [true, false] Were any events found?
|
86
148
|
def has_events?
|
87
149
|
!@current_events.empty?
|
88
150
|
end
|
89
151
|
|
152
|
+
# This function will try to wait until {#event_time}.
|
153
|
+
# If no event was found it will return immediately, and Thread.run()
|
154
|
+
# can be used to prematurely end the wait.
|
90
155
|
def wait_until_event
|
91
156
|
return unless has_events?
|
92
157
|
|
@@ -101,6 +166,8 @@ module TEF
|
|
101
166
|
sleep t_diff if t_diff > 0
|
102
167
|
end
|
103
168
|
|
169
|
+
# Wait until the next event and then execute
|
170
|
+
# the code of each event.
|
104
171
|
def execute!
|
105
172
|
return unless has_events?
|
106
173
|
|
@@ -114,11 +181,18 @@ module TEF
|
|
114
181
|
restart();
|
115
182
|
end
|
116
183
|
|
184
|
+
# Restart this collector.
|
185
|
+
# Will clear {#current_events} and {#event_time}
|
117
186
|
def restart()
|
118
187
|
@current_events = []
|
119
188
|
@event_time = nil;
|
120
189
|
end
|
121
190
|
|
191
|
+
# Generate a {OffsetCollector}
|
192
|
+
# This is mainly an internal function used by {BaseSequence} to
|
193
|
+
# provide an {OffsetCollector}. It converts between the global time-frame
|
194
|
+
# used by this collector, and the local timeframes of each
|
195
|
+
# sub-sequence.
|
122
196
|
def offset_collector(offset, slope)
|
123
197
|
OffsetCollector.new(self, offset, slope);
|
124
198
|
end
|