Remove deprecated 2D_/3D_ prefix
[blender-addons.git] / storypencil / sound.py
blob987710d07957466401b72f5a2e818fb3f5c6d0c0
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 import bpy
4 from typing import List, Sequence, Tuple
5 from bpy.types import (
6 Operator,
10 def send_sound_strip(s, dest_scn):
11 '''recreate sound strip in another scene
12 :dest_scn: scene destination
13 :return: newly create sound strip
14 '''
16 if s.type != 'SOUND':
17 return
18 vse = dest_scn.sequence_editor
19 ns = vse.sequences.new_sound(name=s.name, filepath=s.sound.filepath, channel=s.channel, frame_start=int(s.frame_start))
20 ns.sound = s.sound # reget the same sound source
22 for attr in ('pitch',
23 'pan',
24 'show_waveform',
25 'speed_factor',
26 'volume',
27 'mute'):
28 if hasattr(s, attr):
29 setattr(ns, attr, getattr(s, attr))
30 if ns.volume == 0:
31 ns.volume = 1
32 return ns
34 def get_all_overlapping_sound_strip(scn_strip, skip_mute=True):
35 """return array of all sound strips for this strip"""
36 if scn_strip.type != 'SCENE':
37 return
39 src_scn = scn_strip.id_data
40 vse = src_scn.sequence_editor
41 overlapping_sounds = []
42 for s in vse.sequences:
43 if s.type != 'SOUND':
44 continue
45 if skip_mute and s.mute:
46 continue
48 if (s.frame_final_end - 1 < scn_strip.frame_final_start)\
49 or (s.frame_final_start - 1 > scn_strip.frame_final_end):
50 continue
52 overlapping_sounds.append(s)
54 return overlapping_sounds
56 def delete_sounds(scene):
57 for st in reversed(scene.sequence_editor.sequences):
58 if st.type == 'SOUND':
59 scene.sequence_editor.sequences.remove(st)
61 def get_scene_frame_from_sequencer_frame(scn_strip, sound) -> float:
62 """return frame in scene referential"""
63 return sound.frame_start - scn_strip.frame_start + scn_strip.scene.frame_start
65 def send_sound_to_strip_scene(scn_strip, clear_sequencer=True, skip_mute=True):
66 """Add sounds to strip scene"""
67 if scn_strip.type != 'SCENE':
68 return
69 tgt_scene = scn_strip.scene
71 sounds = get_all_overlapping_sound_strip(scn_strip, skip_mute=skip_mute)
72 if not sounds:
73 return
75 # Clear sounds if exists in scene vse already
76 if clear_sequencer:
77 delete_sounds(tgt_scene)
79 print(f'Duplicating sounds in {tgt_scene.name}:')
80 for s in sounds:
81 new_start = get_scene_frame_from_sequencer_frame(scn_strip, s)
82 ns = send_sound_strip(s, tgt_scene)
83 if ns:
84 ns.frame_start = new_start
85 ns.frame_offset_start = s.frame_offset_start
86 ns.frame_final_duration = s.frame_final_duration
88 return sounds
91 def dispatch_sounds_in_scenes(selected_scn_only=True, skip_mute=True):
92 """Main function to duplicate sounds in strip scenes"""
93 edit_scene = bpy.context.scene
94 edit = edit_scene.sequence_editor
96 ct = 0
97 for strip in edit.sequences:
98 if strip.type != 'SCENE':
99 continue
101 if selected_scn_only and not strip.select:
102 continue
104 sounds = send_sound_to_strip_scene(strip, skip_mute=skip_mute)
105 if sounds:
106 ct += 1
108 if ct:
109 print('INFO', f'Sound duplicated in {ct} scenes')
110 else:
111 print('ERROR', f'No duplication occured')
114 class STORYPENCIL_OT_duplicate_sound_in_edit_scene(Operator):
115 bl_idname = "storypencil.duplicate_sound_in_edit_scene"
116 bl_label = "Sounds To Scenes"
117 bl_description = "Copy sound strips from VSE to the source scenes"
118 bl_options = {'REGISTER', 'UNDO'}
120 @classmethod
121 def poll(cls, context):
122 if context.space_data.type != 'SEQUENCE_EDITOR':
123 return False
125 return True
127 def execute(self, context):
128 scene = context.scene
129 dispatch_sounds_in_scenes(
130 selected_scn_only=scene.storypencil_selected_scn_only,
131 skip_mute=scene.storypencil_skip_sound_mute)
133 bpy.ops.sequencer.reload()
135 return {'FINISHED'}