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
@@ -6,7 +6,25 @@ require_relative 'SheetSequence.rb'
|
|
6
6
|
|
7
7
|
module TEF
|
8
8
|
module Sequencing
|
9
|
+
# Sequene Player class.
|
10
|
+
#
|
11
|
+
# This class is meant as a easy means to play {BaseSequence}s.
|
12
|
+
# It allows the user to start and stop sequences, play them in parallel,
|
13
|
+
# or overwrite them.
|
14
|
+
#
|
15
|
+
# Register hooks to be called after an execution step with {#after_exec}.
|
16
|
+
#
|
17
|
+
# Start playing a sequence by using {#[]=}, then use {#delete} to stop
|
18
|
+
# it prematurely.
|
19
|
+
#
|
20
|
+
# @todo Add pausing of sequences. Requires the BaseSequence to have a
|
21
|
+
# time conversion built-in as well.
|
9
22
|
class Player
|
23
|
+
|
24
|
+
# Initialize a player instance
|
25
|
+
#
|
26
|
+
# It can immediately be used to play {BaseSequence}s or {Sheet}s, though
|
27
|
+
# {#after_exec} callbacks should first be registered.
|
10
28
|
def initialize()
|
11
29
|
@activeSequences = {}
|
12
30
|
@sequenceMutex = Mutex.new
|
@@ -24,10 +42,31 @@ module TEF
|
|
24
42
|
@playThread.abort_on_exception = true
|
25
43
|
end
|
26
44
|
|
45
|
+
# Add a callback to be executed after a animation step.
|
46
|
+
#
|
47
|
+
# The block passed to this function will be executed after each
|
48
|
+
# {EventCollector#execute!}, i.e. after every tick of the animation
|
49
|
+
# system.
|
50
|
+
# This makes it possible to connect it to the Animation system,
|
51
|
+
# for example by calling {Animation::Handler#update_tick},
|
52
|
+
# as well as the parameter stack by calling
|
53
|
+
# {ParameterStack::Stack#process_changes}
|
27
54
|
def after_exec(&block)
|
28
55
|
@post_exec_cbs << block if block_given?
|
29
56
|
end
|
30
57
|
|
58
|
+
# Insert and start a new program.
|
59
|
+
#
|
60
|
+
# This will:
|
61
|
+
# - Stop and tear the currently playing program under 'key' down.
|
62
|
+
# - Instantiate a {SheetSequence} IF the program is a {Sheet}
|
63
|
+
# - Immediately start playing the new program.
|
64
|
+
#
|
65
|
+
# The inserted program is returned.
|
66
|
+
# {#delete} can be used to stop a given program.
|
67
|
+
#
|
68
|
+
# @param key Arbitrary key to identify the program with.
|
69
|
+
# @param [BaseSequence, Sheet] program Program to start playing.
|
31
70
|
def []=(key, program)
|
32
71
|
@sequenceMutex.synchronize do
|
33
72
|
if @activeSequences[key]
|
@@ -35,7 +74,6 @@ module TEF
|
|
35
74
|
end
|
36
75
|
|
37
76
|
if program.is_a? Sheet
|
38
|
-
puts "Inited sheet with start at #{Time.now()}"
|
39
77
|
program = SheetSequence.new(Time.now(), 1, sheet: program)
|
40
78
|
end
|
41
79
|
|
@@ -48,6 +86,8 @@ module TEF
|
|
48
86
|
program
|
49
87
|
end
|
50
88
|
|
89
|
+
# Delete a given program by its key.
|
90
|
+
# This will stop and tear the specified program down.
|
51
91
|
def delete(key)
|
52
92
|
@sequenceMutex.synchronize do
|
53
93
|
if @activeSequences[key]
|
data/lib/tef/Sequencing/Sheet.rb
CHANGED
@@ -1,16 +1,51 @@
|
|
1
1
|
|
2
|
+
require_relative 'EventCollector.rb'
|
2
3
|
|
3
4
|
module TEF
|
4
5
|
module Sequencing
|
6
|
+
# Sheet class
|
7
|
+
#
|
8
|
+
# This class is meant as a container for the minimum
|
9
|
+
# amount of information necessary to instantiate a {SheetSequence}.
|
10
|
+
#
|
11
|
+
# It provides a clean and easy way for the user to define
|
12
|
+
# a sequence of events, as well as minimally necessary information
|
13
|
+
# such as the speed of the sequence or the starting and ending
|
14
|
+
# times.
|
5
15
|
class Sheet
|
16
|
+
# @return [Numeric] The local starting time. Defaults to
|
17
|
+
# 0, i.e the sheet will start playing immediately.
|
18
|
+
# This does not affect the actual time scaling, but instead
|
19
|
+
# is merely used to know when to instantiate the {SheetSequence}
|
6
20
|
attr_accessor :start_time
|
21
|
+
|
22
|
+
# @return [Numeric] The local ending-time. Defaults to nil, i.e.
|
23
|
+
# it will be auto-determined by the notes in the sheet.
|
24
|
+
# Affects when the sheet is torn down and stops
|
25
|
+
# execution!
|
7
26
|
attr_accessor :end_time
|
8
27
|
|
28
|
+
# @return [Numeric, nil] Tempo of the sheet. Defines the execution
|
29
|
+
# speed in BPM. If left nil, the execution speed of the parent
|
30
|
+
# sheet is used.
|
9
31
|
attr_accessor :tempo
|
10
32
|
|
33
|
+
# @return [nil, Proc] Block to call when setting up the {SheetSequence}.
|
34
|
+
# This is the main way of letting the user configure the {SheetSequence},
|
35
|
+
# as this block is called from the context of the sheet itself.
|
36
|
+
# Look at the functions of the Sheet Sequence for more details.
|
37
|
+
#
|
38
|
+
# @see SheetSequence#at
|
39
|
+
# @see SheetSequence#after
|
40
|
+
# @see SheetSequence#play
|
11
41
|
attr_reader :setup_block
|
12
42
|
attr_reader :teardown_block
|
13
43
|
|
44
|
+
# Initialize a new Sheet.
|
45
|
+
#
|
46
|
+
# The user should configure the sheet by writing into
|
47
|
+
# {#start_time}, {#end_time} and by supplying at least a
|
48
|
+
# {#sequence}
|
14
49
|
def initialize()
|
15
50
|
@start_time = 0;
|
16
51
|
@end_time = nil;
|
@@ -21,10 +56,23 @@ module TEF
|
|
21
56
|
@teardown_block = nil;
|
22
57
|
end
|
23
58
|
|
59
|
+
# Configure a block to call when setting up the {SheetSequence}.
|
60
|
+
# This is the main way of letting the user configure the {SheetSequence},
|
61
|
+
# as this block is called from the context of the sheet itself.
|
62
|
+
# Look at the functions of the Sheet Sequence for more details.
|
63
|
+
#
|
64
|
+
# @see SheetSequence#at
|
65
|
+
# @see SheetSequence#after
|
66
|
+
# @see SheetSequence#play
|
24
67
|
def sequence(&block)
|
25
68
|
@setup_block = block;
|
26
69
|
end
|
27
70
|
|
71
|
+
# Configure the block to call when the {SheetSequence} is about to
|
72
|
+
# be torn down. Use this to stop or delete any resources allocated
|
73
|
+
# to the sheet.
|
74
|
+
#
|
75
|
+
# Guaranteed to always be called.
|
28
76
|
def teardown(&block)
|
29
77
|
@teardown_block = block;
|
30
78
|
end
|
@@ -4,7 +4,25 @@ require_relative 'Sheet.rb'
|
|
4
4
|
|
5
5
|
module TEF
|
6
6
|
module Sequencing
|
7
|
+
# Sheet Sequence class.
|
8
|
+
#
|
9
|
+
# This is the main way for the user to specify an exact sequence of events
|
10
|
+
# to execute. It is construced with the help of a {Sheet}, which
|
11
|
+
# acts as specification for this Sheet Sequence.
|
12
|
+
#
|
13
|
+
# Think of the {Sheet} as being the script for a play or movie, while
|
14
|
+
# the {SheetSequence} has the job of actually performing everything.
|
7
15
|
class SheetSequence < BaseSequence
|
16
|
+
|
17
|
+
# Initialize a SheetSequence.
|
18
|
+
#
|
19
|
+
# This is mostly done via {Player#[]=} by passing a {Sheet}.
|
20
|
+
# However, a sequence can also be manually instantiated.
|
21
|
+
#
|
22
|
+
# After initialization, the sheet's {Sheet#setup_block} is called
|
23
|
+
# to fill this SheetSequence with actual content.
|
24
|
+
# The user may also call {#at} and {#after} manually to add additional
|
25
|
+
# events.
|
8
26
|
def initialize(offset, slope, **options)
|
9
27
|
super(offset, slope, **options);
|
10
28
|
|
@@ -55,6 +73,23 @@ module TEF
|
|
55
73
|
super();
|
56
74
|
end
|
57
75
|
|
76
|
+
# Insert an event or subsheet into the event list.
|
77
|
+
#
|
78
|
+
# This is the main way of adding events to this sequence.
|
79
|
+
# Each call to the function will insert a new event at the specified
|
80
|
+
# time, which will call the passed block.
|
81
|
+
# If, instead, a parameter called :sheet or :sequence is passed,
|
82
|
+
# instead the the passed sequence will be instantiated and
|
83
|
+
# added to the list of programs.
|
84
|
+
# Any further options are directly passed to the constructor
|
85
|
+
# of the class specified by the :sequence parameter
|
86
|
+
#
|
87
|
+
# If a block was passed, it will be instance_exec'd at the specified
|
88
|
+
# time.
|
89
|
+
#
|
90
|
+
# Note that any used or created resources shall be destroyed in
|
91
|
+
# the {Sheet#teardown} block. Sub-Sequences as well as notes
|
92
|
+
# played by {#play} are automatically torn down.
|
58
93
|
def at(time, **options, &block)
|
59
94
|
@latest_note_time = time;
|
60
95
|
|
@@ -82,10 +117,22 @@ module TEF
|
|
82
117
|
@notes.insert((i || -1), new_event);
|
83
118
|
end
|
84
119
|
|
120
|
+
# Similar to {#at}, but specifies time relative to the
|
121
|
+
# last event time.
|
122
|
+
# @see #at
|
85
123
|
def after(time, **options, &block)
|
86
124
|
at(time + (@latest_note_time || 0) , **options, &block);
|
87
125
|
end
|
88
126
|
|
127
|
+
# Play a music file, using `play`
|
128
|
+
#
|
129
|
+
# The PID of the music playing task is saved, and the process
|
130
|
+
# will be killed when this sheet is torn down. The user does not
|
131
|
+
# have to do anything else, but may choose to prematurely kill
|
132
|
+
# the playback by using {#kill}
|
133
|
+
#
|
134
|
+
# @param [String] music_piece Path of the file to play.
|
135
|
+
# @return [Numeric] The PID of the spawned process.
|
89
136
|
def play(music_piece, volume = 0.3)
|
90
137
|
play_pid = spawn(*%W{play -q --volume #{volume} #{music_piece}});
|
91
138
|
|
@@ -98,11 +145,12 @@ module TEF
|
|
98
145
|
play_pid
|
99
146
|
end
|
100
147
|
|
148
|
+
# Shorthand to kill
|
101
149
|
def kill(pid)
|
102
150
|
Process.kill('QUIT', pid);
|
103
151
|
end
|
104
152
|
|
105
|
-
def overload_append_events(collector)
|
153
|
+
private def overload_append_events(collector)
|
106
154
|
i = 0
|
107
155
|
loop do
|
108
156
|
next_program = @subprograms[i]
|