[Bf-extensions-cvs] [6fcd157f] master: Storypencil: Support Audio files and UI refactor

Antonio Vazquez noreply at git.blender.org
Thu Jan 19 15:48:24 CET 2023


Commit: 6fcd157f2497d9ba4ba82191cb2abf3de11a0394
Author: Antonio Vazquez
Date:   Tue Jan 17 12:02:23 2023 +0100
Branches: master
https://developer.blender.org/rBA6fcd157f2497d9ba4ba82191cb2abf3de11a0394

Storypencil: Support Audio files and UI refactor

* Now Edit scenes support audio files included in VSE scene. 
  The audio file is copied to edit scene and allows to keep audio synch.

* Refactor UI to make easier to understand swithing modes.

* Fix some bugs founds during testing.

Thanks to Samuel Bernou for provinding base code for audio handling.

===================================================================

M	storypencil/__init__.py
M	storypencil/dopesheet_overlay.py
M	storypencil/render.py
A	storypencil/sound.py
M	storypencil/synchro.py
M	storypencil/ui.py

===================================================================

diff --git a/storypencil/__init__.py b/storypencil/__init__.py
index d1e6bd09..05b929f1 100644
--- a/storypencil/__init__.py
+++ b/storypencil/__init__.py
@@ -6,8 +6,8 @@
 bl_info = {
     "name": "Storypencil - Storyboard Tools",
     "description": "Storyboard tools",
-    "author": "Antonio Vazquez, Matias Mendiola, Daniel Martinez Lara, Rodrigo Blaas",
-    "version": (1, 1, 1),
+    "author": "Antonio Vazquez, Matias Mendiola, Daniel Martinez Lara, Rodrigo Blaas, Samuel Bernou",
+    "version": (1, 1, 3),
     "blender": (3, 3, 0),
     "location": "",
     "warning": "",
@@ -24,6 +24,7 @@ if "bpy" in locals():
     importlib.reload(synchro)
     importlib.reload(dopesheet_overlay)
     importlib.reload(scene_tools)
+    importlib.reload(sound)
     importlib.reload(render)
     importlib.reload(ui)
 else:
@@ -31,6 +32,7 @@ else:
     from . import synchro
     from . import dopesheet_overlay
     from . import scene_tools
+    from . import sound
     from . import render
     from . import ui
 
@@ -62,17 +64,23 @@ classes = (
     synchro.STORYPENCIL_OT_AddSecondaryWindowOperator,
     synchro.STORYPENCIL_OT_Switch,
     synchro.STORYPENCIL_OT_TabSwitch,
+    sound.STORYPENCIL_OT_duplicate_sound_in_edit_scene,
     render.STORYPENCIL_OT_RenderAction,
     ui.STORYPENCIL_PT_Settings,
+    ui.STORYPENCIL_PT_ModePanel,
     ui.STORYPENCIL_PT_SettingsNew,
     ui.STORYPENCIL_PT_RenderPanel,
     ui.STORYPENCIL_PT_General,
-    ui.STORYPENCIL_MT_extra_options,
 )
 
 
 def save_mode(self, context):
     wm = context.window_manager
+    if context.scene.storypencil_mode == 'WINDOW':
+        context.scene.storypencil_use_new_window = True
+    else:
+        context.scene.storypencil_use_new_window = False
+
     wm['storypencil_use_new_window'] = context.scene.storypencil_use_new_window
     # Close all secondary windows
     if context.scene.storypencil_use_new_window is False:
@@ -121,8 +129,7 @@ def register():
 
     Scene.storypencil_use_new_window = BoolProperty(name="Open in new window",
                                                     description="Use secondary main window to edit scenes",
-                                                    default=False,
-                                                    update=save_mode)
+                                                    default=False)
 
     Scene.storypencil_main_workspace = PointerProperty(type=WorkSpace,
                                                        description="Main Workspace used for editing Storyboard")
@@ -159,8 +166,8 @@ def register():
 
     Scene.storypencil_render_numbering = EnumProperty(name="Image Numbering",
                                                       items=(
-                                                            ('1', "Frame", "Use real frame number"),
-                                                            ('2', "Consecutive", "Use sequential numbering"),
+                                                            ('FRAME', "Frame", "Use real frame number"),
+                                                            ('CONSECUTIVE', "Consecutive", "Use sequential numbering"),
                                                             ),
                                                       description="Defines how frame is named")
 
@@ -168,6 +175,24 @@ def register():
                                                          description="Create a separated folder for each strip",
                                                          default=True)
 
