tef-animation 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|