edl 0.0.1 → 0.0.2
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/History.txt +11 -0
- data/Manifest.txt +25 -0
- data/README.txt +12 -1
- data/Rakefile +6 -1
- data/SPECS.txt +75 -0
- data/bin/edl +0 -0
- data/illustr/edl-explain.ai +1182 -2
- data/lib/edl.rb +66 -146
- data/lib/edl/cutter.rb +2 -2
- data/lib/edl/event.rb +132 -0
- data/lib/edl/grabber.rb +2 -3
- data/lib/edl/timewarp.rb +45 -0
- data/lib/edl/transition.rb +23 -0
- data/test/.DS_Store +0 -0
- data/test/samples/FCP_REVERSE.EDL +9 -0
- data/test/samples/SPEEDUP_AND_FADEOUT.EDL +11 -0
- data/test/samples/SPEEDUP_REVERSE_AND_FADEOUT.EDL +11 -0
- data/test/samples/SPLICEME.EDL +1 -4
- data/test/test_edl.rb +389 -169
- metadata +32 -9
data/lib/edl.rb
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
require "rubygems"
|
|
2
2
|
require "timecode"
|
|
3
|
+
require 'stringio'
|
|
4
|
+
|
|
5
|
+
require File.dirname(__FILE__) + '/edl/event'
|
|
6
|
+
require File.dirname(__FILE__) + '/edl/transition'
|
|
7
|
+
require File.dirname(__FILE__) + '/edl/timewarp'
|
|
3
8
|
|
|
4
9
|
# A simplistic EDL parser. Current limitations: no support for DF timecode, no support for audio,
|
|
5
10
|
# no support for split edits, no support for key effects, no support for audio
|
|
6
11
|
module EDL
|
|
7
|
-
VERSION = "0.0.
|
|
8
|
-
|
|
12
|
+
VERSION = "0.0.2"
|
|
9
13
|
DEFAULT_FPS = 25
|
|
10
14
|
|
|
11
15
|
# Represents an EDL, is returned from the parser. Traditional operation is functional style, i.e.
|
|
12
16
|
# edl.renumbered.without_transitions.without_generators
|
|
13
|
-
class List
|
|
14
|
-
attr_accessor :events, :fps
|
|
17
|
+
class List < Array
|
|
15
18
|
|
|
16
|
-
def
|
|
17
|
-
|
|
19
|
+
def events #:nodoc:
|
|
20
|
+
STDERR.puts "EDL::List#events is deprecated and will be removed, use EDL::List as an array instead"
|
|
21
|
+
self
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
# Return the same EDL with all dissolves stripped and replaced by the clips
|
|
24
|
+
# Return the same EDL with all dissolves stripped and replaced by the clips underneath
|
|
21
25
|
def without_transitions
|
|
22
26
|
# Find dissolves
|
|
23
27
|
cpy = []
|
|
24
|
-
|
|
25
|
-
@events.each_with_index do | e, i |
|
|
28
|
+
each_with_index do | e, i |
|
|
26
29
|
# A dissolve always FOLLOWS the incoming clip
|
|
27
|
-
if
|
|
28
|
-
dissolve =
|
|
30
|
+
if e.ends_with_transition?
|
|
31
|
+
dissolve = self[i+1]
|
|
29
32
|
len = dissolve.transition.duration.to_i
|
|
30
33
|
|
|
31
34
|
# The dissolve contains the OUTGOING clip, we are the INCOMING. Extend the
|
|
@@ -34,7 +37,7 @@ module EDL
|
|
|
34
37
|
incoming.src_end_tc += len
|
|
35
38
|
incoming.rec_end_tc += len
|
|
36
39
|
|
|
37
|
-
outgoing = dissolve.copy_properties_to(
|
|
40
|
+
outgoing = dissolve.copy_properties_to(Event.new)
|
|
38
41
|
|
|
39
42
|
# Add the A suffix to the ex-dissolve
|
|
40
43
|
outgoing.num += 'A'
|
|
@@ -43,7 +46,7 @@ module EDL
|
|
|
43
46
|
cpy << incoming
|
|
44
47
|
cpy << outgoing
|
|
45
48
|
elsif e.has_transition?
|
|
46
|
-
# Skip, already handled
|
|
49
|
+
# Skip, already handled on the previous clip
|
|
47
50
|
else
|
|
48
51
|
cpy << e.dup
|
|
49
52
|
end
|
|
@@ -53,15 +56,14 @@ module EDL
|
|
|
53
56
|
self.class.new(cpy)
|
|
54
57
|
end
|
|
55
58
|
|
|
59
|
+
# Return the same EDL, with events renumbered starting from 001
|
|
56
60
|
def renumbered
|
|
57
|
-
renumed =
|
|
61
|
+
renumed = self.dup
|
|
58
62
|
pad = renumed.length.to_s.length
|
|
59
63
|
pad = 3 if pad < 3
|
|
60
64
|
|
|
61
65
|
(0...renumed.length).map{|e| renumed[e].num = "%0#{pad}d" % (e+1) }
|
|
62
|
-
|
|
63
|
-
puts x.inspect
|
|
64
|
-
x
|
|
66
|
+
self.class.new(renumed)
|
|
65
67
|
end
|
|
66
68
|
|
|
67
69
|
# Return the same EDL with all timewarps expanded to native length. Clip length
|
|
@@ -69,8 +71,7 @@ module EDL
|
|
|
69
71
|
# (so this is best used in concert with the original EDL where record TC is pristine)
|
|
70
72
|
def without_timewarps
|
|
71
73
|
self.class.new(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
map do | e |
|
|
74
75
|
if e.has_timewarp?
|
|
75
76
|
repl = e.copy_properties_to(e.class.new)
|
|
76
77
|
from, to = e.timewarp.actual_src_start_tc, e.timewarp.actual_src_end_tc
|
|
@@ -86,7 +87,7 @@ module EDL
|
|
|
86
87
|
# Return the same EDL without AX, BL and other GEN events (like slug, text and solids).
|
|
87
88
|
# Usually used in concert with "without_transitions"
|
|
88
89
|
def without_generators
|
|
89
|
-
self.class.new(
|
|
90
|
+
self.class.new(self.reject{|e| e.generator? })
|
|
90
91
|
end
|
|
91
92
|
|
|
92
93
|
# Return the list of clips used by this EDL at full capture length
|
|
@@ -97,9 +98,9 @@ module EDL
|
|
|
97
98
|
# Return the same EDL with the first event starting at 00:00:00:00 and all subsequent events
|
|
98
99
|
# shifted accordingly
|
|
99
100
|
def from_zero
|
|
100
|
-
shift_by =
|
|
101
|
+
shift_by = self[0].rec_start_tc
|
|
101
102
|
self.class.new(
|
|
102
|
-
|
|
103
|
+
map do | original |
|
|
103
104
|
e = original.dup
|
|
104
105
|
e.rec_start_tc = (e.rec_start_tc - shift_by)
|
|
105
106
|
e.rec_end_tc = (e.rec_end_tc - shift_by)
|
|
@@ -111,7 +112,7 @@ module EDL
|
|
|
111
112
|
# Return the same EDL with neighbouring clips joined at cuts where applicable (if a clip
|
|
112
113
|
# is divided in two pieces it will be spliced). Most useful in combination with without_timewarps
|
|
113
114
|
def spliced
|
|
114
|
-
spliced_edl =
|
|
115
|
+
spliced_edl = inject([]) do | spliced, cur |
|
|
115
116
|
latest = spliced[-1]
|
|
116
117
|
# Append to latest if splicable
|
|
117
118
|
if latest && (latest.reel == cur.reel) && (cur.src_start_tc == (latest.src_end_tc + 1))
|
|
@@ -126,112 +127,7 @@ module EDL
|
|
|
126
127
|
end
|
|
127
128
|
end
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
class Event
|
|
131
|
-
attr_accessor :num,
|
|
132
|
-
:reel,
|
|
133
|
-
:track,
|
|
134
|
-
:src_start_tc,
|
|
135
|
-
:src_end_tc,
|
|
136
|
-
:rec_start_tc,
|
|
137
|
-
:rec_end_tc,
|
|
138
|
-
:comments,
|
|
139
|
-
:original_line
|
|
140
|
-
|
|
141
|
-
def to_s
|
|
142
|
-
%w( num reel track src_start_tc src_end_tc rec_start_tc rec_end_tc).map{|a| self.send(a).to_s}.join(" ")
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def inspect
|
|
146
|
-
to_s
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def copy_properties_to(evt)
|
|
150
|
-
%w( num reel track src_start_tc src_end_tc rec_start_tc rec_end_tc).each do | k |
|
|
151
|
-
evt.send("#{k}=", send(k)) if evt.respond_to?(k)
|
|
152
|
-
end
|
|
153
|
-
evt
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
class Clip < Event
|
|
158
|
-
attr_accessor :clip_name, :timewarp
|
|
159
|
-
attr_accessor :transition
|
|
160
|
-
|
|
161
|
-
# Returns true if the clip starts with a transiton (not a jump cut)
|
|
162
|
-
def has_transition?
|
|
163
|
-
!transition.nil?
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
def has_timewarp?
|
|
167
|
-
!timewarp.nil?
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def black?
|
|
171
|
-
reel == 'BL'
|
|
172
|
-
end
|
|
173
|
-
alias_method :slug?, :black?
|
|
174
|
-
|
|
175
|
-
def length
|
|
176
|
-
(rec_end_tc - rec_start_tc).to_i
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def generator?
|
|
180
|
-
black? || (%(AX GEN).include?(reel))
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
# Represents a transition. We currently only support dissolves and SMPTE wipes
|
|
185
|
-
# Will be avilable as EDL::Clip#transition
|
|
186
|
-
class Transition
|
|
187
|
-
attr_accessor :duration, :effect
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
# Represents a dissolve
|
|
191
|
-
class Dissolve < Transition; end
|
|
192
|
-
|
|
193
|
-
# Represents an SMPTE wipe
|
|
194
|
-
class Wipe < Transition
|
|
195
|
-
attr_accessor :smpte_wipe_index
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
# Represents a timewarp
|
|
199
|
-
class Timewarp
|
|
200
|
-
attr_accessor :actual_framerate
|
|
201
|
-
attr_accessor :clip
|
|
202
|
-
|
|
203
|
-
def speed_in_percent
|
|
204
|
-
(actual_framerate.to_f / DEFAULT_FPS.to_f ) * 100
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
# Get the actual end of source that is needed for the timewarp to be computed properly,
|
|
208
|
-
# round up to not generate stills at ends of clips
|
|
209
|
-
def actual_src_end_tc
|
|
210
|
-
unless reverse?
|
|
211
|
-
clip.src_start_tc + actual_length_of_source
|
|
212
|
-
else
|
|
213
|
-
clip.src_start_tc
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def actual_src_start_tc
|
|
218
|
-
unless reverse?
|
|
219
|
-
clip.src_start_tc
|
|
220
|
-
else
|
|
221
|
-
clip.src_start_tc - actual_length_of_source
|
|
222
|
-
end
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
# Returns the true number of frames that is needed to complete the timewarp edit
|
|
226
|
-
def actual_length_of_source
|
|
227
|
-
length_in_edit = (clip.src_end_tc - clip.src_start_tc).to_i
|
|
228
|
-
((length_in_edit / 25.0) * actual_framerate).ceil.abs
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
def reverse?
|
|
232
|
-
actual_framerate < 0
|
|
233
|
-
end
|
|
234
|
-
end
|
|
130
|
+
#:stopdoc:
|
|
235
131
|
|
|
236
132
|
# A generic matcher
|
|
237
133
|
class Matcher
|
|
@@ -246,7 +142,7 @@ module EDL
|
|
|
246
142
|
end
|
|
247
143
|
|
|
248
144
|
def matches?(line)
|
|
249
|
-
line =~ @regexp
|
|
145
|
+
!!(line =~ @regexp)
|
|
250
146
|
end
|
|
251
147
|
|
|
252
148
|
def apply(stack, line)
|
|
@@ -254,6 +150,18 @@ module EDL
|
|
|
254
150
|
end
|
|
255
151
|
end
|
|
256
152
|
|
|
153
|
+
# EDL clip comment matcher, a generic one
|
|
154
|
+
class CommentMatcher < Matcher
|
|
155
|
+
def initialize
|
|
156
|
+
super(/\* (.+)/)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def apply(stack, line)
|
|
160
|
+
stack[-1].comments << line.scan(@regexp).flatten.pop.strip
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Clip name matcher
|
|
257
165
|
class NameMatcher < Matcher
|
|
258
166
|
def initialize
|
|
259
167
|
super(/\* FROM CLIP NAME:(\s+)(.+)/)
|
|
@@ -261,6 +169,7 @@ module EDL
|
|
|
261
169
|
|
|
262
170
|
def apply(stack, line)
|
|
263
171
|
stack[-1].clip_name = line.scan(@regexp).flatten.pop.strip
|
|
172
|
+
CommentMatcher.new.apply(stack, line)
|
|
264
173
|
end
|
|
265
174
|
end
|
|
266
175
|
|
|
@@ -271,6 +180,7 @@ module EDL
|
|
|
271
180
|
|
|
272
181
|
def apply(stack, line)
|
|
273
182
|
stack[-1].transition.effect = line.scan(@regexp).flatten.pop.strip
|
|
183
|
+
CommentMatcher.new.apply(stack, line)
|
|
274
184
|
end
|
|
275
185
|
end
|
|
276
186
|
|
|
@@ -297,7 +207,7 @@ module EDL
|
|
|
297
207
|
end
|
|
298
208
|
|
|
299
209
|
evt_with_tw = stack.reverse.find{|e| e.src_start_tc == tw_start_source_tc && e.reel == from_reel }
|
|
300
|
-
|
|
210
|
+
|
|
301
211
|
unless evt_with_tw
|
|
302
212
|
raise ApplyError, "Cannot find event marked by timewarp", line
|
|
303
213
|
else
|
|
@@ -326,7 +236,7 @@ module EDL
|
|
|
326
236
|
def apply(stack, line)
|
|
327
237
|
|
|
328
238
|
matches = line.scan(@regexp).shift
|
|
329
|
-
props = {
|
|
239
|
+
props = {}
|
|
330
240
|
|
|
331
241
|
# FIrst one is the event number
|
|
332
242
|
props[:num] = matches.shift
|
|
@@ -355,28 +265,33 @@ module EDL
|
|
|
355
265
|
# Then the timecodes
|
|
356
266
|
[:src_start_tc, :src_end_tc, :rec_start_tc, :rec_end_tc].each do | k |
|
|
357
267
|
begin
|
|
358
|
-
|
|
268
|
+
props[k] = EDL::Parser.timecode_from_line_elements(matches, @fps)
|
|
359
269
|
rescue Timecode::Error => e
|
|
360
270
|
raise ApplyError, "Cannot parse timecode - #{e}", line
|
|
361
271
|
end
|
|
362
272
|
end
|
|
363
273
|
|
|
364
|
-
evt =
|
|
274
|
+
evt = Event.new
|
|
365
275
|
transition_idx = props.delete(:transition)
|
|
366
276
|
evt.transition = case transition_idx
|
|
367
277
|
when 'D'
|
|
368
278
|
d = Dissolve.new
|
|
369
|
-
d.duration = props.delete(:duration)
|
|
279
|
+
d.duration = props.delete(:duration).to_i
|
|
370
280
|
d
|
|
371
|
-
when /W/
|
|
281
|
+
when /W(\d+)/
|
|
372
282
|
w = Wipe.new
|
|
373
|
-
w.duration = props.delete(:duration)
|
|
283
|
+
w.duration = props.delete(:duration).to_i
|
|
374
284
|
w.smpte_wipe_index = transition_idx.gsub(/W/, '')
|
|
375
285
|
w
|
|
376
286
|
else
|
|
377
287
|
nil
|
|
378
288
|
end
|
|
379
289
|
|
|
290
|
+
# Give a hint on the incoming clip as well
|
|
291
|
+
if evt.transition && stack[-1]
|
|
292
|
+
stack[-1].outgoing_transition_duration = evt.transition.duration
|
|
293
|
+
end
|
|
294
|
+
|
|
380
295
|
props.each_pair { | k, v | evt.send("#{k}=", v) }
|
|
381
296
|
|
|
382
297
|
stack << evt
|
|
@@ -384,6 +299,9 @@ module EDL
|
|
|
384
299
|
end
|
|
385
300
|
end
|
|
386
301
|
|
|
302
|
+
#:startdoc:
|
|
303
|
+
|
|
304
|
+
# Is used to parse an EDL
|
|
387
305
|
class Parser
|
|
388
306
|
|
|
389
307
|
attr_reader :fps
|
|
@@ -394,12 +312,15 @@ module EDL
|
|
|
394
312
|
@fps = with_fps
|
|
395
313
|
end
|
|
396
314
|
|
|
397
|
-
def get_matchers
|
|
398
|
-
[ EventMatcher.new(@fps), EffectMatcher.new, NameMatcher.new, TimewarpMatcher.new(@fps) ]
|
|
315
|
+
def get_matchers #:nodoc:
|
|
316
|
+
[ EventMatcher.new(@fps), EffectMatcher.new, NameMatcher.new, TimewarpMatcher.new(@fps), CommentMatcher.new ]
|
|
399
317
|
end
|
|
400
318
|
|
|
319
|
+
# Parse a passed File or IO object line by line, or the whole string
|
|
401
320
|
def parse(io)
|
|
402
|
-
|
|
321
|
+
return parse(StringIO.new(io.to_s)) unless io.respond_to?(:eof?)
|
|
322
|
+
|
|
323
|
+
stack, matchers = List.new, get_matchers
|
|
403
324
|
until io.eof?
|
|
404
325
|
current_line = io.gets.strip
|
|
405
326
|
matchers.each do | matcher |
|
|
@@ -412,15 +333,14 @@ module EDL
|
|
|
412
333
|
end
|
|
413
334
|
end
|
|
414
335
|
end
|
|
415
|
-
|
|
416
|
-
return List.new(stack)
|
|
336
|
+
stack
|
|
417
337
|
end
|
|
418
338
|
|
|
419
|
-
|
|
420
|
-
|
|
339
|
+
# Init a Timecode object from the passed elements with the passed framerate
|
|
340
|
+
def self.timecode_from_line_elements(elements, fps) #:nodoc:
|
|
341
|
+
args = (0..3).map{|_| elements.shift.to_i} + [fps.to_f]
|
|
421
342
|
Timecode.at(*args)
|
|
422
343
|
end
|
|
423
344
|
end
|
|
424
|
-
|
|
425
|
-
|
|
345
|
+
|
|
426
346
|
end
|
data/lib/edl/cutter.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module EDL
|
|
2
2
|
# Can chop an offline edit into events according to the EDL
|
|
3
|
-
class Cutter
|
|
3
|
+
class Cutter #:nodoc:
|
|
4
4
|
def initialize(source_path)
|
|
5
5
|
@source_path = source_path
|
|
6
6
|
end
|
|
@@ -18,7 +18,7 @@ module EDL
|
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
class FFMpegCutter < Cutter
|
|
21
|
+
class FFMpegCutter < Cutter #:nodoc:
|
|
22
22
|
def cut_segment(evt, start_at, end_at)
|
|
23
23
|
source_dir, source_file = File.dirname(@source_path), File.basename(@source_path)
|
|
24
24
|
dest_segment = File.join(source_dir, ('%s_%s' % [evt.num, source_file]))
|
data/lib/edl/event.rb
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
module EDL
|
|
2
|
+
# Represents an edit event
|
|
3
|
+
class Event
|
|
4
|
+
# Event number as in the EDL
|
|
5
|
+
attr_accessor :num
|
|
6
|
+
|
|
7
|
+
# Reel name as in the EDL
|
|
8
|
+
attr_accessor :reel
|
|
9
|
+
|
|
10
|
+
# Event tracks as in the EDL
|
|
11
|
+
attr_accessor :track
|
|
12
|
+
|
|
13
|
+
# Source start timecode of the start frame as in the EDL,
|
|
14
|
+
# no timewarps or dissolves included
|
|
15
|
+
attr_accessor :src_start_tc
|
|
16
|
+
|
|
17
|
+
# Source end timecode of the last frame as in the EDL,
|
|
18
|
+
# no timewarps or dissolves included
|
|
19
|
+
attr_accessor :src_end_tc
|
|
20
|
+
|
|
21
|
+
# Record start timecode of the event in the master as in the EDL
|
|
22
|
+
attr_accessor :rec_start_tc
|
|
23
|
+
|
|
24
|
+
# Record end timecode of the event in the master as in the EDL,
|
|
25
|
+
# outgoing transition is not included
|
|
26
|
+
attr_accessor :rec_end_tc
|
|
27
|
+
|
|
28
|
+
# Array of comment lines verbatim (all comments are included)
|
|
29
|
+
attr_accessor :comments
|
|
30
|
+
|
|
31
|
+
# Clip name contained in FROM CLIP NAME: comment
|
|
32
|
+
attr_accessor :clip_name
|
|
33
|
+
|
|
34
|
+
# Timewarp metadata (an EDL::Timewarp), or nil if no retime is made
|
|
35
|
+
attr_accessor :timewarp
|
|
36
|
+
|
|
37
|
+
# Incoming transition metadata (EDL::Transition), or nil if no transition is used
|
|
38
|
+
attr_accessor :transition
|
|
39
|
+
|
|
40
|
+
# How long is the incoming transition on the next event
|
|
41
|
+
attr_accessor :outgoing_transition_duration
|
|
42
|
+
|
|
43
|
+
def initialize(opts = {})
|
|
44
|
+
opts.each_pair{|k,v| send("#{k}=", v) }
|
|
45
|
+
yield(self) if block_given?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Output a textual description (will not work as an EDL line!)
|
|
49
|
+
def to_s
|
|
50
|
+
%w( num reel track src_start_tc src_end_tc rec_start_tc rec_end_tc).map{|a| self.send(a).to_s}.join(" ")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def inspect
|
|
54
|
+
to_s
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def comments #:nodoc:
|
|
58
|
+
@comments ||= []
|
|
59
|
+
@comments
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def outgoing_transition_duration #:nodoc:
|
|
63
|
+
@outgoing_transition_duration || 0
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Is the clip reversed in the edit?
|
|
67
|
+
def reverse?
|
|
68
|
+
(timewarp && timewarp.reverse?)
|
|
69
|
+
end
|
|
70
|
+
alias_method :reversed?, :reverse?
|
|
71
|
+
|
|
72
|
+
def copy_properties_to(evt)
|
|
73
|
+
%w( num reel track src_start_tc src_end_tc rec_start_tc rec_end_tc).each do | k |
|
|
74
|
+
evt.send("#{k}=", send(k)) if evt.respond_to?(k)
|
|
75
|
+
end
|
|
76
|
+
evt
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Returns true if the clip starts with a transiton (not a jump cut)
|
|
80
|
+
def has_transition?
|
|
81
|
+
!transition.nil?
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Returns true if the clip ends with a transition (if the next clip starts with a transition)
|
|
85
|
+
def ends_with_transition?
|
|
86
|
+
outgoing_transition_duration > 0
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Returns true if the clip has a timewarp (speed ramp, motion memory, you name it)
|
|
90
|
+
def has_timewarp?
|
|
91
|
+
!timewarp.nil?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Is this a black slug?
|
|
95
|
+
def black?
|
|
96
|
+
reel == 'BL'
|
|
97
|
+
end
|
|
98
|
+
alias_method :slug?, :black?
|
|
99
|
+
|
|
100
|
+
# Get the record length of the event (how long it occupies in the EDL without an eventual outgoing transition)
|
|
101
|
+
def rec_length
|
|
102
|
+
(rec_end_tc.to_i - rec_start_tc.to_i).to_i
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Get the record length of the event (how long it occupies in the EDL without an eventual outgoing transition)
|
|
106
|
+
def rec_length_with_transition
|
|
107
|
+
rec_length + outgoing_transition_duration.to_i
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# How long does the capture need to be to complete this event including timewarps and transitions
|
|
111
|
+
def src_length
|
|
112
|
+
@timewarp ? @timewarp.actual_length_of_source : rec_length_with_transition
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
alias_method :capture_length, :src_length
|
|
116
|
+
|
|
117
|
+
# Capture from (and including!) this timecode to complete this event including timewarps and transitions
|
|
118
|
+
def capture_from_tc
|
|
119
|
+
timewarp ? timewarp.source_used_from : src_start_tc
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Capture up to (but not including!) this timecode to complete this event including timewarps and transitions
|
|
123
|
+
def capture_to_tc
|
|
124
|
+
timewarp ? timewarp.source_used_upto : (src_start_tc + rec_length_with_transition)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Returns true if this event is a generator
|
|
128
|
+
def generator?
|
|
129
|
+
black? || (%(AX GEN).include?(reel))
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|