Gamahea commited on
Commit
309dea0
·
verified ·
1 Parent(s): 49b3d36

Fix mastering presets syntax error and add preset description updates

Browse files
Files changed (1) hide show
  1. backend/services/mastering_service.py +661 -666
backend/services/mastering_service.py CHANGED
@@ -1,666 +1,661 @@
1
- """
2
- Audio mastering service with industry-standard presets using Pedalboard
3
- """
4
- import os
5
- import logging
6
- import numpy as np
7
- from pathlib import Path
8
- from typing import Dict, List, Optional
9
- import soundfile as sf
10
- from pedalboard import (
11
- Pedalboard,
12
- Compressor,
13
- Limiter,
14
- Gain,
15
- HighpassFilter,
16
- LowpassFilter,
17
- PeakFilter,
18
- LowShelfFilter,
19
- HighShelfFilter,
20
- Reverb,
21
- Chorus,
22
- Delay
23
- )
24
-
25
- logger = logging.getLogger(__name__)
26
-
27
- class MasteringPreset:
28
- """Mastering preset configuration"""
29
-
30
- def __init__(self, name: str, description: str, chain: List):
31
- self.name = name
32
- self.description = description
33
- self.chain = chain
34
-
35
- class MasteringService:
36
- """Audio mastering and EQ service"""
37
-
38
- # Industry-standard mastering presets
39
- PRESETS = {
40
- # Clean/Transparent Presets
41
- "clean_master": MasteringPreset(
42
- "Clean Master",
43
- "Transparent mastering with gentle compression",
44
- [
45
- HighpassFilter(cutoff_frequency_hz=30),
46
- PeakFilter(cutoff_frequency_hz=100, gain_db=-1, q=0.7),
47
- PeakFilter(cutoff_frequency_hz=3000, gain_db=0.5, q=1.0),
48
- PeakFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7),
49
- Compressor(threshold_db=-12, ratio=2.0, attack_ms=5, release_ms=100),
50
- Limiter(threshold_db=-1.0, release_ms=100)
51
- ]
52
- ),
53
-
54
- "subtle_warmth": MasteringPreset(
55
- "Subtle Warmth",
56
- "Gentle low-end enhancement with smooth highs",
57
- [
58
- HighpassFilter(cutoff_frequency_hz=25),
59
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.5, q=0.7),
60
- PeakFilter(cutoff_frequency_hz=200, gain_db=0.8, q=0.5),
61
- PeakFilter(cutoff_frequency_hz=8000, gain_db=-0.5, q=1.0),
62
- HighShelfFilter(cutoff_frequency_hz=12000, gain_db=1.0, q=0.7),
63
- Compressor(threshold_db=-15, ratio=2.5, attack_ms=10, release_ms=150),
64
- Limiter(threshold_db=-0.5, release_ms=100)
65
- ]
66
- ),
67
-
68
- # Pop/Commercial Presets
69
- "modern_pop": MasteringPreset(
70
- "Modern Pop",
71
- "Radio-ready pop sound with punchy compression",
72
- [
73
- HighpassFilter(cutoff_frequency_hz=35),
74
- PeakFilter(cutoff_frequency_hz=80, gain_db=-1.5, q=0.8),
75
- LowShelfFilter(cutoff_frequency_hz=120, gain_db=2.0, q=0.7),
76
- PeakFilter(cutoff_frequency_hz=2500, gain_db=1.5, q=1.2),
77
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=0.7),
78
- Compressor(threshold_db=-10, ratio=4.0, attack_ms=3, release_ms=80),
79
- Limiter(threshold_db=-0.3, release_ms=50)
80
- ]
81
- ),
82
-
83
- "radio_ready": MasteringPreset(
84
- "Radio Ready",
85
- "Maximum loudness for commercial radio",
86
- [
87
- HighpassFilter(cutoff_frequency_hz=40),
88
- PeakFilter(cutoff_frequency_hz=60, gain_db=-2.0, q=1.0),
89
- LowShelfFilter(cutoff_frequency_hz=150, gain_db=1.5, q=0.8),
90
- PeakFilter(cutoff_frequency_hz=3000, gain_db=2.0, q=1.5),
91
- PeakFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=1.0),
92
- HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.0, q=0.7),
93
- Compressor(threshold_db=-8, ratio=6.0, attack_ms=2, release_ms=60),
94
- Limiter(threshold_db=-0.1, release_ms=30)
95
- ]
96
- ),
97
-
98
- "punchy_commercial": MasteringPreset(
99
- "Punchy Commercial",
100
- "Aggressive punch for mainstream appeal",
101
- [
102
- HighpassFilter(cutoff_frequency_hz=30),
103
- PeakFilter(cutoff_frequency_hz=100, gain_db=-2.0, q=1.2),
104
- LowShelfFilter(cutoff_frequency_hz=200, gain_db=2.5, q=0.7),
105
- PeakFilter(cutoff_frequency_hz=1000, gain_db=-1.0, q=0.8),
106
- PeakFilter(cutoff_frequency_hz=4000, gain_db=2.5, q=1.5),
107
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.8),
108
- Compressor(threshold_db=-9, ratio=5.0, attack_ms=1, release_ms=50),
109
- Limiter(threshold_db=-0.2, release_ms=40)
110
- ]
111
- ),
112
-
113
- # Rock/Alternative Presets
114
- "rock_master": MasteringPreset(
115
- "Rock Master",
116
- "Powerful rock sound with emphasis on mids",
117
- [
118
- HighpassFilter(cutoff_frequency_hz=35),
119
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.0, q=0.7),
120
- PeakFilter(cutoff_frequency_hz=400, gain_db=1.5, q=1.0),
121
- PeakFilter(cutoff_frequency_hz=2000, gain_db=2.0, q=1.2),
122
- PeakFilter(cutoff_frequency_hz=5000, gain_db=1.5, q=1.0),
123
- HighShelfFilter(cutoff_frequency_hz=8000, gain_db=1.0, q=0.8),
124
- Compressor(threshold_db=-12, ratio=3.5, attack_ms=5, release_ms=120),
125
- Limiter(threshold_db=-0.5, release_ms=80)
126
- ]
127
- ),
128
-
129
- "metal_aggressive": MasteringPreset(
130
- "Metal Aggressive",
131
- "Heavy, aggressive metal mastering",
132
- [
133
- HighpassFilter(cutoff_frequency_hz=40),
134
- PeakFilter(cutoff_frequency_hz=80, gain_db=-1.5, q=1.0),
135
- LowShelfFilter(cutoff_frequency_hz=150, gain_db=2.0, q=0.8),
136
- PeakFilter(cutoff_frequency_hz=800, gain_db=-1.5, q=1.2),
137
- PeakFilter(cutoff_frequency_hz=3000, gain_db=3.0, q=1.5),
138
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=0.7),
139
- Compressor(threshold_db=-8, ratio=6.0, attack_ms=1, release_ms=50),
140
- Limiter(threshold_db=-0.1, release_ms=30)
141
- ]
142
- ),
143
-
144
- "indie_rock": MasteringPreset(
145
- "Indie Rock",
146
- "Lo-fi character with mid presence",
147
- [
148
- HighpassFilter(cutoff_frequency_hz=30),
149
- LowShelfFilter(cutoff_frequency_hz=120, gain_db=0.5, q=0.7),
150
- PeakFilter(cutoff_frequency_hz=500, gain_db=1.5, q=1.0),
151
- PeakFilter(cutoff_frequency_hz=2500, gain_db=2.0, q=1.2),
152
- PeakFilter(cutoff_frequency_hz=7000, gain_db=-0.5, q=1.0),
153
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=0.5, q=0.8),
154
- Compressor(threshold_db=-14, ratio=3.0, attack_ms=8, release_ms=150),
155
- Limiter(threshold_db=-0.8, release_ms=100)
156
- ]
157
- ),
158
-
159
- # Electronic/EDM Presets
160
- "edm_club": MasteringPreset(
161
- "EDM Club",
162
- "Powerful club sound with deep bass",
163
- [
164
- HighpassFilter(cutoff_frequency_hz=25),
165
- LowShelfFilter(cutoff_frequency_hz=80, gain_db=3.0, q=0.7),
166
- PeakFilter(cutoff_frequency_hz=150, gain_db=2.0, q=0.8),
167
- PeakFilter(cutoff_frequency_hz=1000, gain_db=-1.5, q=1.0),
168
- PeakFilter(cutoff_frequency_hz=5000, gain_db=2.0, q=1.2),
169
- HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.0, q=0.7),
170
- Compressor(threshold_db=-6, ratio=8.0, attack_ms=0.5, release_ms=40),
171
- Limiter(threshold_db=0.0, release_ms=20)
172
- ]
173
- ),
174
-
175
- "house_groovy": MasteringPreset(
176
- "House Groovy",
177
- "Smooth house music with rolling bass",
178
- [
179
- HighpassFilter(cutoff_frequency_hz=30),
180
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.5, q=0.7),
181
- PeakFilter(cutoff_frequency_hz=250, gain_db=1.0, q=0.8),
182
- PeakFilter(cutoff_frequency_hz=2000, gain_db=0.5, q=1.0),
183
- PeakFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=1.0),
184
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.7),
185
- Compressor(threshold_db=-10, ratio=4.0, attack_ms=2, release_ms=60),
186
- Limiter(threshold_db=-0.2, release_ms=40)
187
- ]
188
- ),
189
-
190
- "techno_dark": MasteringPreset(
191
- "Techno Dark",
192
- "Dark, pounding techno master",
193
- [
194
- HighpassFilter(cutoff_frequency_hz=35),
195
- PeakFilter(cutoff_frequency_hz=60, gain_db=2.0, q=1.0),
196
- LowShelfFilter(cutoff_frequency_hz=120, gain_db=1.5, q=0.8),
197
- PeakFilter(cutoff_frequency_hz=800, gain_db=-2.0, q=1.5),
198
- PeakFilter(cutoff_frequency_hz=4000, gain_db=1.0, q=1.0),
199
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=-0.5, q=0.8),
200
- Compressor(threshold_db=-8, ratio=6.0, attack_ms=1, release_ms=50),
201
- Limiter(threshold_db=-0.1, release_ms=30)
202
- ]
203
- ),
204
-
205
- "dubstep_heavy": MasteringPreset(
206
- "Dubstep Heavy",
207
- "Sub-bass focused with crispy highs",
208
- [
209
- HighpassFilter(cutoff_frequency_hz=20),
210
- PeakFilter(cutoff_frequency_hz=50, gain_db=3.5, q=1.2),
211
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.5, q=0.8),
212
- PeakFilter(cutoff_frequency_hz=500, gain_db=-2.0, q=1.5),
213
- PeakFilter(cutoff_frequency_hz=6000, gain_db=2.5, q=1.2),
214
- HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.5, q=0.7),
215
- Compressor(threshold_db=-6, ratio=10.0, attack_ms=0.3, release_ms=30),
216
- Limiter(threshold_db=0.0, release_ms=20)
217
- ]
218
- ),
219
-
220
- # Hip-Hop/R&B Presets
221
- "hiphop_modern": MasteringPreset(
222
- "Hip-Hop Modern",
223
- "Contemporary hip-hop with deep bass",
224
- [
225
- HighpassFilter(cutoff_frequency_hz=25),
226
- LowShelfFilter(cutoff_frequency_hz=80, gain_db=2.5, q=0.7),
227
- PeakFilter(cutoff_frequency_hz=150, gain_db=1.5, q=0.8),
228
- PeakFilter(cutoff_frequency_hz=1000, gain_db=-1.0, q=1.0),
229
- PeakFilter(cutoff_frequency_hz=3500, gain_db=2.0, q=1.2),
230
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.5, q=0.7),
231
- Compressor(threshold_db=-10, ratio=4.0, attack_ms=5, release_ms=80),
232
- Limiter(threshold_db=-0.3, release_ms=60)
233
- ]
234
- ),
235
-
236
- "trap_808": MasteringPreset(
237
- "Trap 808",
238
- "808-focused trap mastering",
239
- [
240
- HighpassFilter(cutoff_frequency_hz=20),
241
- PeakFilter(cutoff_frequency_hz=50, gain_db=3.0, q=1.0),
242
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.0, q=0.7),
243
- PeakFilter(cutoff_frequency_hz=800, gain_db=-1.5, q=1.2),
244
- PeakFilter(cutoff_frequency_hz=5000, gain_db=2.5, q=1.2),
245
- HighShelfFilter(cutoff_frequency_hz=12000, gain_db=2.0, q=0.7),
246
- Compressor(threshold_db=-8, ratio=5.0, attack_ms=3, release_ms=60),
247
- Limiter(threshold_db=-0.2, release_ms=40)
248
- ]
249
- ),
250
-
251
- "rnb_smooth": MasteringPreset(
252
- "R&B Smooth",
253
- "Silky smooth R&B sound",
254
- [
255
- HighpassFilter(cutoff_frequency_hz=30),
256
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.5, q=0.7),
257
- PeakFilter(cutoff_frequency_hz=300, gain_db=1.0, q=0.8),
258
- PeakFilter(cutoff_frequency_hz=2000, gain_db=0.5, q=1.0),
259
- PeakFilter(cutoff_frequency_hz=6000, gain_db=1.5, q=1.0),
260
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.7),
261
- Compressor(threshold_db=-12, ratio=3.0, attack_ms=8, release_ms=120),
262
- Limiter(threshold_db=-0.5, release_ms=80)
263
- ]
264
- ),
265
-
266
- # Acoustic/Organic Presets
267
- "acoustic_natural": MasteringPreset(
268
- "Acoustic Natural",
269
- "Natural, transparent acoustic sound",
270
- [
271
- HighpassFilter(cutoff_frequency_hz=25),
272
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=0.5, q=0.7),
273
- PeakFilter(cutoff_frequency_hz=500, gain_db=0.8, q=0.8),
274
- PeakFilter(cutoff_frequency_hz=3000, gain_db=1.0, q=1.0),
275
- HighShelfFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=0.7),
276
- Compressor(threshold_db=-16, ratio=2.0, attack_ms=15, release_ms=200),
277
- Limiter(threshold_db=-1.0, release_ms=120)
278
- ]
279
- ),
280
-
281
- "folk_warm": MasteringPreset(
282
- "Folk Warm",
283
- "Warm, intimate folk sound",
284
- [
285
- HighpassFilter(cutoff_frequency_hz=30),
286
- LowShelfFilter(cutoff_frequency_hz=150, gain_db=1.0, q=0.7),
287
- PeakFilter(cutoff_frequency_hz=400, gain_db=1.5, q=0.8),
288
- PeakFilter(cutoff_frequency_hz=2500, gain_db=1.0, q=1.0),
289
- PeakFilter(cutoff_frequency_hz=7000, gain_db=-0.5, q=1.0),
290
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.8),
291
- Compressor(threshold_db=-18, ratio=2.5, attack_ms=20, release_ms=250),
292
- Limiter(threshold_db=-1.5, release_ms=150)
293
- ]
294
- ),
295
-
296
- "jazz_vintage": MasteringPreset(
297
- "Jazz Vintage",
298
- "Classic jazz warmth and space",
299
- [
300
- HighpassFilter(cutoff_frequency_hz=35),
301
- LowShelfFilter(cutoff_frequency_hz=120, gain_db=1.0, q=0.7),
302
- PeakFilter(cutoff_frequency_hz=500, gain_db=1.0, q=0.8),
303
- PeakFilter(cutoff_frequency_hz=2000, gain_db=0.5, q=0.8),
304
- PeakFilter(cutoff_frequency_hz=8000, gain_db=-1.0, q=1.0),
305
- HighShelfFilter(cutoff_frequency_hz=12000, gain_db=0.5, q=0.8),
306
- Compressor(threshold_db=-20, ratio=2.0, attack_ms=25, release_ms=300),
307
- Limiter(threshold_db=-2.0, release_ms=180)
308
- ]
309
- ),
310
-
311
- # Classical/Orchestral Presets
312
- "orchestral_wide": MasteringPreset(
313
- "Orchestral Wide",
314
- "Wide, natural orchestral sound",
315
- [
316
- HighpassFilter(cutoff_frequency_hz=20),
317
- LowShelfFilter(cutoff_frequency_hz=80, gain_db=0.5, q=0.7),
318
- PeakFilter(cutoff_frequency_hz=300, gain_db=0.5, q=0.7),
319
- PeakFilter(cutoff_frequency_hz=4000, gain_db=0.8, q=0.8),
320
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7),
321
- Compressor(threshold_db=-24, ratio=1.5, attack_ms=30, release_ms=400),
322
- Limiter(threshold_db=-3.0, release_ms=250)
323
- ]
324
- ),
325
-
326
- "classical_concert": MasteringPreset(
327
- "Classical Concert",
328
- "Concert hall ambience and dynamics",
329
- [
330
- HighpassFilter(cutoff_frequency_hz=25),
331
- PeakFilter(cutoff_frequency_hz=200, gain_db=0.5, q=0.7),
332
- PeakFilter(cutoff_frequency_hz=1000, gain_db=0.3, q=0.8),
333
- PeakFilter(cutoff_frequency_hz=6000, gain_db=0.8, q=0.8),
334
- HighShelfFilter(cutoff_frequency_hz=12000, gain_db=0.5, q=0.7),
335
- Compressor(threshold_db=-30, ratio=1.2, attack_ms=50, release_ms=500),
336
- Limiter(threshold_db=-4.0, release_ms=300)
337
- ]
338
- ),
339
-
340
- # Ambient/Atmospheric Presets
341
- "ambient_spacious": MasteringPreset(
342
- "Ambient Spacious",
343
- "Wide, spacious ambient master",
344
- [
345
- HighpassFilter(cutoff_frequency_hz=25),
346
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=0.5, q=0.7),
347
- PeakFilter(cutoff_frequency_hz=500, gain_db=-0.5, q=0.8),
348
- PeakFilter(cutoff_frequency_hz=3000, gain_db=0.5, q=1.0),
349
- HighShelfFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=0.7),
350
- Compressor(threshold_db=-20, ratio=2.0, attack_ms=50, release_ms=400),
351
- Limiter(threshold_db=-2.0, release_ms=200)
352
- ]
353
- ),
354
-
355
- "cinematic_epic": MasteringPreset(
356
- "Cinematic Epic",
357
- "Big, powerful cinematic sound",
358
- [
359
- HighpassFilter(cutoff_frequency_hz=30),
360
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.0, q=0.7),
361
- PeakFilter(cutoff_frequency_hz=250, gain_db=1.0, q=0.8),
362
- PeakFilter(cutoff_frequency_hz=2000, gain_db=1.5, q=1.0),
363
- PeakFilter(cutoff_frequency_hz=6000, gain_db=2.0, q=1.0),
364
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=0.7),
365
- Compressor(threshold_db=-14, ratio=3.0, attack_ms=10, release_ms=150),
366
- Limiter(threshold_db=-0.5, release_ms=100)
367
- ]
368
- ),
369
-
370
- # Vintage/Lo-Fi Presets
371
- "lofi_chill": MasteringPreset(
372
- "Lo-Fi Chill",
373
- "Vintage lo-fi character",
374
- [
375
- HighpassFilter(cutoff_frequency_hz=50),
376
- LowpassFilter(cutoff_frequency_hz=10000),
377
- LowShelfFilter(cutoff_frequency_hz=150, gain_db=1.5, q=0.7),
378
- PeakFilter(cutoff_frequency_hz=800, gain_db=-1.0, q=1.2),
379
- PeakFilter(cutoff_frequency_hz=4000, gain_db=-1.5, q=1.0),
380
- Compressor(threshold_db=-12, ratio=3.0, attack_ms=15, release_ms=180),
381
- Limiter(threshold_db=-1.0, release_ms=120)
382
- ]
383
- ),
384
-
385
- "vintage_vinyl": MasteringPreset(
386
- "Vintage Vinyl",
387
- "Classic vinyl record warmth",
388
- [
389
- HighpassFilter(cutoff_frequency_hz=40),
390
- LowpassFilter(cutoff_frequency_hz=12000),
391
- LowShelfFilter(cutoff_frequency_hz=120, gain_db=2.0, q=0.7),
392
- PeakFilter(cutoff_frequency_hz=1000, gain_db=-0.5, q=0.8),
393
- PeakFilter(cutoff_frequency_hz=5000, gain_db=-1.0, q=1.0),
394
- HighShelfFilter(cutoff_frequency_hz=8000, gain_db=-1.5, q=0.8),
395
- Compressor(threshold_db=-16, ratio=2.5, attack_ms=20, release_ms=200),
396
- Limiter(threshold_db=-1.5, release_ms=150)
397
- ]
398
- ),
399
-
400
- "retro_80s": MasteringPreset(
401
- "Retro 80s",
402
- "1980s-inspired mix with character",
403
- [
404
- HighpassFilter(cutoff_frequency_hz=45),
405
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.5, q=0.7),
406
- PeakFilter(cutoff_frequency_hz=800, gain_db=1.0, q=1.2),
407
- PeakFilter(cutoff_frequency_hz=3000, gain_db=1.5, q=1.0),
408
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.7),
409
- Compressor(threshold_db=-14, ratio=3.5, attack_ms=5, release_ms=100),
410
- Limiter(threshold_db=-0.8, release_ms=80)
411
- ]
412
- ),
413
-
414
- # Enhancement Presets (Phase 2)
415
- "harmonic_enhance": MasteringPreset(
416
- "Harmonic Enhance",
417
- "Adds subtle harmonic overtones for brightness and warmth",
418
- [
419
- HighpassFilter(cutoff_frequency_hz=30),
420
- # Subtle low-end warmth
421
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.0, q=0.7),
422
- # Presence boost
423
- PeakFilter(cutoff_frequency_hz=3000, gain_db=1.5, q=1.0),
424
- # Air and clarity
425
- HighShelfFilter(cutoff_frequency_hz=8000, gain_db=2.0, q=0.7),
426
- # Gentle saturation effect through compression
427
- Compressor(threshold_db=-18, ratio=2.5, attack_ms=10, release_ms=120),
428
- # Final limiting
429
- Limiter(threshold_db=-0.5, release_ms=100),
430
- # Note: Additional harmonic generation would require Distortion plugin
431
- # which adds subtle harmonic overtones
432
- ]
433
- ),
434
- }
435
-
436
- def __init__(self):
437
- """Initialize mastering service"""
438
- logger.info("Mastering service initialized")
439
-
440
- # Specialized Presets
441
- "vocal_focused": MasteringPreset(
442
- "Vocal Focused",
443
- "Emphasizes vocal clarity and presence",
444
- [
445
- HighpassFilter(cutoff_frequency_hz=30),
446
- PeakFilter(cutoff_frequency_hz=200, gain_db=-1.0, q=0.8),
447
- PeakFilter(cutoff_frequency_hz=1000, gain_db=1.0, q=1.0),
448
- PeakFilter(cutoff_frequency_hz=3000, gain_db=2.5, q=1.2),
449
- PeakFilter(cutoff_frequency_hz=5000, gain_db=1.5, q=1.0),
450
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7),
451
- Compressor(threshold_db=-12, ratio=3.0, attack_ms=5, release_ms=100),
452
- Limiter(threshold_db=-0.5, release_ms=80)
453
- ]
454
- ),
455
-
456
- "bass_heavy": MasteringPreset(
457
- "Bass Heavy",
458
- "Maximum low-end power",
459
- [
460
- HighpassFilter(cutoff_frequency_hz=20),
461
- LowShelfFilter(cutoff_frequency_hz=60, gain_db=4.0, q=0.7),
462
- PeakFilter(cutoff_frequency_hz=100, gain_db=2.5, q=0.8),
463
- PeakFilter(cutoff_frequency_hz=500, gain_db=-1.5, q=1.0),
464
- PeakFilter(cutoff_frequency_hz=4000, gain_db=1.0, q=1.0),
465
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.5, q=0.7),
466
- Compressor(threshold_db=-10, ratio=4.0, attack_ms=10, release_ms=100),
467
- Limiter(threshold_db=-0.3, release_ms=60)
468
- ]
469
- ),
470
-
471
- "bright_airy": MasteringPreset(
472
- "Bright & Airy",
473
- "Crystal clear highs with airiness",
474
- [
475
- HighpassFilter(cutoff_frequency_hz=30),
476
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=-0.5, q=0.7),
477
- PeakFilter(cutoff_frequency_hz=500, gain_db=-1.0, q=0.8),
478
- PeakFilter(cutoff_frequency_hz=5000, gain_db=2.0, q=1.0),
479
- PeakFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=1.0),
480
- HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.0, q=0.7),
481
- Compressor(threshold_db=-14, ratio=2.5, attack_ms=8, release_ms=120),
482
- Limiter(threshold_db=-0.8, release_ms=100)
483
- ]
484
- ),
485
-
486
- "midrange_punch": MasteringPreset(
487
- "Midrange Punch",
488
- "Powerful mids for presence",
489
- [
490
- HighpassFilter(cutoff_frequency_hz=30),
491
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=0.5, q=0.7),
492
- PeakFilter(cutoff_frequency_hz=500, gain_db=2.0, q=1.0),
493
- PeakFilter(cutoff_frequency_hz=1500, gain_db=2.5, q=1.2),
494
- PeakFilter(cutoff_frequency_hz=3000, gain_db=2.0, q=1.0),
495
- HighShelfFilter(cutoff_frequency_hz=8000, gain_db=0.5, q=0.7),
496
- Compressor(threshold_db=-11, ratio=3.5, attack_ms=5, release_ms=90),
497
- Limiter(threshold_db=-0.5, release_ms=70)
498
- ]
499
- ),
500
-
501
- "dynamic_range": MasteringPreset(
502
- "Dynamic Range",
503
- "Preserves maximum dynamics",
504
- [
505
- HighpassFilter(cutoff_frequency_hz=25),
506
- PeakFilter(cutoff_frequency_hz=100, gain_db=-0.5, q=0.7),
507
- PeakFilter(cutoff_frequency_hz=3000, gain_db=0.5, q=0.8),
508
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7),
509
- Compressor(threshold_db=-20, ratio=1.5, attack_ms=20, release_ms=250),
510
- Limiter(threshold_db=-2.0, release_ms=200)
511
- ]
512
- ),
513
-
514
- "streaming_optimized": MasteringPreset(
515
- "Streaming Optimized",
516
- "Optimized for streaming platforms (Spotify, Apple Music)",
517
- [
518
- HighpassFilter(cutoff_frequency_hz=30),
519
- LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.0, q=0.7),
520
- PeakFilter(cutoff_frequency_hz=500, gain_db=0.5, q=0.8),
521
- PeakFilter(cutoff_frequency_hz=3000, gain_db=1.5, q=1.0),
522
- HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.5, q=0.7),
523
- Compressor(threshold_db=-14, ratio=3.0, attack_ms=5, release_ms=100),
524
- Limiter(threshold_db=-1.0, release_ms=100)
525
- ]
526
- )
527
- }
528
-
529
- def __init__(self):
530
- """Initialize mastering service"""
531
- logger.info("Mastering service initialized with 32 presets")
532
-
533
- def apply_preset(self, audio_path: str, preset_name: str, output_path: str) -> str:
534
- """
535
- Apply mastering preset to audio file
536
-
537
- Args:
538
- audio_path: Path to input audio file
539
- preset_name: Name of preset to apply
540
- output_path: Path to save processed audio
541
-
542
- Returns:
543
- Path to processed audio file
544
- """
545
- try:
546
- if preset_name not in self.PRESETS:
547
- raise ValueError(f"Unknown preset: {preset_name}")
548
-
549
- preset = self.PRESETS[preset_name]
550
- logger.info(f"Applying preset '{preset.name}' to {audio_path}")
551
-
552
- # Load audio
553
- audio, sr = sf.read(audio_path)
554
-
555
- # Ensure stereo
556
- if len(audio.shape) == 1:
557
- audio = np.stack([audio, audio], axis=1)
558
-
559
- # Create pedalboard with preset chain
560
- board = Pedalboard(preset.chain)
561
-
562
- # Process audio
563
- processed = board(audio.T, sr)
564
-
565
- # Save processed audio
566
- sf.write(output_path, processed.T, sr)
567
- logger.info(f"Saved mastered audio to {output_path}")
568
-
569
- return output_path
570
-
571
- except Exception as e:
572
- logger.error(f"Error applying preset: {str(e)}", exc_info=True)
573
- raise
574
-
575
- def apply_custom_eq(
576
- self,
577
- audio_path: str,
578
- output_path: str,
579
- eq_bands: List[Dict],
580
- compression: Optional[Dict] = None,
581
- limiting: Optional[Dict] = None
582
- ) -> str:
583
- """
584
- Apply custom EQ settings to audio file
585
-
586
- Args:
587
- audio_path: Path to input audio file
588
- output_path: Path to save processed audio
589
- eq_bands: List of EQ band settings
590
- compression: Compression settings (optional)
591
- limiting: Limiter settings (optional)
592
-
593
- Returns:
594
- Path to processed audio file
595
- """
596
- try:
597
- logger.info(f"Applying custom EQ to {audio_path}")
598
-
599
- # Load audio
600
- audio, sr = sf.read(audio_path)
601
-
602
- # Ensure stereo
603
- if len(audio.shape) == 1:
604
- audio = np.stack([audio, audio], axis=1)
605
-
606
- # Build processing chain
607
- chain = []
608
-
609
- # Add EQ bands
610
- for band in eq_bands:
611
- band_type = band.get('type', 'peak')
612
- freq = band.get('frequency', 1000)
613
- gain = band.get('gain', 0)
614
- q = band.get('q', 1.0)
615
-
616
- if band_type == 'highpass':
617
- chain.append(HighpassFilter(cutoff_frequency_hz=freq))
618
- elif band_type == 'lowpass':
619
- chain.append(LowpassFilter(cutoff_frequency_hz=freq))
620
- elif band_type == 'lowshelf':
621
- chain.append(LowShelfFilter(cutoff_frequency_hz=freq, gain_db=gain, q=q))
622
- elif band_type == 'highshelf':
623
- chain.append(HighShelfFilter(cutoff_frequency_hz=freq, gain_db=gain, q=q))
624
- else: # peak
625
- chain.append(PeakFilter(cutoff_frequency_hz=freq, gain_db=gain, q=q))
626
-
627
- # Add compression if specified
628
- if compression:
629
- chain.append(Compressor(
630
- threshold_db=compression.get('threshold', -12),
631
- ratio=compression.get('ratio', 2.0),
632
- attack_ms=compression.get('attack', 5),
633
- release_ms=compression.get('release', 100)
634
- ))
635
-
636
- # Add limiting if specified
637
- if limiting:
638
- chain.append(Limiter(
639
- threshold_db=limiting.get('threshold', -1.0),
640
- release_ms=limiting.get('release', 100)
641
- ))
642
-
643
- # Create and apply pedalboard
644
- board = Pedalboard(chain)
645
- processed = board(audio.T, sr)
646
-
647
- # Save processed audio
648
- sf.write(output_path, processed.T, sr)
649
- logger.info(f"Saved custom EQ audio to {output_path}")
650
-
651
- return output_path
652
-
653
- except Exception as e:
654
- logger.error(f"Error applying custom EQ: {str(e)}", exc_info=True)
655
- raise
656
-
657
- def get_preset_list(self) -> List[Dict]:
658
- """Get list of available presets with descriptions"""
659
- return [
660
- {
661
- 'id': key,
662
- 'name': preset.name,
663
- 'description': preset.description
664
- }
665
- for key, preset in self.PRESETS.items()
666
- ]
 
