0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

歌ってみた・VTuber歌枠のステム分離をn8nで自動化する:n8n-nodes-stemsplit ノードでHTTP Request + Wait + IFループを置き換える【2026年版】

0
Posted at

歌ってみたのミックス前処理や、VTuber 歌枠のセトリぶんのオフボーカル準備、案件カバー曲のドラム抜き音源生成——こういう「曲を投げたらステム分離して、結果のURLをDiscordなりS3なりに流したい」系のジョブを、n8n で組んでいる方は多いと思います。

普段から組んでいる方ほど、こういう構成に見覚えがあるはずです。

[HTTP Request: POST /jobs] → [Wait 5s] → [HTTP Request: GET /jobs/:id]
   → [IF: status === COMPLETED?]
       → true:  [Set: 結果のURLを抜き出す]
       → false: [Wait 5s] にループバック

ノードが5つ、分岐が2本、タイムアウト処理は手動。深夜にジョブが詰まって初めて気づく、あの構成です。

このたび npm に n8n-nodes-stemsplit を公開したので、上記の HTTP Request + Wait + IF ループを 1ノードに置き換えるところまでをこの記事でまとめます。歌ってみた・VTuber 歌枠の現場でそのまま使える前提で書きます。

本記事は n8n 側の自動化に焦点を当てています。歌ってみたのオフボーカルを Python で自作する手順は 歌ってみた用のオフボーカル音源をPythonで自作する方法 を、配信現場のセトリ準備フローは VTuberの歌枠配信用カラオケ音源を5分で量産するPythonスクリプト を参照してください。


この記事でわかること

  • ✅ n8n コミュニティノード n8n-nodes-stemsplit のインストール手順
  • StemSplit API 認証情報(sk_live_...)のセットアップ
  • Separate Stems (Wait) ノードでポーリングループを丸ごと消す方法
  • ✅ vocals / drums / bass / piano / guitar / other / instrumental の presigned URL を1ノードで取得するワークフロー
  • ✅ 歌ってみた・VTuber 歌枠想定の n8n ワークフロー JSON(コピペで動く)
  • ✅ バッチ向けの「Fire-and-forget + Get Job」構成も併記

想定するユースケース

歌ってみた・VTuber 周りで、n8n に寄せると楽になるジョブの典型例です。

シーン 入力 欲しい出力 推奨オペレーション
歌ってみた用オフボーカル生成 原曲の MP3/WAV instrumentalUrl Separate Stems (Wait) / BOTH
VTuber 歌枠のセトリ一括処理 原曲ファイルのリスト instrumentalUrl(10曲分) Separate Stems(並列) + Get Job(後追いポーリング)
ミックス師向けの素材分離 クライアントから届いた WAV vocalsUrl, drumsUrl, bassUrl, otherUrl Separate Stems (Wait) / FOUR_STEMS
耳コピ・楽曲解析の下処理 公開楽曲の URL 6 ステム全部 Separate Stems (Wait) / SIX_STEMS

n8n を使いたくなる一番の理由は、Discord / Telegram / Google Drive / S3 / Notion といった外部サービスとの繋ぎ込みが既存ノードで済むことです。「Discord でファイルが投稿されたら → ステム分離して → 結果のリンクを別チャンネルに通知」みたいな線がそのまま引けます。


前提条件

  • n8n v0.200 以降(セルフホスト or n8n Cloud のコミュニティノード許可済みインスタンス)
  • StemSplit のアカウントと API キー(sk_live_... 形式、stemsplit.io/app/settings/api で発行)
  • ステム分離したい楽曲のクレジット残高(1 秒 = 1 クレジット)

クレジット残高は無料枠でも数分ぶんあります。歌ってみた1曲(4分)で約240クレジット消費なので、軽く触る用途なら登録だけで足ります。

著作権について:市販曲のステム分離音源を公の場に出す場合、JASRAC・NexTone への申請、原盤権の扱い(YouTube Content ID 等)が別途必要です。歌ってみた・歌枠は配信プラットフォームの包括契約に依存する部分が多いので、各プラットフォームの最新ガイドラインを必ず確認してください。


ステップ1:コミュニティノードをインストールする

n8n の画面から:

  1. Settings → Community Nodes を開く
  2. Install a community node をクリック
  3. パッケージ名 n8n-nodes-stemsplit を貼り付ける
  4. リスクの確認ダイアログに同意して Install

セルフホストで Docker を使っている場合は CLI でも入ります。

npm install n8n-nodes-stemsplit
# その後 n8n コンテナを再起動

n8n Cloud ではコミュニティノードがデフォルト無効のインスタンスもあります。Settings に Community Nodes メニューが出ない場合は、ワークスペース管理者に有効化を依頼してください。


ステップ2:StemSplit API 認証情報を作る

ノードを使うには StemSplit API 型のクレデンシャルを1つ作ります。

  1. n8n の Credentials から New → 検索バーで StemSplit API を選ぶ
  2. API Key 欄に sk_live_... を貼って Save
  3. Test ボタンを押すと、内部で GET /balance が走ってクレジット残高が返ってきます

Authorization: Bearer <key> を毎回 https://stemsplit.io/api/v1 に送る挙動なので、ノード単位で認証ヘッダを書き直す必要はありません。

キーが間違っていると 401 UNAUTHORIZED、クレジット不足だとジョブ送信時に 402 INSUFFICIENT_CREDITS が返ります。後者は Slack / Discord 通知に流しておくとバッチを静かに落とさずに済みます。


ステップ3:5つのオペレーション

ノードが提供するオペレーションは5種類です。歌ってみた・歌枠用途では基本 Separate Stems (Wait) を使い、バッチや並列処理では Separate Stems + Get Job の組み合わせを使います。

オペレーション 用途
Separate Stems (Wait for Completion) 同期処理。1曲投げて、完了まで待ってから presigned URL を返す
Separate Stems 投げっぱなし。ジョブIDだけ返ってくるので、別ワークフローでポーリングする
Get Job ジョブIDを指定して状態と出力URLを取得
List Jobs ジョブ履歴を PENDING / PROCESSING / COMPLETED / FAILED でフィルタしてページング
Get Balance 現在のクレジット残高を確認(バッチ前のチェック用)

Output Type パラメータで返ってくる URL が変わります。

Output Type 出力されるフィールド
VOCALS vocalsUrl
INSTRUMENTAL instrumentalUrl
BOTH(既定) vocalsUrl + instrumentalUrl
FOUR_STEMS vocalsUrl, drumsUrl, bassUrl, otherUrl
SIX_STEMS vocalsUrl, drumsUrl, bassUrl, pianoUrl, guitarUrl, otherUrlQuality: Best 必須)

歌ってみた向けのオフボーカル生成なら BOTH または INSTRUMENTAL、耳コピやドラム抜きのミックス案件なら FOUR_STEMS、ピアノ・ギターを別取りしたい場合は SIX_STEMS を選びます。

presigned URL の有効期限は ジョブ完了から 1 時間 です。長期保存したい場合は、n8n のフロー内で S3 / GCS / Drive に転送するノードを足してください。生成されたファイル本体も 14 日後にサーバ側から削除されます。


ステップ4:歌ってみたオフボーカル生成ワークフロー(3ノード)

実際のフローはこれだけです。

[Read Binary File: song.mp3]
  → [StemSplit: Separate Stems (Wait), Output Type: INSTRUMENTAL]
  → [HTTP Request: GET {{$json.instrumentalUrl}} → ファイル保存]

n8n の Workflows → Import from File / URL → Paste にそのまま貼れる JSON です。

{
  "name": "StemSplit Off-Vocal Generator",
  "nodes": [
    {
      "parameters": {
        "filePath": "/data/input/song.mp3"
      },
      "name": "Read Binary File",
      "type": "n8n-nodes-base.readBinaryFile",
      "typeVersion": 1,
      "position": [240, 300]
    },
    {
      "parameters": {
        "operation": "separateStemsWait",
        "inputSource": "binary",
        "binaryPropertyName": "data",
        "outputType": "INSTRUMENTAL",
        "quality": "BEST",
        "outputFormat": "WAV",
        "timeoutSeconds": 600,
        "pollIntervalSeconds": 5
      },
      "name": "StemSplit",
      "type": "n8n-nodes-stemsplit.stemSplit",
      "typeVersion": 1,
      "position": [480, 300],
      "credentials": {
        "stemSplitApi": "StemSplit account"
      }
    },
    {
      "parameters": {
        "url": "={{$json.instrumentalUrl}}",
        "options": { "response": { "response": { "responseFormat": "file" } } }
      },
      "name": "Download Instrumental",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [720, 300]
    }
  ],
  "connections": {
    "Read Binary File": { "main": [[{ "node": "StemSplit", "type": "main", "index": 0 }]] },
    "StemSplit":        { "main": [[{ "node": "Download Instrumental", "type": "main", "index": 0 }]] }
  }
}

ポイントは Separate Stems (Wait) ノードが内部でポーリングを回してくれていること。pollIntervalSecondstimeoutSeconds を typed パラメータとして持っているので、長尺曲(ライブ音源など)の場合は timeoutSeconds: 1800 などに上げれば OK です。失敗時はノードが例外を投げるので、n8n のエラー分岐ブランチがそのまま発火します。

歌ってみたなら、この後 Write Binary Fileoffvocal_<曲名>.wav として保存しておけば、Python 側のミックス処理(歌ってみた用のオフボーカル音源をPythonで自作する方法 からの続きの工程)にそのまま流せます。


ステップ5:VTuber 歌枠セトリ10曲を並列バッチ処理する

歌枠当日のセトリが10曲決まったとき、待ち時間を最小にしたいので Separate Stems(投げっぱなし) + Get Job(後追い) で並列に回します。1ワークフロー内でポーリングすると n8n のメモリに長時間居座るので、送信用と回収用で2つに分割するのが安全です。