+    Scene.storypencil_copy_sounds = BoolProperty(name="Copy Sounds",
+                                                 description="Copy automatically the sounds from VSE to edit scene",
+                                                 default=True)
+
+    Scene.storypencil_mode = EnumProperty(name="Mode",
+                                          items=(
+                                                ('SWITCH', "Switch", "Use same window and switch scene"),
+                                                ('WINDOW', "New Window", "Use a new window for editing"),
+                                                ),
+                                          update=save_mode,
+                                          description="Defines how frame is named")
+    Scene.storypencil_selected_scn_only = BoolProperty(name='Selected Scene Only',
+                                                       default=False,
+                                                       description='Selected Scenes only')
+    Scene.storypencil_skip_sound_mute = BoolProperty(name='Ignore Muted Sound',
+                                                     default=True,
+                                                     description='Skip muted sound')
+
     WindowManager.storypencil_settings = PointerProperty(
         type=synchro.STORYPENCIL_PG_Settings,
         name="Storypencil settings",
@@ -232,6 +257,10 @@ def unregister():
     del Scene.storypencil_add_render_strip
     del Scene.storypencil_render_numbering
     del Scene.storypencil_add_render_byfolder
+    del Scene.storypencil_copy_sounds
+    del Scene.storypencil_mode
+    del Scene.storypencil_selected_scn_only
+    del Scene.storypencil_skip_sound_mute
 
 if __name__ == '__main__':
     register()
diff --git a/storypencil/dopesheet_overlay.py b/storypencil/dopesheet_overlay.py
index 2c00d8e9..26aeedfe 100644
--- a/storypencil/dopesheet_overlay.py
+++ b/storypencil/dopesheet_overlay.py
@@ -58,13 +58,18 @@ def get_scene_strip_in_out(strip):
 def draw_callback_px(line_drawer: LineDrawer):
     context = bpy.context
     region = context.region
+    main_scene = context.scene.storypencil_main_scene
+    if main_scene is None:
+        return
 
+    use_win = main_scene.storypencil_use_new_window
     wm = context.window_manager
 
     if (
-            not wm.storypencil_settings.active
+            (use_win and not wm.storypencil_settings.active)
             or not wm.storypencil_settings.show_main_strip_range
-            or not is_secondary_window(wm, window_id(context.window))
+            or (use_win and not is_secondary_window(wm, window_id(context.window)))
+            or (not use_win and context.scene == main_scene)
     ):
         return
 
diff --git a/storypencil/render.py b/storypencil/render.py
index 357209df..31d07e2f 100644
--- a/storypencil/render.py
+++ b/storypencil/render.py
@@ -177,7 +177,7 @@ class STORYPENCIL_OT_RenderAction(Operator):
                             if keyframe > scene.frame_end:
                                 break
                         # For frame name use only the number
-                        if scene.storypencil_render_numbering == '1':
+                        if scene.storypencil_render_numbering == 'FRAME':
                             # Real
                             framename = strip_name + '.' + self.format_to4(key)
                         else:
diff --git a/storypencil/sound.py b/storypencil/sound.py
new file mode 100644
index 00000000..d3f43f1b
--- /dev/null
+++ b/storypencil/sound.py
@@ -0,0 +1,135 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import bpy
+from typing import List, Sequence, Tuple
+from bpy.types import (
+    Operator,
+)
+
+
+def send_sound_strip(s, dest_scn):
+    '''recreate sound strip in another scene
+    :dest_scn: scene destination
+    :return: newly create sound strip
+    '''
+
+    if s.type != 'SOUND':
+        return
+    vse = dest_scn.sequence_editor
+    ns = vse.sequences.new_sound(name=s.name, filepath=s.sound.filepath, channel=s.channel, frame_start=int(s.frame_start))
+    ns.sound = s.sound # reget the same sound source
+
+    for attr in ('pitch',
+                 'pan',
+                 'show_waveform',
+                 'speed_factor',
+                 'volume',
+                 'mute'):
+        if hasattr(s, attr):
+            setattr(ns, attr, getattr(s, attr))
+    if ns.volume == 0:
+        ns.volume = 1
+    return ns
+
+def get_all_overlapping_sound_strip(scn_strip, skip_mute=True):
+    """return array of all sound strips for this strip"""
+    if scn_strip.type != 'SCENE':
+        return
+
+    src_scn = scn_strip.id_data
+    vse = src_scn.sequence_editor
+    overlapping_sounds = []
+    for s in vse.sequences:
+        if s.type != 'SOUND':
+            continue
+        if skip_mute and s.mute:
+            continue
+
+        if (s.frame_final_end - 1 <  scn_strip.frame_final_start)\
+            or (s.frame_final_start - 1 > scn_strip.frame_final_end):
+            continue
+
+        overlapping_sounds.append(s)
+
+    return overlapping_sounds
+
+def delete_sounds(scene):
+    for st in reversed(scene.sequence_editor.sequences):
+        if st.type == 'SOUND':
+            scene.sequence_editor.sequences.remove(st)
+
+def get_scene_frame_from_sequencer_frame(scn_strip, sound) -> float:
+    """return frame in scene referential"""
+    return sound.frame_start - scn_strip.frame_start + scn_strip.scene.frame_start
+
+def send_sound_to_strip_scene(scn_strip, clear_sequencer=True, skip_mute=True):
+    """Add sounds to strip scene"""
+    if scn_strip.type != 'SCENE':
+        return
+    tgt_scene = scn_strip.scene
+
+    sounds = get_all_overlapping_sound_strip(scn_strip, skip_mute=skip_mute)
+    if not sounds:
+        return
+
+    # Clear sounds if exists in scene vse already
+    if clear_sequencer:
+        delete_sounds(tgt_scene)
+
+    print(f'Duplicating sounds in {tgt_scene.name}:')
+    for s in sounds:
+        new_start = get_scene_frame_from_sequencer_frame(scn_strip, s)
+        ns = send_sound_strip(s, tgt_scene)
+        if ns:
+            ns.frame_start = new_start
+            ns.frame_offset_start = s.frame_offset_start
+            ns.frame_final_duration = s.frame_final_duration
+
+    return sounds
+
+
+def dispatch_sounds_in_scenes(selected_scn_only=True, skip_mute=True):
+    """Main function to duplicate sounds in strip scenes"""
+    edit_scene = bpy.context.scene
+    edit = edit_scene.sequence_editor
+
+    ct = 0
+    for strip in edit.sequences:
+        if strip.type != 'SCENE':
+            continue
+
+        if selected_scn_only and not strip.select:
+     

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list