Welcome to mirror list, hosted at ThFree Co, Russian Federation.

align_audios.py « operators « power_sequencer - git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: a280f1fdec619ad083e5360429b72a11fe1b6094 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#
# Copyright (C) 2016-2019 by Nathan Lovato, Daniel Oakey, Razvan Radulescu, and contributors
#
# This file is part of Power Sequencer.
#
# Power Sequencer is free software: you can redistribute it and/or modify it under the terms of the
# GNU General Public License as published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# Power Sequencer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with Power Sequencer. If
# not, see <https://www.gnu.org/licenses/>.
#
import bpy

from .utils.doc import doc_name, doc_idname, doc_brief, doc_description


class POWER_SEQUENCER_OT_align_audios(bpy.types.Operator):
    """*brief* Align two audio strips


    Tries to synchronize the selected audio strip to the active audio strip by comparing the sound.
    Useful to synchronize audio of the same event recorded with different microphones.

    To use this feature, you must have [ffmpeg](https://www.ffmpeg.org/download.html) and
    [scipy](https://www.scipy.org/install.html) installed on your computer and available on the PATH (command line) to work.

    The longer the audio files, the longer the tool can take to run, as it has to convert, analyze,
    and compare the audio sources to work.
    """

    doc = {
        "name": doc_name(__qualname__),
        "demo": "https://i.imgur.com/xkBUzDj.gif",
        "description": doc_description(__doc__),
        "shortcuts": [],
        "keymap": "Sequencer",
    }
    bl_idname = doc_idname(__qualname__)
    bl_label = doc["name"]
    bl_description = doc_brief(doc["description"])
    bl_options = {"REGISTER", "UNDO"}

    @classmethod
    def poll(cls, context):
        if not context.scene:
            return False

        active = context.scene.sequence_editor.active_strip
        selected = context.selected_sequences
        ok = (
            len(selected) == 2
            and active in selected
            and all(map(lambda s: s.type == "SOUND", selected))
        )
        return ok

    def execute(self, context):
        try:
            import scipy
        except ImportError:
            self.report({"ERROR"}, "Scipy must be installed to align audios")
            return {"FINISHED"}

        if not is_ffmpeg_available():
            self.report({"ERROR"}, "ffmpeg must be installed to align audios")
            return {"FINISHED"}

        # This import is here because otherwise, it slows down blender startup
        from .audiosync import find_offset

        scene = context.scene

        active = scene.sequence_editor.active_strip
        active_filepath = bpy.path.abspath(active.sound.filepath)

        selected = context.selected_sequences
        selected.pop(selected.index(active))

        align_strip = selected[0]
        align_strip_filepath = bpy.path.abspath(align_strip.sound.filepath)

        offset, score = find_offset(align_strip_filepath, active_filepath)

        initial_offset = active.frame_start - align_strip.frame_start

        fps = scene.render.fps / scene.render.fps_base
        frames = int(offset * fps)

        align_strip.frame_start -= frames - initial_offset

        self.report({"INFO"}, "Alignment score: " + str(round(score, 1)))

        return {"FINISHED"}


def is_ffmpeg_available():
    """
    Returns true if ffmpeg is installed and available from the PATH
    """
    try:
        subprocess.call(["ffmpeg", "--help"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        return True
    except OSError:
        return False