はじめ
音響信号処理において、**エンベロープ(envelope)は音の振幅の時間的変化を制御する重要な要素です。音そのものはサイン波などの高周波成分で構成されますが、その強弱や形(アタックや減衰)**はエンベロープによって表現されます。
たとえば、ピアノの音は打鍵直後に強く鳴り、すぐに音量が減衰していきます。一方、バイオリンの音はゆるやかに立ち上がり、弓を引く間は持続します。このような**「音のかたち」**を再現するために、リニア、指数関数、ADSR、ガウス型などのさまざまなエンベロープが使われます。
本記事では、音響用に使われる代表的な10種類のエンベロープ関数とその数式を一覧で紹介し、用途や特徴もあわせて解説します。
主なエンベロープの種類と数式一覧(音響用)
種類 | 説明 | 数式(時間 ( t )、最大時間 ( T )、初期振幅 ( A_0 )、減衰係数 αなど) |
---|---|---|
1. リニア(直線) | 単純な立ち上がり・減衰 | ( A(t) = A_0 \cdot (1 - t/T) )(減衰) または ( A(t) = A_0 \cdot (t/T) )(立ち上がり) |
2. 指数減衰 | ピアノなど自然な余韻 | ( A(t) = A_0 \cdot e^{-\alpha t} ) |
3. 指数立ち上がり | シンセのアタック表現 | ( A(t) = A_0 \cdot (1 - e^{-\alpha t}) ) |
4. ADSR(各フェーズで切替) | 楽器音制御の定番モデル | Attack: ( A(t) = \frac{t}{T_a} ) Decay: ( A(t) = 1 - (1 - S)\cdot \frac{t}{T_d} ) Sustain: ( A(t) = S ) Release: ( A(t) = S \cdot e^{-\alpha t} ) |
5. ガウス型エンベロープ | 短くて滑らかな音(例:打楽器) | ( A(t) = A_0 \cdot e^{-\left( \frac{t - \mu}{\sigma} \right)^2} ) |
6. サイン型エンベロープ | ゆるやかな立ち上がりと減衰 | ( A(t) = \sin\left( \frac{\pi t}{T} \right) ) |
7. 三角エンベロープ | 対称な立ち上がりと下り | ( A(t) = \frac{2A_0}{T} \cdot \min(t, T - t) ) |
8. 半周期コサイン | より柔らかなアタック・減衰 | ( A(t) = \frac{1 - \cos\left( \frac{\pi t}{T} \right)}{2} ) |
9. Hanning / Hann | ウィンドウ関数にも使用される | ( A(t) = 0.5 \cdot \left(1 - \cos\left( \frac{2\pi t}{T} \right) \right) ) |
10. Blackman | 滑らかに減衰 | ( A(t) = 0.42 - 0.5\cos\left( \frac{2\pi t}{T} \right) + 0.08\cos\left( \frac{4\pi t}{T} \right) ) |
使い分け例
用途 | 適したエンベロープ |
---|---|
ピアノ・打楽器 | 指数減衰, ガウス, 三角 |
シンセサイザー | ADSR, 指数立ち上がり, 半周期コサイン |
音のブレンド・フェードイン | サイン型, Hanning |
残響シミュレーション | 指数減衰, Blackman |
Pythonでこれらのエンベロープを実装・比較
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import Audio, display
# --- パラメータ設定 / Parameter settings ---
duration = 2.0 # 音の長さ / Duration (seconds)
sample_rate = 44100 # サンプリングレート / Sample rate (Hz)
frequency = 261.63 # 周波数 C4(ド)/ Frequency of C4
amplitude = 1.0 # 振幅 / Amplitude
time = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
# --- 各エンベロープ関数の定義 / Define envelope functions ---
def linear_envelope(t, T):
return amplitude * (1 - t / T)
def exponential_decay(t, alpha=3.0):
return amplitude * np.exp(-alpha * t)
def exponential_rise(t, alpha=5.0):
return amplitude * (1 - np.exp(-alpha * t))
def adsr_envelope(t, attack=0.1, decay=0.2, sustain_level=0.6, sustain=1.0, release=0.7):
total = attack + decay + sustain + release
env = np.zeros_like(t)
for i, ti in enumerate(t):
if ti < attack:
env[i] = ti / attack
elif ti < attack + decay:
env[i] = 1 - (1 - sustain_level) * ((ti - attack) / decay)
elif ti < attack + decay + sustain:
env[i] = sustain_level
elif ti < total:
env[i] = sustain_level * np.exp(-5 * (ti - (attack + decay + sustain)))
else:
env[i] = 0
return env
def gaussian_envelope(t, mu, sigma):
return amplitude * np.exp(-((t - mu) / sigma)**2)
def sine_envelope(t, T):
return np.sin(np.pi * t / T)
def triangle_envelope(t, T):
return (2 * amplitude / T) * np.minimum(t, T - t)
def half_cosine_envelope(t, T):
return (1 - np.cos(np.pi * t / T)) / 2
def hanning_envelope(t, T):
return 0.5 * (1 - np.cos(2 * np.pi * t / T))
def blackman_envelope(t, T):
return 0.42 - 0.5 * np.cos(2 * np.pi * t / T) + 0.08 * np.cos(4 * np.pi * t / T)
# --- 各エンベロープの波形生成 / Generate waveform with envelopes ---
envelopes = {
"Linear": linear_envelope(time, duration),
"Exponential Decay": exponential_decay(time),
"Exponential Rise": exponential_rise(time),
"ADSR": adsr_envelope(time),
"Gaussian": gaussian_envelope(time, duration/2, 0.2),
"Sine": sine_envelope(time, duration),
"Triangle": triangle_envelope(time, duration),
"Half Cosine": half_cosine_envelope(time, duration),
"Hanning": hanning_envelope(time, duration),
"Blackman": blackman_envelope(time, duration),
}
# --- プロット / Plot all envelopes ---
plt.figure(figsize=(14, 10))
for i, (name, env) in enumerate(envelopes.items()):
plt.subplot(5, 2, i + 1)
plt.plot(time, env)
plt.title(name)
plt.xlabel("Time (s)")
plt.ylabel("Amplitude")
plt.grid(True)
plt.tight_layout()
plt.show()
# --- サイン波に任意のエンベロープを適用して音を生成 / Apply one envelope to sine wave ---
selected_envelope = envelopes["Exponential Decay"] # 例: 指数減衰 / Example: exponential decay
sine_wave = selected_envelope * np.sin(2 * np.pi * frequency * time)
from IPython.display import Audio, display
# --- すべてのエンベロープでサイン波を生成して再生 / Play sine wave for all envelopes ---
audios = {}
for name, env in envelopes.items():
wave = env * np.sin(2 * np.pi * frequency * time)
audios[name] = Audio(wave, rate=sample_rate)
# --- 再生オブジェクトを表示 / Display all audio objects ---
for name, audio in audios.items():
print(f"🎵 {name}")
display(audio)