1
+ """
2
+ Audio mastering service with industry-standard presets using Pedalboard
3
+ """
4
+ import os
5
+ import logging
6
+ import numpy as np
7
+ from pathlib import Path
8
+ from typing import Dict, List, Optional
9
+ import soundfile as sf
10
+ from pedalboard import (
11
+ Pedalboard,
12
+ Compressor,
13
+ Limiter,
14
+ Gain,
15
+ HighpassFilter,
16
+ LowpassFilter,
17
+ PeakFilter,
18
+ LowShelfFilter,
19
+ HighShelfFilter,
20
+ Reverb,
21
+ Chorus,
22
+ Delay
23
+ )
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+ class MasteringPreset:
28
+ """Mastering preset configuration"""
29
+
30
+ def __init__(self, name: str, description: str, chain: List):
31
+ self.name = name
32
+ self.description = description
33
+ self.chain = chain
34
+
35
+ class MasteringService:
36
+ """Audio mastering and EQ service"""
37
+
38
+ # Industry-standard mastering presets
39
+ PRESETS = {
40
+ # Clean/Transparent Presets
41
+ "clean_master": MasteringPreset(
42
+ "Clean Master",
43
+ "Transparent mastering with gentle compression",
44
+ [
45
+ HighpassFilter(cutoff_frequency_hz=30),
46
+ PeakFilter(cutoff_frequency_hz=100, gain_db=-1, q=0.7),
47
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=0.5, q=1.0),
48
+ PeakFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7),
49
+ Compressor(threshold_db=-12, ratio=2.0, attack_ms=5, release_ms=100),
50
+ Limiter(threshold_db=-1.0, release_ms=100)
51
+ ]
52
+ ),
53
+
54
+ "subtle_warmth": MasteringPreset(
55
+ "Subtle Warmth",
56
+ "Gentle low-end enhancement with smooth highs",
57
+ [
58
+ HighpassFilter(cutoff_frequency_hz=25),
59
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.5, q=0.7),
60
+ PeakFilter(cutoff_frequency_hz=200, gain_db=0.8, q=0.5),
61
+ PeakFilter(cutoff_frequency_hz=8000, gain_db=-0.5, q=1.0),
62
+ HighShelfFilter(cutoff_frequency_hz=12000, gain_db=1.0, q=0.7),
63
+ Compressor(threshold_db=-15, ratio=2.5, attack_ms=10, release_ms=150),
64
+ Limiter(threshold_db=-0.5, release_ms=100)
65
+ ]
66
+ ),
67
+
68
+ # Pop/Commercial Presets
69
+ "modern_pop": MasteringPreset(
70
+ "Modern Pop",
71
+ "Radio-ready pop sound with punchy compression",
72
+ [
73
+ HighpassFilter(cutoff_frequency_hz=35),
74
+ PeakFilter(cutoff_frequency_hz=80, gain_db=-1.5, q=0.8),
75
+ LowShelfFilter(cutoff_frequency_hz=120, gain_db=2.0, q=0.7),
76
+ PeakFilter(cutoff_frequency_hz=2500, gain_db=1.5, q=1.2),
77
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=0.7),
78
+ Compressor(threshold_db=-10, ratio=4.0, attack_ms=3, release_ms=80),
79
+ Limiter(threshold_db=-0.3, release_ms=50)
80
+ ]
81
+ ),
82
+
83
+ "radio_ready": MasteringPreset(
84
+ "Radio Ready",
85
+ "Maximum loudness for commercial radio",
86
+ [
87
+ HighpassFilter(cutoff_frequency_hz=40),
88
+ PeakFilter(cutoff_frequency_hz=60, gain_db=-2.0, q=1.0),
89
+ LowShelfFilter(cutoff_frequency_hz=150, gain_db=1.5, q=0.8),
90
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=2.0, q=1.5),
91
+ PeakFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=1.0),
92
+ HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.0, q=0.7),
93
+ Compressor(threshold_db=-8, ratio=6.0, attack_ms=2, release_ms=60),
94
+ Limiter(threshold_db=-0.1, release_ms=30)
95
+ ]
96
+ ),
97
+
98
+ "punchy_commercial": MasteringPreset(
99
+ "Punchy Commercial",
100
+ "Aggressive punch for mainstream appeal",
101
+ [
102
+ HighpassFilter(cutoff_frequency_hz=30),
103
+ PeakFilter(cutoff_frequency_hz=100, gain_db=-2.0, q=1.2),
104
+ LowShelfFilter(cutoff_frequency_hz=200, gain_db=2.5, q=0.7),
105
+ PeakFilter(cutoff_frequency_hz=1000, gain_db=-1.0, q=0.8),
106
+ PeakFilter(cutoff_frequency_hz=4000, gain_db=2.5, q=1.5),
107
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.8),
108
+ Compressor(threshold_db=-9, ratio=5.0, attack_ms=1, release_ms=50),
109
+ Limiter(threshold_db=-0.2, release_ms=40)
110
+ ]
111
+ ),
112
+
113
+ # Rock/Alternative Presets
114
+ "rock_master": MasteringPreset(
115
+ "Rock Master",
116
+ "Powerful rock sound with emphasis on mids",
117
+ [
118
+ HighpassFilter(cutoff_frequency_hz=35),
119
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.0, q=0.7),
120
+ PeakFilter(cutoff_frequency_hz=400, gain_db=1.5, q=1.0),
121
+ PeakFilter(cutoff_frequency_hz=2000, gain_db=2.0, q=1.2),
122
+ PeakFilter(cutoff_frequency_hz=5000, gain_db=1.5, q=1.0),
123
+ HighShelfFilter(cutoff_frequency_hz=8000, gain_db=1.0, q=0.8),
124
+ Compressor(threshold_db=-12, ratio=3.5, attack_ms=5, release_ms=120),
125
+ Limiter(threshold_db=-0.5, release_ms=80)
126
+ ]
127
+ ),
128
+
129
+ "metal_aggressive": MasteringPreset(
130
+ "Metal Aggressive",
131
+ "Heavy, aggressive metal mastering",
132
+ [
133
+ HighpassFilter(cutoff_frequency_hz=40),
134
+ PeakFilter(cutoff_frequency_hz=80, gain_db=-1.5, q=1.0),
135
+ LowShelfFilter(cutoff_frequency_hz=150, gain_db=2.0, q=0.8),
136
+ PeakFilter(cutoff_frequency_hz=800, gain_db=-1.5, q=1.2),
137
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=3.0, q=1.5),
138
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=0.7),
139
+ Compressor(threshold_db=-8, ratio=6.0, attack_ms=1, release_ms=50),
140
+ Limiter(threshold_db=-0.1, release_ms=30)
141
+ ]
142
+ ),
143
+
144
+ "indie_rock": MasteringPreset(
145
+ "Indie Rock",
146
+ "Lo-fi character with mid presence",
147
+ [
148
+ HighpassFilter(cutoff_frequency_hz=30),
149
+ LowShelfFilter(cutoff_frequency_hz=120, gain_db=0.5, q=0.7),
150
+ PeakFilter(cutoff_frequency_hz=500, gain_db=1.5, q=1.0),
151
+ PeakFilter(cutoff_frequency_hz=2500, gain_db=2.0, q=1.2),
152
+ PeakFilter(cutoff_frequency_hz=7000, gain_db=-0.5, q=1.0),
153
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=0.5, q=0.8),
154
+ Compressor(threshold_db=-14, ratio=3.0, attack_ms=8, release_ms=150),
155
+ Limiter(threshold_db=-0.8, release_ms=100)
156
+ ]
157
+ ),
158
+
159
+ # Electronic/EDM Presets
160
+ "edm_club": MasteringPreset(
161
+ "EDM Club",
162
+ "Powerful club sound with deep bass",
163
+ [
164
+ HighpassFilter(cutoff_frequency_hz=25),
165
+ LowShelfFilter(cutoff_frequency_hz=80, gain_db=3.0, q=0.7),
166
+ PeakFilter(cutoff_frequency_hz=150, gain_db=2.0, q=0.8),
167
+ PeakFilter(cutoff_frequency_hz=1000, gain_db=-1.5, q=1.0),
168
+ PeakFilter(cutoff_frequency_hz=5000, gain_db=2.0, q=1.2),
169
+ HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.0, q=0.7),
170
+ Compressor(threshold_db=-6, ratio=8.0, attack_ms=0.5, release_ms=40),
171
+ Limiter(threshold_db=0.0, release_ms=20)
172
+ ]
173
+ ),
174
+
175
+ "house_groovy": MasteringPreset(
176
+ "House Groovy",
177
+ "Smooth house music with rolling bass",
178
+ [
179
+ HighpassFilter(cutoff_frequency_hz=30),
180
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.5, q=0.7),
181
+ PeakFilter(cutoff_frequency_hz=250, gain_db=1.0, q=0.8),
182
+ PeakFilter(cutoff_frequency_hz=2000, gain_db=0.5, q=1.0),
183
+ PeakFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=1.0),
184
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.7),
185
+ Compressor(threshold_db=-10, ratio=4.0, attack_ms=2, release_ms=60),
186
+ Limiter(threshold_db=-0.2, release_ms=40)
187
+ ]
188
+ ),
189
+
190
+ "techno_dark": MasteringPreset(
191
+ "Techno Dark",
192
+ "Dark, pounding techno master",
193
+ [
194
+ HighpassFilter(cutoff_frequency_hz=35),
195
+ PeakFilter(cutoff_frequency_hz=60, gain_db=2.0, q=1.0),
196
+ LowShelfFilter(cutoff_frequency_hz=120, gain_db=1.5, q=0.8),
197
+ PeakFilter(cutoff_frequency_hz=800, gain_db=-2.0, q=1.5),
198
+ PeakFilter(cutoff_frequency_hz=4000, gain_db=1.0, q=1.0),
199
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=-0.5, q=0.8),
200
+ Compressor(threshold_db=-8, ratio=6.0, attack_ms=1, release_ms=50),
201
+ Limiter(threshold_db=-0.1, release_ms=30)
202
+ ]
203
+ ),
204
+
205
+ "dubstep_heavy": MasteringPreset(
206
+ "Dubstep Heavy",
207
+ "Sub-bass focused with crispy highs",
208
+ [
209
+ HighpassFilter(cutoff_frequency_hz=20),
210
+ PeakFilter(cutoff_frequency_hz=50, gain_db=3.5, q=1.2),
211
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.5, q=0.8),
212
+ PeakFilter(cutoff_frequency_hz=500, gain_db=-2.0, q=1.5),
213
+ PeakFilter(cutoff_frequency_hz=6000, gain_db=2.5, q=1.2),
214
+ HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.5, q=0.7),
215
+ Compressor(threshold_db=-6, ratio=10.0, attack_ms=0.3, release_ms=30),
216
+ Limiter(threshold_db=0.0, release_ms=20)
217
+ ]
218
+ ),
219
+
220
+ # Hip-Hop/R&B Presets
221
+ "hiphop_modern": MasteringPreset(
222
+ "Hip-Hop Modern",
223
+ "Contemporary hip-hop with deep bass",
224
+ [
225
+ HighpassFilter(cutoff_frequency_hz=25),
226
+ LowShelfFilter(cutoff_frequency_hz=80, gain_db=2.5, q=0.7),
227
+ PeakFilter(cutoff_frequency_hz=150, gain_db=1.5, q=0.8),
228
+ PeakFilter(cutoff_frequency_hz=1000, gain_db=-1.0, q=1.0),
229
+ PeakFilter(cutoff_frequency_hz=3500, gain_db=2.0, q=1.2),
230
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.5, q=0.7),
231
+ Compressor(threshold_db=-10, ratio=4.0, attack_ms=5, release_ms=80),
232
+ Limiter(threshold_db=-0.3, release_ms=60)
233
+ ]
234
+ ),
235
+
236
+ "trap_808": MasteringPreset(
237
+ "Trap 808",
238
+ "808-focused trap mastering",
239
+ [
240
+ HighpassFilter(cutoff_frequency_hz=20),
241
+ PeakFilter(cutoff_frequency_hz=50, gain_db=3.0, q=1.0),
242
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.0, q=0.7),
243
+ PeakFilter(cutoff_frequency_hz=800, gain_db=-1.5, q=1.2),
244
+ PeakFilter(cutoff_frequency_hz=5000, gain_db=2.5, q=1.2),
245
+ HighShelfFilter(cutoff_frequency_hz=12000, gain_db=2.0, q=0.7),
246
+ Compressor(threshold_db=-8, ratio=5.0, attack_ms=3, release_ms=60),
247
+ Limiter(threshold_db=-0.2, release_ms=40)
248
+ ]
249
+ ),
250
+
251
+ "rnb_smooth": MasteringPreset(
252
+ "R&B Smooth",
253
+ "Silky smooth R&B sound",
254
+ [
255
+ HighpassFilter(cutoff_frequency_hz=30),
256
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.5, q=0.7),
257
+ PeakFilter(cutoff_frequency_hz=300, gain_db=1.0, q=0.8),
258
+ PeakFilter(cutoff_frequency_hz=2000, gain_db=0.5, q=1.0),
259
+ PeakFilter(cutoff_frequency_hz=6000, gain_db=1.5, q=1.0),
260
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.7),
261
+ Compressor(threshold_db=-12, ratio=3.0, attack_ms=8, release_ms=120),
262
+ Limiter(threshold_db=-0.5, release_ms=80)
263
+ ]
264
+ ),
265
+
266
+ # Acoustic/Organic Presets
267
+ "acoustic_natural": MasteringPreset(
268
+ "Acoustic Natural",
269
+ "Natural, transparent acoustic sound",
270
+ [
271
+ HighpassFilter(cutoff_frequency_hz=25),
272
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=0.5, q=0.7),
273
+ PeakFilter(cutoff_frequency_hz=500, gain_db=0.8, q=0.8),
274
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=1.0, q=1.0),
275
+ HighShelfFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=0.7),
276
+ Compressor(threshold_db=-16, ratio=2.0, attack_ms=15, release_ms=200),
277
+ Limiter(threshold_db=-1.0, release_ms=120)
278
+ ]
279
+ ),
280
+
281
+ "folk_warm": MasteringPreset(
282
+ "Folk Warm",
283
+ "Warm, intimate folk sound",
284
+ [
285
+ HighpassFilter(cutoff_frequency_hz=30),
286
+ LowShelfFilter(cutoff_frequency_hz=150, gain_db=1.0, q=0.7),
287
+ PeakFilter(cutoff_frequency_hz=400, gain_db=1.5, q=0.8),
288
+ PeakFilter(cutoff_frequency_hz=2500, gain_db=1.0, q=1.0),
289
+ PeakFilter(cutoff_frequency_hz=7000, gain_db=-0.5, q=1.0),
290
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.8),
291
+ Compressor(threshold_db=-18, ratio=2.5, attack_ms=20, release_ms=250),
292
+ Limiter(threshold_db=-1.5, release_ms=150)
293
+ ]
294
+ ),
295
+
296
+ "jazz_vintage": MasteringPreset(
297
+ "Jazz Vintage",
298
+ "Classic jazz warmth and space",
299
+ [
300
+ HighpassFilter(cutoff_frequency_hz=35),
301
+ LowShelfFilter(cutoff_frequency_hz=120, gain_db=1.0, q=0.7),
302
+ PeakFilter(cutoff_frequency_hz=500, gain_db=1.0, q=0.8),
303
+ PeakFilter(cutoff_frequency_hz=2000, gain_db=0.5, q=0.8),
304
+ PeakFilter(cutoff_frequency_hz=8000, gain_db=-1.0, q=1.0),
305
+ HighShelfFilter(cutoff_frequency_hz=12000, gain_db=0.5, q=0.8),
306
+ Compressor(threshold_db=-20, ratio=2.0, attack_ms=25, release_ms=300),
307
+ Limiter(threshold_db=-2.0, release_ms=180)
308
+ ]
309
+ ),
310
+
311
+ # Classical/Orchestral Presets
312
+ "orchestral_wide": MasteringPreset(
313
+ "Orchestral Wide",
314
+ "Wide, natural orchestral sound",
315
+ [
316
+ HighpassFilter(cutoff_frequency_hz=20),
317
+ LowShelfFilter(cutoff_frequency_hz=80, gain_db=0.5, q=0.7),
318
+ PeakFilter(cutoff_frequency_hz=300, gain_db=0.5, q=0.7),
319
+ PeakFilter(cutoff_frequency_hz=4000, gain_db=0.8, q=0.8),
320
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7),
321
+ Compressor(threshold_db=-24, ratio=1.5, attack_ms=30, release_ms=400),
322
+ Limiter(threshold_db=-3.0, release_ms=250)
323
+ ]
324
+ ),
325
+
326
+ "classical_concert": MasteringPreset(
327
+ "Classical Concert",
328
+ "Concert hall ambience and dynamics",
329
+ [
330
+ HighpassFilter(cutoff_frequency_hz=25),
331
+ PeakFilter(cutoff_frequency_hz=200, gain_db=0.5, q=0.7),
332
+ PeakFilter(cutoff_frequency_hz=1000, gain_db=0.3, q=0.8),
333
+ PeakFilter(cutoff_frequency_hz=6000, gain_db=0.8, q=0.8),
334
+ HighShelfFilter(cutoff_frequency_hz=12000, gain_db=0.5, q=0.7),
335
+ Compressor(threshold_db=-30, ratio=1.2, attack_ms=50, release_ms=500),
336
+ Limiter(threshold_db=-4.0, release_ms=300)
337
+ ]
338
+ ),
339
+
340
+ # Ambient/Atmospheric Presets
341
+ "ambient_spacious": MasteringPreset(
342
+ "Ambient Spacious",
343
+ "Wide, spacious ambient master",
344
+ [
345
+ HighpassFilter(cutoff_frequency_hz=25),
346
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=0.5, q=0.7),
347
+ PeakFilter(cutoff_frequency_hz=500, gain_db=-0.5, q=0.8),
348
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=0.5, q=1.0),
349
+ HighShelfFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=0.7),
350
+ Compressor(threshold_db=-20, ratio=2.0, attack_ms=50, release_ms=400),
351
+ Limiter(threshold_db=-2.0, release_ms=200)
352
+ ]
353
+ ),
354
+
355
+ "cinematic_epic": MasteringPreset(
356
+ "Cinematic Epic",
357
+ "Big, powerful cinematic sound",
358
+ [
359
+ HighpassFilter(cutoff_frequency_hz=30),
360
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.0, q=0.7),
361
+ PeakFilter(cutoff_frequency_hz=250, gain_db=1.0, q=0.8),
362
+ PeakFilter(cutoff_frequency_hz=2000, gain_db=1.5, q=1.0),
363
+ PeakFilter(cutoff_frequency_hz=6000, gain_db=2.0, q=1.0),
364
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=0.7),
365
+ Compressor(threshold_db=-14, ratio=3.0, attack_ms=10, release_ms=150),
366
+ Limiter(threshold_db=-0.5, release_ms=100)
367
+ ]
368
+ ),
369
+
370
+ # Vintage/Lo-Fi Presets
371
+ "lofi_chill": MasteringPreset(
372
+ "Lo-Fi Chill",
373
+ "Vintage lo-fi character",
374
+ [
375
+ HighpassFilter(cutoff_frequency_hz=50),
376
+ LowpassFilter(cutoff_frequency_hz=10000),
377
+ LowShelfFilter(cutoff_frequency_hz=150, gain_db=1.5, q=0.7),
378
+ PeakFilter(cutoff_frequency_hz=800, gain_db=-1.0, q=1.2),
379
+ PeakFilter(cutoff_frequency_hz=4000, gain_db=-1.5, q=1.0),
380
+ Compressor(threshold_db=-12, ratio=3.0, attack_ms=15, release_ms=180),
381
+ Limiter(threshold_db=-1.0, release_ms=120)
382
+ ]
383
+ ),
384
+
385
+ "vintage_vinyl": MasteringPreset(
386
+ "Vintage Vinyl",
387
+ "Classic vinyl record warmth",
388
+ [
389
+ HighpassFilter(cutoff_frequency_hz=40),
390
+ LowpassFilter(cutoff_frequency_hz=12000),
391
+ LowShelfFilter(cutoff_frequency_hz=120, gain_db=2.0, q=0.7),
392
+ PeakFilter(cutoff_frequency_hz=1000, gain_db=-0.5, q=0.8),
393
+ PeakFilter(cutoff_frequency_hz=5000, gain_db=-1.0, q=1.0),
394
+ HighShelfFilter(cutoff_frequency_hz=8000, gain_db=-1.5, q=0.8),
395
+ Compressor(threshold_db=-16, ratio=2.5, attack_ms=20, release_ms=200),
396
+ Limiter(threshold_db=-1.5, release_ms=150)
397
+ ]
398
+ ),
399
+
400
+ "retro_80s": MasteringPreset(
401
+ "Retro 80s",
402
+ "1980s-inspired mix with character",
403
+ [
404
+ HighpassFilter(cutoff_frequency_hz=45),
405
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.5, q=0.7),
406
+ PeakFilter(cutoff_frequency_hz=800, gain_db=1.0, q=1.2),
407
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=1.5, q=1.0),
408
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.7),
409
+ Compressor(threshold_db=-14, ratio=3.5, attack_ms=5, release_ms=100),
410
+ Limiter(threshold_db=-0.8, release_ms=80)
411
+ ]
412
+ ),
413
+
414
+ # Enhancement Presets (Phase 2)
415
+ "harmonic_enhance": MasteringPreset(
416
+ "Harmonic Enhance",
417
+ "Adds subtle harmonic overtones for brightness and warmth",
418
+ [
419
+ HighpassFilter(cutoff_frequency_hz=30),
420
+ # Subtle low-end warmth
421
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.0, q=0.7),
422
+ # Presence boost
423
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=1.5, q=1.0),
424
+ # Air and clarity
425
+ HighShelfFilter(cutoff_frequency_hz=8000, gain_db=2.0, q=0.7),
426
+ # Gentle saturation effect through compression
427
+ Compressor(threshold_db=-18, ratio=2.5, attack_ms=10, release_ms=120),
428
+ # Final limiting
429
+ Limiter(threshold_db=-0.5, release_ms=100),
430
+ # Note: Additional harmonic generation would require Distortion plugin
431
+ # which adds subtle harmonic overtones
432
+ ]
433
+ ),
434
+
435
+ # Specialized Presets
436
+ "vocal_focused": MasteringPreset(
437
+ "Vocal Focused",
438
+ "Emphasizes vocal clarity and presence",
439
+ [
440
+ HighpassFilter(cutoff_frequency_hz=30),
441
+ PeakFilter(cutoff_frequency_hz=200, gain_db=-1.0, q=0.8),
442
+ PeakFilter(cutoff_frequency_hz=1000, gain_db=1.0, q=1.0),
443
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=2.5, q=1.2),
444
+ PeakFilter(cutoff_frequency_hz=5000, gain_db=1.5, q=1.0),
445
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7),
446
+ Compressor(threshold_db=-12, ratio=3.0, attack_ms=5, release_ms=100),
447
+ Limiter(threshold_db=-0.5, release_ms=80)
448
+ ]
449
+ ),
450
+
451
+ "bass_heavy": MasteringPreset(
452
+ "Bass Heavy",
453
+ "Maximum low-end power",
454
+ [
455
+ HighpassFilter(cutoff_frequency_hz=20),
456
+ LowShelfFilter(cutoff_frequency_hz=60, gain_db=4.0, q=0.7),
457
+ PeakFilter(cutoff_frequency_hz=100, gain_db=2.5, q=0.8),
458
+ PeakFilter(cutoff_frequency_hz=500, gain_db=-1.5, q=1.0),
459
+ PeakFilter(cutoff_frequency_hz=4000, gain_db=1.0, q=1.0),
460
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.5, q=0.7),
461
+ Compressor(threshold_db=-10, ratio=4.0, attack_ms=10, release_ms=100),
462
+ Limiter(threshold_db=-0.3, release_ms=60)
463
+ ]
464
+ ),
465
+
466
+ "bright_airy": MasteringPreset(
467
+ "Bright & Airy",
468
+ "Crystal clear highs with airiness",
469
+ [
470
+ HighpassFilter(cutoff_frequency_hz=30),
471
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=-0.5, q=0.7),
472
+ PeakFilter(cutoff_frequency_hz=500, gain_db=-1.0, q=0.8),
473
+ PeakFilter(cutoff_frequency_hz=5000, gain_db=2.0, q=1.0),
474
+ PeakFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=1.0),
475
+ HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.0, q=0.7),
476
+ Compressor(threshold_db=-14, ratio=2.5, attack_ms=8, release_ms=120),
477
+ Limiter(threshold_db=-0.8, release_ms=100)
478
+ ]
479
+ ),
480
+
481
+ "midrange_punch": MasteringPreset(
482
+ "Midrange Punch",
483
+ "Powerful mids for presence",
484
+ [
485
+ HighpassFilter(cutoff_frequency_hz=30),
486
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=0.5, q=0.7),
487
+ PeakFilter(cutoff_frequency_hz=500, gain_db=2.0, q=1.0),
488
+ PeakFilter(cutoff_frequency_hz=1500, gain_db=2.5, q=1.2),
489
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=2.0, q=1.0),
490
+ HighShelfFilter(cutoff_frequency_hz=8000, gain_db=0.5, q=0.7),
491
+ Compressor(threshold_db=-11, ratio=3.5, attack_ms=5, release_ms=90),
492
+ Limiter(threshold_db=-0.5, release_ms=70)
493
+ ]
494
+ ),
495
+
496
+ "dynamic_range": MasteringPreset(
497
+ "Dynamic Range",
498
+ "Preserves maximum dynamics",
499
+ [
500
+ HighpassFilter(cutoff_frequency_hz=25),
501
+ PeakFilter(cutoff_frequency_hz=100, gain_db=-0.5, q=0.7),
502
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=0.5, q=0.8),
503
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7),
504
+ Compressor(threshold_db=-20, ratio=1.5, attack_ms=20, release_ms=250),
505
+ Limiter(threshold_db=-2.0, release_ms=200)
506
+ ]
507
+ ),
508
+
509
+ "streaming_optimized": MasteringPreset(
510
+ "Streaming Optimized",
511
+ "Optimized for streaming platforms (Spotify, Apple Music)",
512
+ [
513
+ HighpassFilter(cutoff_frequency_hz=30),
514
+ LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.0, q=0.7),
515
+ PeakFilter(cutoff_frequency_hz=500, gain_db=0.5, q=0.8),
516
+ PeakFilter(cutoff_frequency_hz=3000, gain_db=1.5, q=1.0),
517
+ HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.5, q=0.7),
518
+ Compressor(threshold_db=-14, ratio=3.0, attack_ms=5, release_ms=100),
519
+ Limiter(threshold_db=-1.0, release_ms=100)
520
+ ]
521
+ )
522
+ }
523
+
524
+ def __init__(self):
525
+ """Initialize mastering service"""
526
+ logger.info("Mastering service initialized with 32 presets")
527
+
528
+ def apply_preset(self, audio_path: str, preset_name: str, output_path: str) -> str:
529
+ """
530
+ Apply mastering preset to audio file
531
+
532
+ Args:
533
+ audio_path: Path to input audio file
534
+ preset_name: Name of preset to apply
535
+ output_path: Path to save processed audio
536
+
537
+ Returns:
538
+ Path to processed audio file
539
+ """
540
+ try:
541
+ if preset_name not in self.PRESETS:
542
+ raise ValueError(f"Unknown preset: {preset_name}")
543
+
544
+ preset = self.PRESETS[preset_name]
545
+ logger.info(f"Applying preset '{preset.name}' to {audio_path}")
546
+
547
+ # Load audio
548
+ audio, sr = sf.read(audio_path)
549
+
550
+ # Ensure stereo
551
+ if len(audio.shape) == 1:
552
+ audio = np.stack([audio, audio], axis=1)
553
+
554
+ # Create pedalboard with preset chain
555
+ board = Pedalboard(preset.chain)
556
+
557
+ # Process audio
558
+ processed = board(audio.T, sr)
559
+
560
+ # Save processed audio
561
+ sf.write(output_path, processed.T, sr)
562
+ logger.info(f"Saved mastered audio to {output_path}")
563
+
564
+ return output_path
565
+
566
+ except Exception as e:
567
+ logger.error(f"Error applying preset: {str(e)}", exc_info=True)
568
+ raise
569
+
570
+ def apply_custom_eq(
571
+ self,
572
+ audio_path: str,
573
+ output_path: str,
574
+ eq_bands: List[Dict],
575
+ compression: Optional[Dict] = None,
576
+ limiting: Optional[Dict] = None
577
+ ) -> str:
578
+ """
579
+ Apply custom EQ settings to audio file
580
+
581
+ Args:
582
+ audio_path: Path to input audio file
583
+ output_path: Path to save processed audio
584
+ eq_bands: List of EQ band settings
585
+ compression: Compression settings (optional)
586
+ limiting: Limiter settings (optional)
587
+
588
+ Returns:
589
+ Path to processed audio file
590
+ """
591
+ try:
592
+ logger.info(f"Applying custom EQ to {audio_path}")
593
+
594
+ # Load audio
595
+ audio, sr = sf.read(audio_path)
596
+
597
+ # Ensure stereo
598
+ if len(audio.shape) == 1:
599
+ audio = np.stack([audio, audio], axis=1)
600
+
601
+ # Build processing chain
602
+ chain = []
603
+
604
+ # Add EQ bands
605
+ for band in eq_bands:
606
+ band_type = band.get('type', 'peak')
607
+ freq = band.get('frequency', 1000)
608
+ gain = band.get('gain', 0)
609
+ q = band.get('q', 1.0)
610
+
611
+ if band_type == 'highpass':
612
+ chain.append(HighpassFilter(cutoff_frequency_hz=freq))
613
+ elif band_type == 'lowpass':
614
+ chain.append(LowpassFilter(cutoff_frequency_hz=freq))
615
+ elif band_type == 'lowshelf':
616
+ chain.append(LowShelfFilter(cutoff_frequency_hz=freq, gain_db=gain, q=q))
617
+ elif band_type == 'highshelf':
618
+ chain.append(HighShelfFilter(cutoff_frequency_hz=freq, gain_db=gain, q=q))
619
+ else: # peak
620
+ chain.append(PeakFilter(cutoff_frequency_hz=freq, gain_db=gain, q=q))
621
+
622
+ # Add compression if specified
623
+ if compression:
624
+ chain.append(Compressor(
625
+ threshold_db=compression.get('threshold', -12),
626
+ ratio=compression.get('ratio', 2.0),
627
+ attack_ms=compression.get('attack', 5),
628
+ release_ms=compression.get('release', 100)
629
+ ))
630
+
631
+ # Add limiting if specified
632
+ if limiting:
633
+ chain.append(Limiter(
634
+ threshold_db=limiting.get('threshold', -1.0),
635
+ release_ms=limiting.get('release', 100)
636
+ ))
637
+
638
+ # Create and apply pedalboard
639
+ board = Pedalboard(chain)
640
+ processed = board(audio.T, sr)
641
+
642
+ # Save processed audio
643
+ sf.write(output_path, processed.T, sr)
644
+ logger.info(f"Saved custom EQ audio to {output_path}")
645
+
646
+ return output_path
647
+
648
+ except Exception as e:
649
+ logger.error(f"Error applying custom EQ: {str(e)}", exc_info=True)
650
+ raise
651
+
652
+ def get_preset_list(self) -> List[Dict]:
653
+ """Get list of available presets with descriptions"""
654
+ return [
655
+ {
656
+ 'id': key,
657
+ 'name': preset.name,
658
+ 'description': preset.description
659
+ }
660
+ for key, preset in self.PRESETS.items()
661
+ ]