編集の基礎
ここでいう編集は、1 つのパートの音そのもの、つまりピッチ、長さ、声のキャラクターを変えることです。
トラックを測定するだけで手を加えない解析とも、複数のパートのバランスを取るミキシングとも別の工程です。
このページは、編集 DSP ガイドを読む前に必要な言葉を定義します。終わり近くに、2 つの主な編集を呼び出しとして示す短い例があります。
編集の位置
制作の流れは、個々のパートを編集し(タイミング修正、ノートの音程調整、声質変更)、それらをミックスし、仕上がったステレオファイルを配信向けにマスタリングする、という順です。編集はパート単位の修復と整形の工程です。控えめな編集はパートを自然に保ち、大胆な編集はクリエイティブな効果になります。
ピッチと時間は独立している
テープを速く回すと、音楽は速くかつ高くなります。2 つは結びついているからです。現代の編集 DSP の要点は、この 2 つを分離し、一方を変えてももう一方を巻き込まないようにすることです。
- タイムストレッチはピッチを変えずに長さを変えます。ここで
rateは再生速度の倍率です。rateが1.0より大きいと速く再生されるためクリップは短くなり、1.0より小さいと遅く再生されるため長くなります。 - ピッチシフトは長さを変えずにピッチを変えます。
これをきれいに行うのは難しい処理です。アルゴリズムは各ノートの周波数を保ったまま、時間を生み出したり取り除いたりしなければならず、大きな変更は必ずアーティファクト(にじみ、位相っぽさ、ロボット的な音)を残します。小さな変更なら音質の変化はほとんど聞き取れません。
半音とセント
音楽のピッチは半音で測ります。半音は、ピアノの鍵盤で隣り合う鍵の間隔です。12 半音で 1 オクターブになり、1 オクターブ上がると周波数は倍になります(A4 = 440 Hz、A5 = 880 Hz)。
つまり semitones = 12 は 1 オクターブ上、-12 は 1 オクターブ下、7 は完全 5 度です。
セントは半音の 1/100 で、微調整に使います。多くのリスナーは、およそ ±5〜10 セントを超えるとピッチのずれに気づき始めます。
MIDI ノート番号
関数が MIDI ノート番号(pitchCorrectToMidi の currentMidi や targetMidi など)を求めているとき、渡すのは整数 1 つが 1 半音にあたるインデックスです(小数も可)。基準になる値を 2 つ覚えておくと便利です。
- A4 = 69 = 440 Hz: チューニング基準。
- C4 = 60: 中央のド(ミドル C)。
オクターブごとに 12 を足すので、C5 = 72、C3 = 48 です。よく使う目標音をいくつか挙げます。
| 音名 | MIDI | 周波数 |
|---|---|---|
| C3 | 48 | 130.81 Hz |
| C4(中央のド) | 60 | 261.63 Hz |
| E4 | 64 | 329.63 Hz |
| G4 | 67 | 392.00 Hz |
| A4(チューニング基準) | 69 | 440.00 Hz |
| C5 | 72 | 523.25 Hz |
手計算なら midi = 69 + 12 · log2(freq / 440) と freq = 440 · 2^((midi − 69) / 12) で変換できます。68.7 のような小数の MIDI 値は、A4 より少し低いピッチを表しているだけです。歌い手がぴったり音に乗ることは稀なので、測定したピッチをそのまま current に、整数を target に渡せるのが便利です。
フォルマント: ピッチの独立した相棒
フォルマントは、固定された周波数帯に現れるエネルギーのピークです。声では声道の共鳴から生まれ、楽器では胴や管の共鳴から生まれます。
フォルマントは母音と、声の太さや明るさといったキャラクターを決めます。ピッチとは別物で、同じ人が違う音高で歌っても、母音らしさや声のキャラクターは同じ声道の共鳴から生まれます。
そのため、声質ツールではピッチとフォルマントを分けて扱います。
| コントロール | 変わるもの | 聞こえ方 |
|---|---|---|
| ピッチ | 音楽的な音高 | 同じ声が高く/低く歌っているように聞こえる |
| フォルマント | 声のキャラクター | 同じ音高のまま、小さく明るい声/大きく暗い声に近づく |
両方を一緒に大きく動かすと、おなじみの不自然な「チップマンク」効果になります。voiceChange では、formantFactor は既定でピッチシフトの後に適用されます(formantMode: 'relative')。formantMode: 'absolute' にすると入力を基準にした値になり、ピッチシフトにかかわらず 1 でフォルマントが元の位置に留まります。
サンプルと秒
区間に作用する編集関数(ノートストレッチなど)は、サンプル位置を取ります。サンプル位置は正確でずれないからです。多くの関数は、同じ位置を *Sec という名前(onsetSec、offsetSec、startSec、endSec、paddingSec)で秒指定することもでき、呼び出しのサンプルレートで換算されます。どちらか一方の指定だけを使い、両方は渡せません。換算は samples = round(seconds × sampleRate) です。48 kHz なら 0.25 秒はサンプル 12000 です。サンプルとサンプルレートが何かは オーディオ基礎 を参照してください。
libsonare で試す
タイムストレッチとピッチシフトは、それぞれ 1 回の呼び出しです。rate が 0.5 なら半分の速さで再生されるので、ピッチはそのまま、長さは 2 倍になります。semitones: 12 は、長さを保ったままピッチを 1 オクターブ上げます。
import { init, timeStretch, pitchShift } from '@libraz/libsonare';
await init();
const slower = timeStretch(samples, sampleRate, 0.5); // 長さは 2 倍、ピッチは同じ
const higher = pitchShift(samples, sampleRate, 12); // 1 オクターブ上、長さは同じimport libsonare as sonare
slower = sonare.time_stretch(samples, sample_rate, 0.5) # 長さは 2 倍、ピッチは同じ
higher = sonare.pitch_shift(samples, sample_rate, 12) # 1 オクターブ上、長さは同じsonare time-stretch take.wav --rate 0.5 -o slower.wav
sonare pitch-shift take.wav --semitones 12 -o higher.wavlibsonare が編集 DSP をどう実装するか
libsonare の編集関数は、解析やマスタリングと同じ C++ DSP コアの上にあります。違いは、信号を測るのではなく書き換える点です。
| 関数ファミリー | 実装の考え方 | 初学者向けの要点 |
|---|---|---|
| タイムストレッチ / ピッチシフト | フェーズボコーダー(短い重なり合うスペクトルフレームから信号を組み立て直す方式)とリサンプリングを組み合わせる | 長さと音高を別々に動かせるが、大きな変更ではアーティファクトが出る |
voiceChange | 倍音のピッチとは別にスペクトル包絡を動かす | 目標音を保ったまま声のキャラクターを動かせる |
pitchCorrectToMidi | 呼び出し側が渡した現在 MIDI ノートから目標 MIDI ノートへ寄せる | 先に pitchYin、pitchPyin、または独自検出器で現在ピッチを推定する |
autoTune | モノフォニックの録音を、検出したキー(key: 'detect')または指定したキーの音へスナップする。strength で効き具合を調整 | 補正後のサンプルと、使ったキーを返す |
noteStretch | サンプル位置で指定した正確な区間を処理する | onsetSample/offsetSample か、onsetSec/offsetSec で渡す |