テンポ変更
テンポの変更やバッファリング状態の監視パターンを紹介します。
使用モジュール: play, stretcher
テンポ変更デモ
WSOLA ベースの pitch 保持 time-stretch 機能のデモです。テンポスライダーでリアルタイムに再生速度を変更できます。
Sound Source
Pitch 保持の time-stretch を体験するには、長めの音源を使用してください。
または
波形
0:00.0 0:00.0
テンポ変更
Stretcher Engine Buffering...
チャンクバッファリングデモ
WSOLA stretcher エンジンのチャンクバッファリングの仕組みを観察するデモです。各チャンクの処理状態やイベントログをリアルタイムに確認できます。
Sound Source
チャンク分割の仕組みを確認するには、長めの音源を使用してください。
または
波形
0:00.0 0:00.0
チャンクバッファリング
チャンク状態
未処理
キュー済み
変換中
再生可能
解放済み
再生位置
Stretcher Engine Buffering...
イベントログ
コード例
1. Pitch 保存テンポ変更
preservePitch のデフォルトは true なので、通常の play() 呼び出しでピッチが保存されます。通常速度変更(ピッチも変わる)には preservePitch: false を明示します。
import { WaaPlayer } from "waa-play";
const waa = new WaaPlayer();await waa.ensureRunning();const buffer = await waa.load("/audio/track.mp3");
// Change tempo while preserving pitch (default behavior)const playback = waa.play(buffer, { playbackRate: 0.8 });
// Change tempo during playbackplayback.setPlaybackRate(1.2); // 1.2x speed, pitch maintained
// To change pitch along with tempo, set preservePitch: falseconst playback2 = waa.play(buffer, { playbackRate: 1.5, preservePitch: false,});WSOLA アルゴリズムにより、ピッチを変えずにテンポを変更できます。preservePitch: true(デフォルト)で WSOLA ベースの time-stretch が有効になります。
関数 API 版
import { createContext, ensureRunning } from "waa-play/context";import { loadBuffer } from "waa-play/buffer";import { play } from "waa-play/play";
const ctx = createContext();await ensureRunning(ctx);const buffer = await loadBuffer(ctx, "/audio/track.mp3");
// Change tempo while preserving pitch (default behavior)const playback = play(ctx, buffer, { playbackRate: 0.8 });
// Change tempo during playbackplayback.setPlaybackRate(1.2);
// To change pitch along with tempo, set preservePitch: falseconst playback2 = play(ctx, buffer, { playbackRate: 1.5, preservePitch: false,});2. Buffering 状態の監視
WSOLA 処理は非同期で行われるため、テンポ変更時に buffering が発生する可能性があります。
const playback = waa.play(buffer, { playbackRate: 0.8 });
// Monitor buffering startplayback.on("buffering", ({ reason }) => { console.log(`Buffering... (reason: ${reason})`); // Show loading UI});
// Monitor buffering completionplayback.on("buffered", ({ stallDuration }) => { console.log(`Buffering complete (${stallDuration.toFixed(0)}ms)`); // Hide loading UI});
// Check stretcher state via snapshotconst snapshot = waa.getSnapshot(playback);if (snapshot.stretcher) { console.log(`Tempo: ${snapshot.stretcher.tempo}`); console.log(`Buffer health: ${snapshot.stretcher.bufferHealth}`); console.log(`Converting: ${snapshot.stretcher.converting}`); console.log(`Conversion progress: ${(snapshot.stretcher.conversionProgress * 100).toFixed(0)}%`);}buffering イベントの reason は "initial" | "seek" | "tempo-change" | "underrun" のいずれかです。getSnapshot() の stretcher フィールドで詳細な状態を取得できます。
関数 API 版
import { getSnapshot } from "waa-play/adapters";
const playback = play(ctx, buffer, { playbackRate: 0.8 });
playback.on("buffering", ({ reason }) => { console.log(`Buffering... (reason: ${reason})`);});
playback.on("buffered", ({ stallDuration }) => { console.log(`Buffering complete (${stallDuration.toFixed(0)}ms)`);});
const snapshot = getSnapshot(playback);if (snapshot.stretcher) { console.log(`Tempo: ${snapshot.stretcher.tempo}`); console.log(`Buffer health: ${snapshot.stretcher.bufferHealth}`); console.log(`Converting: ${snapshot.stretcher.converting}`); console.log(`Conversion progress: ${(snapshot.stretcher.conversionProgress * 100).toFixed(0)}%`);}