Page Menu
Home
Search
Configure Global Search
Log In
Files
F22010
VoiceOverAssistant.py
Public
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Authored By
iND Dev (ind)
Nov 13 2013, 4:40 PM
Size
9 KB
Subscribers
None
VoiceOverAssistant.py
View Options
bl_info
=
{
"name"
:
"Voice Over Assistant"
,
"description"
:
"Shows text over a video clip, used for "
"assisting audio voice-over recording."
,
"author"
:
"Neal Delfeld"
,
"version"
:
(
0
,
8
),
"blender"
:
(
2
,
65
,
0
),
"location"
:
"Sequencer"
,
"warning"
:
"For the time being, the filename has to be manually"
"entered in the function 'get_script_filename()'"
,
"wiki_url"
:
"http://wiki.blender.org/index.php/Extensions:2.5/Py/"
"Scripts/My_Script"
,
"tracker_url"
:
"http://projects.blender.org/tracker/index.php?"
"func=detail&aid=<number>"
,
"category"
:
"Animation"
}
'''
Uses the Header, and should probably be a Menu, but it's a Panel right now.
'''
import
bpy
import
bgl
import
blf
import
re
from
bpy.types
import
Header
,
Panel
,
Operator
# return current filename
def
get_script_filename
(
self
):
return
Put
your
filename
here
.
# font drawing function
def
draw_callback_px
(
self
,
context
):
if
not
context
.
window_manager
.
voice_over_is_on
:
return
scene
=
context
.
scene
# check for resized window/region
# reset visible chars to the max chars in order to force it to shorten later
if
self
.
regionWidth
!=
int
(
context
.
region
.
width
):
self
.
regionWidth
=
int
(
context
.
region
.
width
)
self
.
visibleChars
=
self
.
maxVisibleChars
self
.
scriptText
=
self
.
getScriptListFromFile
(
self
.
filename
)
# get the correct text line from the list
if
scene
.
use_preview_range
:
minFrm
=
scene
.
frame_preview_start
maxFrm
=
scene
.
frame_preview_end
else
:
minFrm
=
scene
.
frame_start
maxFrm
=
scene
.
frame_end
# no divide by zero
if
maxFrm
==
minFrm
:
return
curPercPos
=
max
(
0
,
min
(
1
,(
scene
.
frame_current
-
minFrm
)
/
(
maxFrm
-
minFrm
)))
showStr
=
self
.
scriptText
[
int
((
len
(
self
.
scriptText
)
-
1
)
*
curPercPos
)]
sqc
=
context
.
scene
font_id
=
0
# changing the font size has a huge memory hit, since all the cached text has to be re-written
# blf.size(font_id, sqc.voice_over_font_size, 72)
blf
.
size
(
font_id
,
21
,
72
)
# get text line's onscreen width and height
lineWid
,
lineHt
=
blf
.
dimensions
(
font_id
,
showStr
)
# shorten the max text length to fit onscreen
if
self
.
visibleChars
>
self
.
minVisibleChars
and
(
sqc
.
voice_over_pos_x
+
lineWid
)
>
(
context
.
region
.
width
-
(
sqc
.
voice_over_pos_x
*
2
)):
self
.
visibleChars
=
max
(
self
.
visibleChars
-
10
,
self
.
minVisibleChars
)
self
.
scriptText
=
self
.
getScriptListFromFile
(
self
.
filename
)
# --- RECURSION ---
draw_callback_px
(
self
,
context
)
else
:
# bgl.glColor3f(1.0, 1.0, 1.0)
bgl
.
glColor3f
(
sqc
.
voice_over_text_color
[
0
],
sqc
.
voice_over_text_color
[
1
],
sqc
.
voice_over_text_color
[
2
])
blf
.
position
(
font_id
,
sqc
.
voice_over_pos_x
,
sqc
.
voice_over_pos_y
,
0
)
blf
.
draw
(
font_id
,
showStr
)
class
VoiceOverReader
(
Operator
):
"""Voice Over Reader"""
bl_idname
=
"sequencer.voice_over_reader"
bl_label
=
"Voice Over Reader"
_fileText
=
None
_timer
=
None
_handle
=
None
regionWidth
=
0
scriptText
=
None
maxVisibleChars
=
300
minVisibleChars
=
30
visibleChars
=
maxVisibleChars
filename
=
None
# returns a list of lines of text, split into words, but no longer than visibleChars length
# it will be longer than visibleChars on certain occasions.
def
getScriptListFromFile
(
self
,
curfilename
):
if
not
self
.
_fileText
:
if
not
curfilename
:
filename
=
get_script_filename
(
self
)
curfilename
=
filename
self
.
_fileText
=
open
(
curfilename
,
"rt"
)
.
read
()
self
.
_fileText
=
re
.
sub
(
'[=]'
,
''
,
self
.
_fileText
)
self
.
_fileText
=
self
.
_fileText
.
replace
(
'
\n\n
'
,
'
\n
'
)
.
replace
(
'
\n
'
,
'
\n
(pause)
\n
'
)
self
.
_fileText
=
re
.
split
(
'\s+'
,
self
.
_fileText
)
tf3
=
[
""
]
for
wrd
in
self
.
_fileText
:
if
(
len
(
tf3
[
len
(
tf3
)
-
1
])
+
len
(
wrd
))
>
self
.
visibleChars
:
tf3
.
append
(
""
)
tf3
[
len
(
tf3
)
-
1
]
+=
wrd
+
" "
return
tf3
def
modal
(
self
,
context
,
event
):
# sometimes the region is empty, so this error check catches that
try
:
context
.
area
.
tag_redraw
()
except
:
return
{
'PASS_THROUGH'
}
# main thingy
if
event
.
type
==
'TIMER'
:
draw_callback_px
(
self
,
context
)
return
{
'PASS_THROUGH'
}
# to quit
if
event
.
type
in
{
'RIGHTMOUSE'
,
'ESC'
}:
return
self
.
cancel
(
context
)
# this is last because this function has to clear the screen first (I think)
if
not
context
.
window_manager
.
voice_over_is_on
:
return
self
.
cancel
(
context
)
return
{
'PASS_THROUGH'
}
def
invoke
(
self
,
context
,
event
):
self
.
scriptText
=
self
.
getScriptListFromFile
(
self
.
filename
)
# if context.screen.is_animation_playing:
if
context
.
window_manager
.
voice_over_is_on
is
False
:
# operator is called for the first time, start everything
context
.
window_manager
.
voice_over_is_on
=
True
self
.
regionWidth
=
0
self
.
visibleChars
=
self
.
maxVisibleChars
self
.
_timer
=
context
.
window_manager
.
event_timer_add
(
0.05
,
context
.
window
)
self
.
_handle
=
bpy
.
types
.
SpaceSequenceEditor
.
draw_handler_add
(
draw_callback_px
,
(
self
,
context
),
'WINDOW'
,
'POST_PIXEL'
)
context
.
window_manager
.
modal_handler_add
(
self
)
return
{
'RUNNING_MODAL'
}
else
:
# operator is called again, stop displaying
return
self
.
cancel
(
context
)
# remove event listeners, etc.
def
cancel
(
self
,
context
):
try
:
context
.
window_manager
.
event_timer_remove
(
self
.
_timer
)
except
:
pass
try
:
bpy
.
types
.
SpaceSequenceEditor
.
draw_handler_remove
(
self
.
_handle
,
'WINDOW'
)
except
:
pass
context
.
window_manager
.
voice_over_is_on
=
False
return
{
'CANCELLED'
}
# properties used by the script
def
init_properties
():
sequencer
=
bpy
.
types
.
Scene
wm
=
bpy
.
types
.
WindowManager
sequencer
.
voice_over_script_filename
=
bpy
.
props
.
StringProperty
(
name
=
"Script Filename"
,
description
=
"Script Filename"
,
# get=get_script_filename,
subtype
=
'FILE_PATH'
)
sequencer
.
voice_over_pos_x
=
bpy
.
props
.
IntProperty
(
name
=
"X"
,
description
=
"Voice over text Y position"
,
default
=
15
,
min
=
5
,
max
=
100
)
sequencer
.
voice_over_pos_y
=
bpy
.
props
.
IntProperty
(
name
=
"Y"
,
description
=
"Voice over text Y position"
,
default
=
30
,
min
=
5
,
max
=
100
)
sequencer
.
voice_over_text_color
=
bpy
.
props
.
FloatVectorProperty
(
name
=
"Color"
,
description
=
"Voice over text color"
,
default
=
(
1.0
,
1.0
,
1.0
,
1.0
),
min
=
0.1
,
max
=
1
,
subtype
=
'COLOR'
,
size
=
4
)
# sequencer.voice_over_font_size = bpy.props.IntProperty(
# name="Size",
# description="Voice over text size",
# default=21, min=12, max=24)
# Runstate initially always set to False
# note: it is not stored in the sequencer, but in window manager:
wm
.
voice_over_is_on
=
bpy
.
props
.
BoolProperty
(
default
=
False
)
# removal of properties when script is disabled
def
clear_properties
():
props
=
(
"voice_over_is_on"
,
"voice_over_script_filename"
,
"voice_over_pos_x"
,
"voice_over_pos_y"
,
"voice_over_text_color"
,
# "voice_over_font_size",
)
wm
=
bpy
.
context
.
window_manager
for
p
in
props
:
if
p
in
wm
:
del
wm
[
p
]
# defining the header items
class
SEQ_Voice_Over_Reader_display
(
Header
):
bl_label
=
"Voice Over Reader Display"
bl_space_type
=
'SEQUENCE_EDITOR'
bl_idname
=
"SEQ_Voice_Over_Reader_display"
@classmethod
def
poll
(
cls
,
context
):
return
(
context
.
object
is
not
None
)
def
draw
(
self
,
context
):
wm
=
context
.
window_manager
sc
=
context
.
scene
layout
=
self
.
layout
if
not
wm
.
voice_over_is_on
:
layout
.
operator
(
"sequencer.voice_over_reader"
,
text
=
"Voice Over"
,
icon
=
"PLAY"
)
else
:
layout
.
operator
(
"sequencer.voice_over_reader"
,
text
=
"Hide V.O."
,
icon
=
"PAUSE"
)
row
=
layout
.
row
()
row
.
prop
(
sc
,
"voice_over_script_filename"
,
text
=
""
)
row
=
layout
.
row
(
align
=
True
)
# row.label(text="Position:")
row
.
prop
(
sc
,
"voice_over_pos_x"
,
text
=
"X"
)
row
.
prop
(
sc
,
"voice_over_pos_y"
,
text
=
"Y"
)
row
=
layout
.
row
()
row
.
prop
(
sc
,
"voice_over_text_color"
,
text
=
""
)
# row = layout.row(align = True)
# row.prop(sc, "voice_over_font_size")
def
register
():
init_properties
()
bpy
.
utils
.
register_class
(
SEQ_Voice_Over_Reader_display
)
bpy
.
utils
.
register_class
(
VoiceOverReader
)
def
unregister
():
bpy
.
utils
.
unregister_class
(
VoiceOverReader
)
bpy
.
utils
.
unregister_class
(
SEQ_Voice_Over_Reader_display
)
clear_properties
()
if
__name__
==
"__main__"
:
register
()
# if __name__ == "__main__": # only for live edit.
# bpy.utils.register_module(__name__)
File Metadata
Details
Mime Type
text/x-python
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a7/20/4401af99f38c8a52edfedd89fd14
Event Timeline
Log In to Comment