0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで学ぶ音信号処理(エンベロープ)

Posted at

はじめ

音響信号処理において、**エンベロープ(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)

結果
image.png

image.png

0
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?