""" Audio mastering service with industry-standard presets using Pedalboard """ import os import logging import numpy as np from pathlib import Path from typing import Dict, List, Optional import soundfile as sf from pedalboard import ( Pedalboard, Compressor, Limiter, Gain, HighpassFilter, LowpassFilter, PeakFilter, LowShelfFilter, HighShelfFilter, Reverb, Chorus, Delay ) logger = logging.getLogger(__name__) class MasteringPreset: """Mastering preset configuration""" def __init__(self, name: str, description: str, chain: List): self.name = name self.description = description self.chain = chain class MasteringService: """Audio mastering and EQ service""" # Industry-standard mastering presets PRESETS = { # Clean/Transparent Presets "clean_master": MasteringPreset( "Clean Master", "Transparent mastering with gentle compression", [ HighpassFilter(cutoff_frequency_hz=30), PeakFilter(cutoff_frequency_hz=100, gain_db=-1, q=0.7), PeakFilter(cutoff_frequency_hz=3000, gain_db=0.5, q=1.0), PeakFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7), Compressor(threshold_db=-12, ratio=2.0, attack_ms=5, release_ms=100), Limiter(threshold_db=-1.0, release_ms=100) ] ), "subtle_warmth": MasteringPreset( "Subtle Warmth", "Gentle low-end enhancement with smooth highs", [ HighpassFilter(cutoff_frequency_hz=25), LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.5, q=0.7), PeakFilter(cutoff_frequency_hz=200, gain_db=0.8, q=0.5), PeakFilter(cutoff_frequency_hz=8000, gain_db=-0.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=12000, gain_db=1.0, q=0.7), Compressor(threshold_db=-15, ratio=2.5, attack_ms=10, release_ms=150), Limiter(threshold_db=-0.5, release_ms=100) ] ), # Pop/Commercial Presets "modern_pop": MasteringPreset( "Modern Pop", "Radio-ready pop sound with punchy compression", [ HighpassFilter(cutoff_frequency_hz=35), PeakFilter(cutoff_frequency_hz=80, gain_db=-1.5, q=0.8), LowShelfFilter(cutoff_frequency_hz=120, gain_db=2.0, q=0.7), PeakFilter(cutoff_frequency_hz=2500, gain_db=1.5, q=1.2), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=0.7), Compressor(threshold_db=-10, ratio=4.0, attack_ms=3, release_ms=80), Limiter(threshold_db=-0.3, release_ms=50) ] ), "radio_ready": MasteringPreset( "Radio Ready", "Maximum loudness for commercial radio", [ HighpassFilter(cutoff_frequency_hz=40), PeakFilter(cutoff_frequency_hz=60, gain_db=-2.0, q=1.0), LowShelfFilter(cutoff_frequency_hz=150, gain_db=1.5, q=0.8), PeakFilter(cutoff_frequency_hz=3000, gain_db=2.0, q=1.5), PeakFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.0, q=0.7), Compressor(threshold_db=-8, ratio=6.0, attack_ms=2, release_ms=60), Limiter(threshold_db=-0.1, release_ms=30) ] ), "punchy_commercial": MasteringPreset( "Punchy Commercial", "Aggressive punch for mainstream appeal", [ HighpassFilter(cutoff_frequency_hz=30), PeakFilter(cutoff_frequency_hz=100, gain_db=-2.0, q=1.2), LowShelfFilter(cutoff_frequency_hz=200, gain_db=2.5, q=0.7), PeakFilter(cutoff_frequency_hz=1000, gain_db=-1.0, q=0.8), PeakFilter(cutoff_frequency_hz=4000, gain_db=2.5, q=1.5), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.8), Compressor(threshold_db=-9, ratio=5.0, attack_ms=1, release_ms=50), Limiter(threshold_db=-0.2, release_ms=40) ] ), # Rock/Alternative Presets "rock_master": MasteringPreset( "Rock Master", "Powerful rock sound with emphasis on mids", [ HighpassFilter(cutoff_frequency_hz=35), LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.0, q=0.7), PeakFilter(cutoff_frequency_hz=400, gain_db=1.5, q=1.0), PeakFilter(cutoff_frequency_hz=2000, gain_db=2.0, q=1.2), PeakFilter(cutoff_frequency_hz=5000, gain_db=1.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=8000, gain_db=1.0, q=0.8), Compressor(threshold_db=-12, ratio=3.5, attack_ms=5, release_ms=120), Limiter(threshold_db=-0.5, release_ms=80) ] ), "metal_aggressive": MasteringPreset( "Metal Aggressive", "Heavy, aggressive metal mastering", [ HighpassFilter(cutoff_frequency_hz=40), PeakFilter(cutoff_frequency_hz=80, gain_db=-1.5, q=1.0), LowShelfFilter(cutoff_frequency_hz=150, gain_db=2.0, q=0.8), PeakFilter(cutoff_frequency_hz=800, gain_db=-1.5, q=1.2), PeakFilter(cutoff_frequency_hz=3000, gain_db=3.0, q=1.5), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=0.7), Compressor(threshold_db=-8, ratio=6.0, attack_ms=1, release_ms=50), Limiter(threshold_db=-0.1, release_ms=30) ] ), "indie_rock": MasteringPreset( "Indie Rock", "Lo-fi character with mid presence", [ HighpassFilter(cutoff_frequency_hz=30), LowShelfFilter(cutoff_frequency_hz=120, gain_db=0.5, q=0.7), PeakFilter(cutoff_frequency_hz=500, gain_db=1.5, q=1.0), PeakFilter(cutoff_frequency_hz=2500, gain_db=2.0, q=1.2), PeakFilter(cutoff_frequency_hz=7000, gain_db=-0.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=0.5, q=0.8), Compressor(threshold_db=-14, ratio=3.0, attack_ms=8, release_ms=150), Limiter(threshold_db=-0.8, release_ms=100) ] ), # Electronic/EDM Presets "edm_club": MasteringPreset( "EDM Club", "Powerful club sound with deep bass", [ HighpassFilter(cutoff_frequency_hz=25), LowShelfFilter(cutoff_frequency_hz=80, gain_db=3.0, q=0.7), PeakFilter(cutoff_frequency_hz=150, gain_db=2.0, q=0.8), PeakFilter(cutoff_frequency_hz=1000, gain_db=-1.5, q=1.0), PeakFilter(cutoff_frequency_hz=5000, gain_db=2.0, q=1.2), HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.0, q=0.7), Compressor(threshold_db=-6, ratio=8.0, attack_ms=0.5, release_ms=40), Limiter(threshold_db=0.0, release_ms=20) ] ), "house_groovy": MasteringPreset( "House Groovy", "Smooth house music with rolling bass", [ HighpassFilter(cutoff_frequency_hz=30), LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.5, q=0.7), PeakFilter(cutoff_frequency_hz=250, gain_db=1.0, q=0.8), PeakFilter(cutoff_frequency_hz=2000, gain_db=0.5, q=1.0), PeakFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.7), Compressor(threshold_db=-10, ratio=4.0, attack_ms=2, release_ms=60), Limiter(threshold_db=-0.2, release_ms=40) ] ), "techno_dark": MasteringPreset( "Techno Dark", "Dark, pounding techno master", [ HighpassFilter(cutoff_frequency_hz=35), PeakFilter(cutoff_frequency_hz=60, gain_db=2.0, q=1.0), LowShelfFilter(cutoff_frequency_hz=120, gain_db=1.5, q=0.8), PeakFilter(cutoff_frequency_hz=800, gain_db=-2.0, q=1.5), PeakFilter(cutoff_frequency_hz=4000, gain_db=1.0, q=1.0), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=-0.5, q=0.8), Compressor(threshold_db=-8, ratio=6.0, attack_ms=1, release_ms=50), Limiter(threshold_db=-0.1, release_ms=30) ] ), "dubstep_heavy": MasteringPreset( "Dubstep Heavy", "Sub-bass focused with crispy highs", [ HighpassFilter(cutoff_frequency_hz=20), PeakFilter(cutoff_frequency_hz=50, gain_db=3.5, q=1.2), LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.5, q=0.8), PeakFilter(cutoff_frequency_hz=500, gain_db=-2.0, q=1.5), PeakFilter(cutoff_frequency_hz=6000, gain_db=2.5, q=1.2), HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.5, q=0.7), Compressor(threshold_db=-6, ratio=10.0, attack_ms=0.3, release_ms=30), Limiter(threshold_db=0.0, release_ms=20) ] ), # Hip-Hop/R&B Presets "hiphop_modern": MasteringPreset( "Hip-Hop Modern", "Contemporary hip-hop with deep bass", [ HighpassFilter(cutoff_frequency_hz=25), LowShelfFilter(cutoff_frequency_hz=80, gain_db=2.5, q=0.7), PeakFilter(cutoff_frequency_hz=150, gain_db=1.5, q=0.8), PeakFilter(cutoff_frequency_hz=1000, gain_db=-1.0, q=1.0), PeakFilter(cutoff_frequency_hz=3500, gain_db=2.0, q=1.2), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.5, q=0.7), Compressor(threshold_db=-10, ratio=4.0, attack_ms=5, release_ms=80), Limiter(threshold_db=-0.3, release_ms=60) ] ), "trap_808": MasteringPreset( "Trap 808", "808-focused trap mastering", [ HighpassFilter(cutoff_frequency_hz=20), PeakFilter(cutoff_frequency_hz=50, gain_db=3.0, q=1.0), LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.0, q=0.7), PeakFilter(cutoff_frequency_hz=800, gain_db=-1.5, q=1.2), PeakFilter(cutoff_frequency_hz=5000, gain_db=2.5, q=1.2), HighShelfFilter(cutoff_frequency_hz=12000, gain_db=2.0, q=0.7), Compressor(threshold_db=-8, ratio=5.0, attack_ms=3, release_ms=60), Limiter(threshold_db=-0.2, release_ms=40) ] ), "rnb_smooth": MasteringPreset( "R&B Smooth", "Silky smooth R&B sound", [ HighpassFilter(cutoff_frequency_hz=30), LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.5, q=0.7), PeakFilter(cutoff_frequency_hz=300, gain_db=1.0, q=0.8), PeakFilter(cutoff_frequency_hz=2000, gain_db=0.5, q=1.0), PeakFilter(cutoff_frequency_hz=6000, gain_db=1.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.7), Compressor(threshold_db=-12, ratio=3.0, attack_ms=8, release_ms=120), Limiter(threshold_db=-0.5, release_ms=80) ] ), # Acoustic/Organic Presets "acoustic_natural": MasteringPreset( "Acoustic Natural", "Natural, transparent acoustic sound", [ HighpassFilter(cutoff_frequency_hz=25), LowShelfFilter(cutoff_frequency_hz=100, gain_db=0.5, q=0.7), PeakFilter(cutoff_frequency_hz=500, gain_db=0.8, q=0.8), PeakFilter(cutoff_frequency_hz=3000, gain_db=1.0, q=1.0), HighShelfFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=0.7), Compressor(threshold_db=-16, ratio=2.0, attack_ms=15, release_ms=200), Limiter(threshold_db=-1.0, release_ms=120) ] ), "folk_warm": MasteringPreset( "Folk Warm", "Warm, intimate folk sound", [ HighpassFilter(cutoff_frequency_hz=30), LowShelfFilter(cutoff_frequency_hz=150, gain_db=1.0, q=0.7), PeakFilter(cutoff_frequency_hz=400, gain_db=1.5, q=0.8), PeakFilter(cutoff_frequency_hz=2500, gain_db=1.0, q=1.0), PeakFilter(cutoff_frequency_hz=7000, gain_db=-0.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.8), Compressor(threshold_db=-18, ratio=2.5, attack_ms=20, release_ms=250), Limiter(threshold_db=-1.5, release_ms=150) ] ), "jazz_vintage": MasteringPreset( "Jazz Vintage", "Classic jazz warmth and space", [ HighpassFilter(cutoff_frequency_hz=35), LowShelfFilter(cutoff_frequency_hz=120, gain_db=1.0, q=0.7), PeakFilter(cutoff_frequency_hz=500, gain_db=1.0, q=0.8), PeakFilter(cutoff_frequency_hz=2000, gain_db=0.5, q=0.8), PeakFilter(cutoff_frequency_hz=8000, gain_db=-1.0, q=1.0), HighShelfFilter(cutoff_frequency_hz=12000, gain_db=0.5, q=0.8), Compressor(threshold_db=-20, ratio=2.0, attack_ms=25, release_ms=300), Limiter(threshold_db=-2.0, release_ms=180) ] ), # Classical/Orchestral Presets "orchestral_wide": MasteringPreset( "Orchestral Wide", "Wide, natural orchestral sound", [ HighpassFilter(cutoff_frequency_hz=20), LowShelfFilter(cutoff_frequency_hz=80, gain_db=0.5, q=0.7), PeakFilter(cutoff_frequency_hz=300, gain_db=0.5, q=0.7), PeakFilter(cutoff_frequency_hz=4000, gain_db=0.8, q=0.8), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7), Compressor(threshold_db=-24, ratio=1.5, attack_ms=30, release_ms=400), Limiter(threshold_db=-3.0, release_ms=250) ] ), "classical_concert": MasteringPreset( "Classical Concert", "Concert hall ambience and dynamics", [ HighpassFilter(cutoff_frequency_hz=25), PeakFilter(cutoff_frequency_hz=200, gain_db=0.5, q=0.7), PeakFilter(cutoff_frequency_hz=1000, gain_db=0.3, q=0.8), PeakFilter(cutoff_frequency_hz=6000, gain_db=0.8, q=0.8), HighShelfFilter(cutoff_frequency_hz=12000, gain_db=0.5, q=0.7), Compressor(threshold_db=-30, ratio=1.2, attack_ms=50, release_ms=500), Limiter(threshold_db=-4.0, release_ms=300) ] ), # Ambient/Atmospheric Presets "ambient_spacious": MasteringPreset( "Ambient Spacious", "Wide, spacious ambient master", [ HighpassFilter(cutoff_frequency_hz=25), LowShelfFilter(cutoff_frequency_hz=100, gain_db=0.5, q=0.7), PeakFilter(cutoff_frequency_hz=500, gain_db=-0.5, q=0.8), PeakFilter(cutoff_frequency_hz=3000, gain_db=0.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=8000, gain_db=1.5, q=0.7), Compressor(threshold_db=-20, ratio=2.0, attack_ms=50, release_ms=400), Limiter(threshold_db=-2.0, release_ms=200) ] ), "cinematic_epic": MasteringPreset( "Cinematic Epic", "Big, powerful cinematic sound", [ HighpassFilter(cutoff_frequency_hz=30), LowShelfFilter(cutoff_frequency_hz=100, gain_db=2.0, q=0.7), PeakFilter(cutoff_frequency_hz=250, gain_db=1.0, q=0.8), PeakFilter(cutoff_frequency_hz=2000, gain_db=1.5, q=1.0), PeakFilter(cutoff_frequency_hz=6000, gain_db=2.0, q=1.0), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=0.7), Compressor(threshold_db=-14, ratio=3.0, attack_ms=10, release_ms=150), Limiter(threshold_db=-0.5, release_ms=100) ] ), # Vintage/Lo-Fi Presets "lofi_chill": MasteringPreset( "Lo-Fi Chill", "Vintage lo-fi character", [ HighpassFilter(cutoff_frequency_hz=50), LowpassFilter(cutoff_frequency_hz=10000), LowShelfFilter(cutoff_frequency_hz=150, gain_db=1.5, q=0.7), PeakFilter(cutoff_frequency_hz=800, gain_db=-1.0, q=1.2), PeakFilter(cutoff_frequency_hz=4000, gain_db=-1.5, q=1.0), Compressor(threshold_db=-12, ratio=3.0, attack_ms=15, release_ms=180), Limiter(threshold_db=-1.0, release_ms=120) ] ), "vintage_vinyl": MasteringPreset( "Vintage Vinyl", "Classic vinyl record warmth", [ HighpassFilter(cutoff_frequency_hz=40), LowpassFilter(cutoff_frequency_hz=12000), LowShelfFilter(cutoff_frequency_hz=120, gain_db=2.0, q=0.7), PeakFilter(cutoff_frequency_hz=1000, gain_db=-0.5, q=0.8), PeakFilter(cutoff_frequency_hz=5000, gain_db=-1.0, q=1.0), HighShelfFilter(cutoff_frequency_hz=8000, gain_db=-1.5, q=0.8), Compressor(threshold_db=-16, ratio=2.5, attack_ms=20, release_ms=200), Limiter(threshold_db=-1.5, release_ms=150) ] ), "retro_80s": MasteringPreset( "Retro 80s", "1980s-inspired mix with character", [ HighpassFilter(cutoff_frequency_hz=45), LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.5, q=0.7), PeakFilter(cutoff_frequency_hz=800, gain_db=1.0, q=1.2), PeakFilter(cutoff_frequency_hz=3000, gain_db=1.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=2.0, q=0.7), Compressor(threshold_db=-14, ratio=3.5, attack_ms=5, release_ms=100), Limiter(threshold_db=-0.8, release_ms=80) ] ), # Enhancement Presets (Phase 2) "harmonic_enhance": MasteringPreset( "Harmonic Enhance", "Adds subtle harmonic overtones for brightness and warmth", [ HighpassFilter(cutoff_frequency_hz=30), # Subtle low-end warmth LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.0, q=0.7), # Presence boost PeakFilter(cutoff_frequency_hz=3000, gain_db=1.5, q=1.0), # Air and clarity HighShelfFilter(cutoff_frequency_hz=8000, gain_db=2.0, q=0.7), # Gentle saturation effect through compression Compressor(threshold_db=-18, ratio=2.5, attack_ms=10, release_ms=120), # Final limiting Limiter(threshold_db=-0.5, release_ms=100), # Note: Additional harmonic generation would require Distortion plugin # which adds subtle harmonic overtones ] ), # Specialized Presets "vocal_focused": MasteringPreset( "Vocal Focused", "Emphasizes vocal clarity and presence", [ HighpassFilter(cutoff_frequency_hz=30), PeakFilter(cutoff_frequency_hz=200, gain_db=-1.0, q=0.8), PeakFilter(cutoff_frequency_hz=1000, gain_db=1.0, q=1.0), PeakFilter(cutoff_frequency_hz=3000, gain_db=2.5, q=1.2), PeakFilter(cutoff_frequency_hz=5000, gain_db=1.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7), Compressor(threshold_db=-12, ratio=3.0, attack_ms=5, release_ms=100), Limiter(threshold_db=-0.5, release_ms=80) ] ), "bass_heavy": MasteringPreset( "Bass Heavy", "Maximum low-end power", [ HighpassFilter(cutoff_frequency_hz=20), LowShelfFilter(cutoff_frequency_hz=60, gain_db=4.0, q=0.7), PeakFilter(cutoff_frequency_hz=100, gain_db=2.5, q=0.8), PeakFilter(cutoff_frequency_hz=500, gain_db=-1.5, q=1.0), PeakFilter(cutoff_frequency_hz=4000, gain_db=1.0, q=1.0), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.5, q=0.7), Compressor(threshold_db=-10, ratio=4.0, attack_ms=10, release_ms=100), Limiter(threshold_db=-0.3, release_ms=60) ] ), "bright_airy": MasteringPreset( "Bright & Airy", "Crystal clear highs with airiness", [ HighpassFilter(cutoff_frequency_hz=30), LowShelfFilter(cutoff_frequency_hz=100, gain_db=-0.5, q=0.7), PeakFilter(cutoff_frequency_hz=500, gain_db=-1.0, q=0.8), PeakFilter(cutoff_frequency_hz=5000, gain_db=2.0, q=1.0), PeakFilter(cutoff_frequency_hz=10000, gain_db=2.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=12000, gain_db=3.0, q=0.7), Compressor(threshold_db=-14, ratio=2.5, attack_ms=8, release_ms=120), Limiter(threshold_db=-0.8, release_ms=100) ] ), "midrange_punch": MasteringPreset( "Midrange Punch", "Powerful mids for presence", [ HighpassFilter(cutoff_frequency_hz=30), LowShelfFilter(cutoff_frequency_hz=100, gain_db=0.5, q=0.7), PeakFilter(cutoff_frequency_hz=500, gain_db=2.0, q=1.0), PeakFilter(cutoff_frequency_hz=1500, gain_db=2.5, q=1.2), PeakFilter(cutoff_frequency_hz=3000, gain_db=2.0, q=1.0), HighShelfFilter(cutoff_frequency_hz=8000, gain_db=0.5, q=0.7), Compressor(threshold_db=-11, ratio=3.5, attack_ms=5, release_ms=90), Limiter(threshold_db=-0.5, release_ms=70) ] ), "dynamic_range": MasteringPreset( "Dynamic Range", "Preserves maximum dynamics", [ HighpassFilter(cutoff_frequency_hz=25), PeakFilter(cutoff_frequency_hz=100, gain_db=-0.5, q=0.7), PeakFilter(cutoff_frequency_hz=3000, gain_db=0.5, q=0.8), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.0, q=0.7), Compressor(threshold_db=-20, ratio=1.5, attack_ms=20, release_ms=250), Limiter(threshold_db=-2.0, release_ms=200) ] ), "streaming_optimized": MasteringPreset( "Streaming Optimized", "Optimized for streaming platforms (Spotify, Apple Music)", [ HighpassFilter(cutoff_frequency_hz=30), LowShelfFilter(cutoff_frequency_hz=100, gain_db=1.0, q=0.7), PeakFilter(cutoff_frequency_hz=500, gain_db=0.5, q=0.8), PeakFilter(cutoff_frequency_hz=3000, gain_db=1.5, q=1.0), HighShelfFilter(cutoff_frequency_hz=10000, gain_db=1.5, q=0.7), Compressor(threshold_db=-14, ratio=3.0, attack_ms=5, release_ms=100), Limiter(threshold_db=-1.0, release_ms=100) ] ) } def __init__(self): """Initialize mastering service""" logger.info("Mastering service initialized with 32 presets") def apply_preset(self, audio_path: str, preset_name: str, output_path: str) -> str: """ Apply mastering preset to audio file Args: audio_path: Path to input audio file preset_name: Name of preset to apply output_path: Path to save processed audio Returns: Path to processed audio file """ try: if preset_name not in self.PRESETS: raise ValueError(f"Unknown preset: {preset_name}") preset = self.PRESETS[preset_name] logger.info(f"Applying preset '{preset.name}' to {audio_path}") # Load audio audio, sr = sf.read(audio_path) # Ensure stereo if len(audio.shape) == 1: audio = np.stack([audio, audio], axis=1) # Create pedalboard with preset chain board = Pedalboard(preset.chain) # Process audio processed = board(audio.T, sr) # Save processed audio sf.write(output_path, processed.T, sr) logger.info(f"Saved mastered audio to {output_path}") return output_path except Exception as e: logger.error(f"Error applying preset: {str(e)}", exc_info=True) raise def apply_custom_eq( self, audio_path: str, output_path: str, eq_bands: List[Dict], compression: Optional[Dict] = None, limiting: Optional[Dict] = None ) -> str: """ Apply custom EQ settings to audio file Args: audio_path: Path to input audio file output_path: Path to save processed audio eq_bands: List of EQ band settings compression: Compression settings (optional) limiting: Limiter settings (optional) Returns: Path to processed audio file """ try: logger.info(f"Applying custom EQ to {audio_path}") # Load audio audio, sr = sf.read(audio_path) # Ensure stereo if len(audio.shape) == 1: audio = np.stack([audio, audio], axis=1) # Build processing chain chain = [] # Add EQ bands for band in eq_bands: band_type = band.get('type', 'peak') freq = band.get('frequency', 1000) gain = band.get('gain', 0) q = band.get('q', 1.0) if band_type == 'highpass': chain.append(HighpassFilter(cutoff_frequency_hz=freq)) elif band_type == 'lowpass': chain.append(LowpassFilter(cutoff_frequency_hz=freq)) elif band_type == 'lowshelf': chain.append(LowShelfFilter(cutoff_frequency_hz=freq, gain_db=gain, q=q)) elif band_type == 'highshelf': chain.append(HighShelfFilter(cutoff_frequency_hz=freq, gain_db=gain, q=q)) else: # peak chain.append(PeakFilter(cutoff_frequency_hz=freq, gain_db=gain, q=q)) # Add compression if specified if compression: chain.append(Compressor( threshold_db=compression.get('threshold', -12), ratio=compression.get('ratio', 2.0), attack_ms=compression.get('attack', 5), release_ms=compression.get('release', 100) )) # Add limiting if specified if limiting: chain.append(Limiter( threshold_db=limiting.get('threshold', -1.0), release_ms=limiting.get('release', 100) )) # Create and apply pedalboard board = Pedalboard(chain) processed = board(audio.T, sr) # Save processed audio sf.write(output_path, processed.T, sr) logger.info(f"Saved custom EQ audio to {output_path}") return output_path except Exception as e: logger.error(f"Error applying custom EQ: {str(e)}", exc_info=True) raise def get_preset_list(self) -> List[Dict]: """Get list of available presets with descriptions""" return [ { 'id': key, 'name': preset.name, 'description': preset.description } for key, preset in self.PRESETS.items() ]