Last active
June 27, 2023 11:41
-
-
Save loupzeur/ecb2294a40b0a5ea9bc68904b2bf7ffc to your computer and use it in GitHub Desktop.
blender sound silence cutter, will cut out sound of silence
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bl_info = { | |
# required | |
'name': 'Silence Cutter Addon', | |
'blender': (3, 5, 1), | |
'category': 'Object', | |
# optional | |
'version': (0, 0, 1), | |
'author': 'LoupZeur', | |
'description': 'An addon that cut silence in video found in sequence editor, require pydub (pip install pydub)', | |
} | |
import bpy | |
from pydub import AudioSegment | |
silence_frame=[] | |
def detect_silence(sequence, frame_start=1, frame_end=250, frame_duration=100, threshold=1000): | |
if not hasattr(sequence, 'filepath'): | |
return | |
audio = AudioSegment.from_file(bpy.path.abspath(sequence.filepath), format="mp4") | |
global silence_frame | |
silence_frame=[] | |
# Set the initial state | |
is_silence = True | |
start_frame = frame_start | |
# Iterate through the frames | |
for frame in range(frame_start, frame_end + 1): | |
bpy.context.scene.frame_set(frame) | |
start_time = (frame-1) * 1000 / 30 | |
end_time = start_time + frame_duration #frame_duration | |
average_volume = audio[start_time:end_time].rms | |
# Determine if the frame is silent | |
if average_volume > threshold: | |
if is_silence: | |
if frame-1<=start_frame: | |
start_frame=frame | |
is_silence = False | |
continue | |
bpy.ops.sequencer.select_all() | |
# Silence has ended | |
end_frame = frame - 1 | |
bpy.ops.sequencer.split(frame=start_frame) | |
bpy.ops.sequencer.split(frame=end_frame) | |
silence_frame.append((start_frame,end_frame)) | |
start_frame = frame | |
is_silence = False | |
else: | |
if not is_silence: | |
# Silence has started | |
start_frame = frame | |
is_silence = True | |
bpy.ops.sequencer.select_all(action='DESELECT') | |
for x in silence_frame: | |
for i in bpy.context.scene.sequence_editor.sequences: | |
if i.frame_final_start>=x[0] and i.frame_final_end<=x[1]: | |
i.select=True | |
# Call the detect_silence function | |
#detect_silence(bpy.context.scene) | |
#Action operator | |
class SilenceCutterOperator(bpy.types.Operator): | |
bl_idname = 'scr.video_cutter' | |
bl_label = 'Silence Cutter' | |
def execute(self, context): | |
for obj in bpy.context.selected_sequences: | |
detect_silence( | |
obj, | |
context.scene.sc_start, | |
context.scene.sc_end, | |
context.scene.sc_sound_length, | |
context.scene.sc_sound_threshold) | |
return {'FINISHED'} | |
# To Display Options | |
class SilenceCutterPanel(bpy.types.Panel): | |
bl_idname = 'SEQUENCE_EDITOR_SILENCE_CUTTER' | |
bl_label = 'Silence Cutter' | |
bl_space_type = 'SEQUENCE_EDITOR' | |
bl_region_type = 'UI' | |
def draw(self, context): | |
col = self.layout.column() | |
for (prop_name, _) in PROPS: | |
row = col.row() | |
row.prop(context.scene, prop_name) | |
col.operator('scr.video_cutter', text='Cut') | |
CLASSES = [ | |
SilenceCutterPanel, | |
SilenceCutterOperator, | |
] | |
PROPS = [ | |
('sc_start', bpy.props.IntProperty(name='Start Frame', default=1)), | |
('sc_end', bpy.props.IntProperty(name='End Frame', default=250)), | |
('sc_sound_length', bpy.props.IntProperty(name='Audio Length to check (ms)', default=100)), | |
('sc_sound_threshold', bpy.props.IntProperty(name='Audio Threshold (rms)', default=1000)), | |
] | |
# Registering and Unregistering | |
def register(): | |
for (prop_name, prop_value) in PROPS: | |
setattr(bpy.types.Scene, prop_name, prop_value) | |
for klass in CLASSES: | |
bpy.utils.register_class(klass) | |
def unregister(): | |
for (prop_name, _) in PROPS: | |
delattr(bpy.types.Scene, prop_name) | |
for klass in CLASSES: | |
bpy.utils.unregister_class(klass) | |
if __name__ == '__main__': | |
register() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment