歌ってみたのミックス前処理や、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 の画面から:
- Settings → Community Nodes を開く
- Install a community node をクリック
- パッケージ名
n8n-nodes-stemsplitを貼り付ける - リスクの確認ダイアログに同意して Install
セルフホストで Docker を使っている場合は CLI でも入ります。
npm install n8n-nodes-stemsplit
# その後 n8n コンテナを再起動
n8n Cloud ではコミュニティノードがデフォルト無効のインスタンスもあります。Settings に Community Nodes メニューが出ない場合は、ワークスペース管理者に有効化を依頼してください。
ステップ2:StemSplit API 認証情報を作る
ノードを使うには StemSplit API 型のクレデンシャルを1つ作ります。
- n8n の Credentials から New → 検索バーで
StemSplit APIを選ぶ -
API Key欄にsk_live_...を貼って Save -
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, otherUrl(Quality: 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) ノードが内部でポーリングを回してくれていること。pollIntervalSeconds と timeoutSeconds を typed パラメータとして持っているので、長尺曲(ライブ音源など)の場合は timeoutSeconds: 1800 などに上げれば OK です。失敗時はノードが例外を投げるので、n8n のエラー分岐ブランチがそのまま発火します。
歌ってみたなら、この後 Write Binary File で offvocal_<曲名>.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秒かかるので、即興リクエストには FAST か BALANCED を使う方が無難です。
バイナリではなく 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 記事
- VTuberの歌枠配信用カラオケ音源を5分で量産するPythonスクリプト — 配信現場のセトリ準備フロー
- 歌ってみた用のオフボーカル音源をPythonで自作する方法 — Demucs ローカル運用編
- 自分専用カラオケ動画をPythonで作る:AI音源分離 × Whisper × 歌詞同期 — 歌詞同期までやりたい場合の応用
- yt-dlpでYouTubeから音声を抽出してAI音源分離する完全ガイド — n8n の HTTP Request 部分を yt-dlp に置き換えたい場合