heybaeheef commited on
Commit
a6c03bb
ยท
verified ยท
1 Parent(s): 09b0f26

Upload effect_chain.py

Browse files
Files changed (1) hide show
  1. audio_processing/effect_chain.py +185 -0
audio_processing/effect_chain.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Effect Chain - Pedalboard ๊ธฐ๋ฐ˜ ์˜ค๋””์˜ค ์ดํŽ™ํŠธ ์ฒ˜๋ฆฌ
3
+ =================================================
4
+ V2: ํ•™์Šต ๋ฐ์ดํ„ฐ ํŒŒ๋ผ๋ฏธํ„ฐ ํ‚ค์™€ ํ˜ธํ™˜์„ฑ ๊ฐœ์„ 
5
+ """
6
+
7
+ import numpy as np
8
+ import soundfile as sf
9
+ from typing import Dict, List, Optional
10
+ from pedalboard import (
11
+ Pedalboard,
12
+ Compressor,
13
+ Gain,
14
+ HighShelfFilter,
15
+ LowShelfFilter,
16
+ PeakFilter,
17
+ Delay,
18
+ Reverb,
19
+ Distortion,
20
+ Limiter
21
+ )
22
+
23
+
24
+ class EffectChain:
25
+ """Pedalboard ๊ธฐ๋ฐ˜ ์ดํŽ™ํŠธ ์ฒด์ธ"""
26
+
27
+ def __init__(self, sample_rate: int = 44100):
28
+ self.sample_rate = sample_rate
29
+
30
+ self.available_effects = [
31
+ "eq_peak1", "eq_peak2",
32
+ "eq_lowshelf", "eq_highshelf",
33
+ "distortion", "delay", "compressor",
34
+ "reverb", "limiter"
35
+ ]
36
+
37
+ def get_available_effects(self) -> List[str]:
38
+ """์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ดํŽ™ํŠธ ๋ชฉ๋ก"""
39
+ return self.available_effects
40
+
41
+ def _get_param(self, params: Dict[str, float], *keys, default=0.0) -> float:
42
+ """
43
+ ์—ฌ๋Ÿฌ ํ‚ค ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ๋ฐ˜ํ™˜ (ํ˜ธํ™˜์„ฑ ์ฒ˜๋ฆฌ)
44
+ ์˜ˆ: 'eq_peak1.params.Q' ๋˜๋Š” 'eq_peak1.params.q' ๋‘˜ ๋‹ค ์ง€์›
45
+ """
46
+ for key in keys:
47
+ if key in params:
48
+ return params[key]
49
+ return default
50
+
51
+ def _build_pedalboard(self, params: Dict[str, float]) -> Pedalboard:
52
+ """ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ Pedalboard ๊ตฌ์„ฑ"""
53
+
54
+ effects = []
55
+
56
+ # Compressor (ํ•ญ์ƒ ์ ์šฉ)
57
+ effects.append(Compressor(
58
+ threshold_db=-18.0,
59
+ ratio=2.0,
60
+ attack_ms=10.0,
61
+ release_ms=100.0
62
+ ))
63
+
64
+ # EQ Peak 1 (Q/q ๋‘˜ ๋‹ค ์ง€์›)
65
+ freq1 = self._get_param(params, "eq_peak1.params.freq", default=1000.0)
66
+ gain1 = self._get_param(params, "eq_peak1.params.gain", default=0.0)
67
+ q1 = self._get_param(params, "eq_peak1.params.Q", "eq_peak1.params.q", default=1.0)
68
+ if abs(gain1) > 0.1:
69
+ effects.append(PeakFilter(
70
+ cutoff_frequency_hz=max(20, min(20000, freq1)),
71
+ gain_db=max(-12, min(12, gain1)),
72
+ q=max(0.1, min(10, q1))
73
+ ))
74
+
75
+ # EQ Peak 2 (Q/q ๋‘˜ ๋‹ค ์ง€์›)
76
+ freq2 = self._get_param(params, "eq_peak2.params.freq", default=4000.0)
77
+ gain2 = self._get_param(params, "eq_peak2.params.gain", default=0.0)
78
+ q2 = self._get_param(params, "eq_peak2.params.Q", "eq_peak2.params.q", default=1.0)
79
+ if abs(gain2) > 0.1:
80
+ effects.append(PeakFilter(
81
+ cutoff_frequency_hz=max(20, min(20000, freq2)),
82
+ gain_db=max(-12, min(12, gain2)),
83
+ q=max(0.1, min(10, q2))
84
+ ))
85
+
86
+ # Low Shelf
87
+ freq_low = self._get_param(params, "eq_lowshelf.params.freq", default=200.0)
88
+ gain_low = self._get_param(params, "eq_lowshelf.params.gain", default=0.0)
89
+ if abs(gain_low) > 0.1:
90
+ effects.append(LowShelfFilter(
91
+ cutoff_frequency_hz=max(20, min(2000, freq_low)),
92
+ gain_db=max(-12, min(12, gain_low)),
93
+ q=0.707
94
+ ))
95
+
96
+ # High Shelf
97
+ freq_high = self._get_param(params, "eq_highshelf.params.freq", default=8000.0)
98
+ gain_high = self._get_param(params, "eq_highshelf.params.gain", default=0.0)
99
+ if abs(gain_high) > 0.1:
100
+ effects.append(HighShelfFilter(
101
+ cutoff_frequency_hz=max(1000, min(20000, freq_high)),
102
+ gain_db=max(-12, min(12, gain_high)),
103
+ q=0.707
104
+ ))
105
+
106
+ # Distortion
107
+ dist_amount = self._get_param(params, "distortion_amount", default=0.0)
108
+ if dist_amount > 0.01:
109
+ # ํ•™์Šต ๋ฐ์ดํ„ฐ๋Š” sigmoid ํ›„ 0.1 ๊ณฑํ•˜๋ฏ€๋กœ ์ตœ๋Œ€ 0.1
110
+ # ์—ฌ๊ธฐ์„œ๋Š” drive_db๋กœ ๋ณ€ํ™˜ (0~20dB ๋ฒ”์œ„)
111
+ effects.append(Distortion(
112
+ drive_db=max(0, min(20, dist_amount * 100))
113
+ ))
114
+
115
+ # Delay
116
+ delay_time = self._get_param(params, "delay.delay_time", default=0.02)
117
+ delay_feedback = self._get_param(params, "delay.feedback", default=0.3)
118
+ delay_mix = self._get_param(params, "delay.mix", default=0.2)
119
+ if delay_mix > 0.01:
120
+ effects.append(Delay(
121
+ delay_seconds=max(0.01, min(1.0, delay_time)),
122
+ feedback=max(0.0, min(0.9, delay_feedback)),
123
+ mix=max(0.0, min(1.0, delay_mix))
124
+ ))
125
+
126
+ # Limiter (ํ•ญ์ƒ ๋งˆ์ง€๋ง‰์—)
127
+ effects.append(Limiter(threshold_db=-1.0))
128
+
129
+ return Pedalboard(effects)
130
+
131
+ def process(
132
+ self,
133
+ input_path: str,
134
+ output_path: str,
135
+ parameters: Dict[str, float]
136
+ ) -> bool:
137
+ """์˜ค๋””์˜ค ํŒŒ์ผ ์ฒ˜๋ฆฌ"""
138
+ try:
139
+ # ์˜ค๋””์˜ค ๋กœ๋“œ
140
+ audio, sr = sf.read(input_path)
141
+
142
+ # ๋ชจ๋…ธ/์Šคํ…Œ๋ ˆ์˜ค ์ฒ˜๋ฆฌ
143
+ if len(audio.shape) == 1:
144
+ audio = audio.reshape(-1, 1)
145
+
146
+ # float32๋กœ ๋ณ€ํ™˜
147
+ audio = audio.astype(np.float32)
148
+
149
+ # Pedalboard ๊ตฌ์„ฑ
150
+ board = self._build_pedalboard(parameters)
151
+
152
+ # ์ฒ˜๋ฆฌ
153
+ processed = board(audio, sr)
154
+
155
+ # Wet/Dry ๋ฏน์Šค (final_wet_mix ํŒŒ๋ผ๋ฏธํ„ฐ ์‚ฌ์šฉ)
156
+ wet_mix = self._get_param(parameters, "final_wet_mix", default=0.5)
157
+ wet_mix = max(0.0, min(1.0, wet_mix))
158
+
159
+ # ๊ธธ์ด ๋งž์ถ”๊ธฐ
160
+ min_len = min(len(audio), len(processed))
161
+ output = audio[:min_len] * (1 - wet_mix) + processed[:min_len] * wet_mix
162
+
163
+ # ํด๋ฆฌํ•‘ ๋ฐฉ์ง€
164
+ output = np.clip(output, -1.0, 1.0)
165
+
166
+ # ์ €์žฅ
167
+ sf.write(output_path, output, sr)
168
+
169
+ print(f"[EffectChain] โœ… ์ฒ˜๋ฆฌ ์™„๋ฃŒ: {output_path}")
170
+ print(f"[EffectChain] ์ ์šฉ๋œ ํŒŒ๋ผ๋ฏธํ„ฐ:")
171
+ print(f" - EQ Peak1 Gain: {self._get_param(parameters, 'eq_peak1.params.gain'):.2f} dB")
172
+ print(f" - EQ Peak2 Gain: {self._get_param(parameters, 'eq_peak2.params.gain'):.2f} dB")
173
+ print(f" - Low Shelf Gain: {self._get_param(parameters, 'eq_lowshelf.params.gain'):.2f} dB")
174
+ print(f" - High Shelf Gain: {self._get_param(parameters, 'eq_highshelf.params.gain'):.2f} dB")
175
+ print(f" - Distortion: {self._get_param(parameters, 'distortion_amount'):.3f}")
176
+ print(f" - Delay Mix: {self._get_param(parameters, 'delay.mix'):.2f}")
177
+ print(f" - Wet Mix: {wet_mix:.2f}")
178
+
179
+ return True
180
+
181
+ except Exception as e:
182
+ print(f"[EffectChain] โŒ ์ฒ˜๋ฆฌ ์‹คํŒจ: {e}")
183
+ import traceback
184
+ traceback.print_exc()
185
+ raise e