🎥

【動画編集】テキストから字幕SRTファイルを生成してCapCutで音声読み上げ

2023/08/14に公開

エンジニアでYouTube「直也テック」を運営する直也です。

動画編集の効率化を進めており「テキストからSRTファイルを生成してCapCutで音声読み上げ」ができたので紹介します。

これができるとテロップ付きナレーション動画を簡単に作ることができます

アウトプット例


実際に今回紹介する方法でテロップ付きナレーション動画を作ってみました。

SRTファイルとは?

  • srtは「SubRip Subtitle」の略
  • テキストベースの字幕ファイル
  • このファイルには、開始時間、終了時間、および対応するテキストが記載されており、これによって動画の特定の時間帯に字幕を表示することができます

背景

  • 動画編集ソフト「CapCut」はTikTokを作るBytedance社が出している動画編集アプリ・PCソフト
    • CapCutはキャップカットと読みます
  • 動画編集ソフト「CapCut」にはテキスト読み上げ機能がある
  • PC版のCapCutでは字幕キャプションファイルのSRTをインポートできる機能がある

やりたいこと

  1. 台本からCapCut上のテキストオブジェクトを発話時刻に合わせて生成
  2. CapCut上でそれらのテキストオブジェクトを選択してテキスト読み上げ機能によって合成音声を作成(この作業は手動)

PC版のCapCutのインストール

スマホアプリが有名だけど実はPC版もある。無料。
https://www.capcut.com/ja-jp/

テキストからSRTに変換

テキスト台本

test.txt
これはテストナレーションです
今回の企画はメントスコーラです
それではやっていきたいと思います
  • 話者は一人

SRTファイルを作成

testOutput.srt
1
00:00:00,00 --> 00:00:02,98
これはテストナレーションです

2
00:00:02,98 --> 00:00:06,18
今回の企画はメントスコーラです

3
00:00:06,18 --> 00:00:09,59
それではやっていきたいと思います


  • ミリ秒の直前はカンマ区切り
  • ミリ秒の桁数が大きいとCapCutでバグりそうなので2桁まで表示

コード

環境準備

package.json
{
  "name": "srt-maker",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/node": "^20.4.5",
    "ts-node": "^10.9.1",
    "typescript": "^5.1.6"
  }
}
  • package.jsonを作成
npm install
  • installする

全体のコード

main.ts
import * as fs from 'fs';

const inputFile = 'test.txt';
const outputFile = 'testOutput.srt';

const speed = 38 / 8.1;
const startTime = { hours: 0, minutes: 0, seconds: 0, milliseconds: 0 };

function timeToString(time: { hours: number, minutes: number, seconds: number, milliseconds: number }) {
    return `${String(time.hours).padStart(2, '0')}:${String(time.minutes).padStart(2, '0')}:${String(Math.floor(time.seconds)).padStart(2, '0')},${String(Math.floor(time.milliseconds / 10)).padStart(2, '0')}`;
}

function addTime(startTime: { hours: number, minutes: number, seconds: number, milliseconds: number }, secondsToAdd: number) {
    let totalSeconds = startTime.seconds + Math.floor(secondsToAdd);
    let totalMilliseconds = startTime.milliseconds + (secondsToAdd % 1) * 1000;
    if (totalMilliseconds >= 1000) {
        totalSeconds += Math.floor(totalMilliseconds / 1000);
        totalMilliseconds %= 1000;
    }
    let totalMinutes = startTime.minutes + Math.floor(totalSeconds / 60);
    let totalHours = startTime.hours + Math.floor(totalMinutes / 60);

    return {
        hours: totalHours % 24,
        minutes: totalMinutes % 60,
        seconds: totalSeconds % 60,
        milliseconds: totalMilliseconds
    };
}

let content = fs.readFileSync(inputFile, 'utf-8');
let lines = content.split('\n').map(line => line.trim()).filter(line => line && !line.startsWith('-'));

let currentNumber = 1;
let currentStartTime = startTime;
let outputContent = '';

for (const line of lines) {
    // アルファベットの文字数を2で割る
    const adjustedLength = [...line].reduce((count, char) => {
        if (/[a-zA-Z]/.test(char)) {
            return count + 0.5;  // 2文字で1文字としてカウント
        }
        return count + 1;
    }, 0);

    let duration = adjustedLength / speed;
    let endTime = addTime(currentStartTime, duration);

    outputContent += `${currentNumber}\n`;
    outputContent += `${timeToString(currentStartTime)} --> ${timeToString(endTime)}\n`;
    outputContent += line + '\n\n';

    currentStartTime = endTime;
    currentNumber++;
}

fs.writeFileSync(outputFile, outputContent);
console.log(`SRT file generated at ${outputFile}`);

読み上げスピードを定義

main.ts
const speed = 38 / 8.1;
  • CapCutの読み上げ機能には合成音声の種類が数十種類ある
  • 今回は「カワボ」を選択(かわいいボイスの略称)
  • あらかじめCapCut上でサンプルテキストを読み上げさせてみて何文字で何秒くらいかかるのかを計測しておく
    • カワボの場合はおおよそ38文字で8.1秒だった(綺麗な数字でスピードを計算してももちろんOKです)
main.ts
// アルファベットの文字数を2で割る
const adjustedLength = [...line].reduce((count, char) => {
    if (/[a-zA-Z]/.test(char)) {
        return count + 0.5;  // 2文字で1文字としてカウント
    }
    return count + 1;
}, 0);
  • 実際に生成してみてわかったのですがアルファベットの読み上げスピードは日本語の文字よりも早いです。なのでアルファベットは2文字で1文字としてカウントしてます。

コードの実行

npx ts-node main.ts
  • srtファイルが作成される

CapCutでSRTをインポート

  • メニュー「テキスト」を選択
  • サイドメニューの「ローカルキャプション」を選択
  • インポートを選択しsrtファイルを選択

  • srtファイルがインポートされる

テキスト読み上げ

  • テキストオブジェクトを全選択
  • メニュー「テキスト読み上げ」を選択
  • 「カワボ」を選択
  • 「読み込みを開始」を選択

  • 音声を生成できた

以上です。

コードを書いて動画編集も効率化していきたいと思います。

Discussion