오버드라이브 계열은 LTI시스템이 아니기 때문에 전달함수로 구현할수없음을 알아냈다.
그래서 LTI 시스템인 simple delay를 이용하여 전달함수를 만들어 보려고 한다.
딜레이는 메아리처럼 일정한 시간적 간격을 가지고 짧게 소리를 되풀이 하는 이펙터이다.

꼴의 FIR 시스템이라고 볼수있다.
이는 z-Transform으로 아래와 같이 표현 할 수 있다.

GPT를 활용하여 간단한 딜레이 이펙터를 만들었다.
import numpy as np
from scipy.io import wavfile
def read_wav_mono(path: str):
fs, x = wavfile.read(path)
# stereo -> mono
if x.ndim == 2:
x = x.mean(axis=1)
# int -> float32 [-1, 1]
if np.issubdtype(x.dtype, np.integer):
max_int = np.iinfo(x.dtype).max
x = x.astype(np.float32) / max_int
else:
x = x.astype(np.float32)
return fs, x
def write_wav(path: str, fs: int, x: np.ndarray):
x = np.asarray(x, dtype=np.float32)
# clipping 방지
peak = np.max(np.abs(x))
if peak > 1.0:
x = x / peak * 0.98
wavfile.write(path, fs, (x * 32767).astype(np.int16))
def bpm_to_delay_samples(fs: int, bpm: float, note: str = "quarter") -> int:
"""
BPM과 음표 단위로 delay time 계산
note options:
- "whole"
- "half"
- "quarter"
- "eighth"
- "sixteenth"
- "dotted_eighth"
- "triplet_eighth"
"""
quarter_sec = 60.0 / bpm
note_map = {
"whole": 4.0,
"half": 2.0,
"quarter": 1.0,
"eighth": 0.5,
"sixteenth": 0.25,
"dotted_eighth": 0.75,
"triplet_eighth": 1.0 / 3.0,
}
if note not in note_map:
raise ValueError(f"Unsupported note: {note}")
delay_sec = quarter_sec * note_map[note]
delay_samples = int(round(delay_sec * fs))
return delay_samples
def apply_guitar_delay_lti(
x: np.ndarray,
fs: int,
bpm: float,
note: str = "dotted_eighth",
mix: float = 0.35,
feedback: float = 0.40,
repeats: int = 6,
dry_gain: float = 1.0,
):
"""
일렉기타용 LTI delay
y[n] = dry_gain*x[n] + sum_{k=1..repeats} mix*(feedback^(k-1))*x[n-kD]
- 고정 계수만 사용 -> LTI
- BPM 기반 딜레이 시간
- 멀티탭 echo 형태
Args:
x: mono input
fs: sample rate
bpm: tempo
note: delay division
mix: wet level
feedback: repeat attenuation (0~1)
repeats: number of echoes
dry_gain: direct signal gain
"""
if not (0.0 <= mix <= 1.0):
raise ValueError("mix must be between 0 and 1")
if not (0.0 <= feedback < 1.0):
raise ValueError("feedback must be in [0, 1)")
if repeats < 1:
raise ValueError("repeats must be >= 1")
delay_samples = bpm_to_delay_samples(fs, bpm, note)
# 출력 길이 확보
out_len = len(x) + delay_samples * repeats
y = np.zeros(out_len, dtype=np.float32)
# dry
y[:len(x)] += dry_gain * x
# echoes
for k in range(1, repeats + 1):
gain = mix * (feedback ** (k - 1))
start = k * delay_samples
end = start + len(x)
y[start:end] += gain * x
return y, delay_samples
if __name__ == "__main__":
input_path = "DATA/clean1.wav"
output_path = "OUTPUT/delay_clean1.wav"
# ===== 사용자 설정 =====
bpm = 90.0
note = "eighth" # "quarter", "eighth", "dotted_eighth" 추천
mix = 0.32 # wet 양
feedback = 0.45 # 반복 감쇠
repeats = 7 # 반복 횟수
dry_gain = 1.0
# ======================
fs, x = read_wav_mono(input_path)
y, delay_samples = apply_guitar_delay_lti(
x=x,
fs=fs,
bpm=bpm,
note=note,
mix=mix,
feedback=feedback,
repeats=repeats,
dry_gain=dry_gain,
)
write_wav(output_path, fs, y)
delay_ms = 1000.0 * delay_samples / fs
print(f"Saved: {output_path}")
print(f"BPM: {bpm}")
print(f"Note: {note}")
print(f"Delay: {delay_samples} samples ({delay_ms:.2f} ms)")
clean1.wav
0.85MB
delay_clean1.wav
1.04MB
두번째 파일을 들어보면 첫번째 파일에서 딜레이가 추가된것을 볼수있다.
이번에도
sine
impulse
gaussian
clean
에 적용해서 전달함수를 만들어 보겠다.
'이직로그 > DSP' 카테고리의 다른 글
| Audio DSP: 일렉기타 이펙터 만들기 5 - 결과물 비교하기 (0) | 2026.05.11 |
|---|---|
| Audio DSP: 일렉기타 이펙터 만들기 3 - 다양한 데이터 셋으로 전달함수 만들기 (1) | 2026.04.15 |
| Audio DSP: 일렉기타 이펙터 만들기 2 - wet, dry 신호 분석 (0) | 2026.03.27 |
| Audio DSP 프로젝트: 이펙터 시뮬레이터 만들기 (0) | 2026.03.27 |
| Audio DSP: 일렉기타 이펙터 만들기 1 (1) | 2026.03.17 |