# 送信ワークフロー(セトリ確定時に1回手動実行)
[Manual Trigger]
  → [Postgres: SELECT * FROM setlist WHERE prepared = false]
  → [StemSplit: Separate Stems, Input: URL, Output: INSTRUMENTAL]   ← ジョブIDが即返る
  → [Postgres: UPDATE setlist SET job_id = ..., status = 'SUBMITTED']

# 回収ワークフロー(30秒ごとのスケジュール実行)
[Schedule Trigger: every 30s]
  → [Postgres: SELECT * FROM setlist WHERE status = 'SUBMITTED']
  → [StemSplit: Get Job]
  → [IF: $json.status === 'COMPLETED']
      → true:
          → [HTTP Request: GET {{$json.instrumentalUrl}}]
          → [Write Binary File: /streaming/offvocals/{{$json.input.fileName}}_off.wav]
          → [Postgres: UPDATE setlist SET status = 'READY']
      → false: 何もしない(次回ループで再評価)

このパターンの良いところは、n8n の実行時間に依存せず、状態を全部 Postgres に置けること。配信PC が落ちても、回収ワークフローを再起動すれば「SUBMITTED のまま」のジョブを拾い直せます。

歌枠の本番中に新しい曲リクエストが入った場合は、送信ワークフローを Discord / Webhook トリガーで叩けるようにしておけば対応できます。ただし BEST 品質は4分曲で約30〜90秒かかるので、即興リクエストには FASTBALANCED を使う方が無難です。


バイナリではなく URL を渡したいとき

n8n のメモリに音源を読み込みたくない / Google Drive や Dropbox の公開URLをそのまま渡したいケースでは、Input Source: URL に切り替えるだけです。ファイルは StemSplit 側のサーバが直接フェッチします。

{
  "operation": "separateStemsWait",
  "inputSource": "url",
  "sourceUrl": "https://drive.google.com/uc?export=download&id=...",
  "outputType": "FOUR_STEMS",
  "quality": "BALANCED"
}

50 MB を超えるファイル(高ビットレートの長尺ライブ音源など)はリジェクトされるので、その場合は事前に ffmpeg -b:a 192k などで圧縮しておくのが手っ取り早いです。


出力フィールド一覧(Separate Stems (Wait) の場合)

ノードを通過した後の $json に乗ってくるフィールドは以下の通りです。下流ノードで ={{$json.vocalsUrl}} のように直接参照できるよう、フラットに展開済みです。

フィールド 説明
id ジョブID(後で Get Job から再取得するときに使う)
status COMPLETED(待機ありの場合は常にこれ)
progress 0〜100
creditsCharged 実際に消費したクレジット秒数
vocalsUrl, vocalsExpiresAt ボーカル presigned URL と有効期限
instrumentalUrl, instrumentalExpiresAt オフボーカル presigned URL と有効期限
drumsUrl, bassUrl, pianoUrl, guitarUrl, otherUrl 該当する Output Type のときだけ
input.fileName, input.durationSeconds, input.fileSizeBytes 入力ファイルのメタデータ
metadata リクエスト時に渡した任意の JSON(曲名・配信日・案件IDなどを乗せると便利)

metadata フィールドは StemSplit 側の DB にそのまま保存されるので、{ "song": "夜に駆ける", "stream_id": "20260601_utawaku" } のような業務 ID を埋めておくと、後から List Jobs で配信回ごとに絞れます。


既存の HTTP Request + Wait + IF 構成からの移行

すでに REST API 直叩きで作っている場合、移行は以下の入れ替えで済みます。

旧(5ノード) 新(1ノード)
HTTP Request: POST /jobs Separate Stems (Wait)Submit 部分(内部処理)
Wait 5s Poll Interval (Seconds) パラメータ
HTTP Request: GET /jobs/{id} Separate Stems (Wait)Poll 部分(内部処理)
IF: status === "COMPLETED" Timeout (Seconds) 経過で例外、それ以外は継続(内部処理)
Set: data.stems.vocals の抽出 フラットな vocalsUrl 等を直接参照

API のエンドポイントもキー形式も同じなので、過去の id でログを取っていても破綻しません。


まとめ

  • 歌ってみた・VTuber 歌枠でステム分離を n8n から叩くなら、n8n-nodes-stemsplit ノードの Separate Stems (Wait) だけで完結します
  • Output Type を切り替えるだけで vocals / drums / bass / piano / guitar / other / instrumental の presigned URL が一発で返ってきます
  • セトリ10曲の並列バッチは Separate Stems(投げっぱなし) + Get Job(回収)で、状態を Postgres に逃がす構成が安全です
  • presigned URL は1時間、ファイル本体は14日で消えるので、長期保存はフロー内で S3 等に流す前提で組みます

歌ってみたや配信のミックス工程は、人間がやらなくていい部分を n8n に押し付けて、人間は歌の練習や本番に集中する——というのがこの記事のゴールです。

参考リンク

関連 Qiita 記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?