-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompression.py
More file actions
106 lines (86 loc) · 3.66 KB
/
Copy pathcompression.py
File metadata and controls
106 lines (86 loc) · 3.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import numpy as np
import librosa
import soundfile as sf
def compress_dynamic_range(audio, threshold=-20, ratio=4, attack=0.01, release=0.1, makeup_gain=0, sr=44100):
"""
Dynamic range compressor for audio signals
Parameters:
- audio: Input audio signal (numpy array)
- threshold: Threshold in dB below which compression is applied
- ratio: Compression ratio (higher = more compression)
- attack: Attack time in seconds (how quickly compression is applied)
- release: Release time in seconds (how quickly compression is released)
- makeup_gain: Makeup gain in dB to apply after compression
- sr: Sample rate
Returns:
- Compressed audio signal
"""
# Convert threshold to linear amplitude
threshold_linear = 10 ** (threshold / 20)
# Calculate attack and release coefficients
attack_samples = int(sr * attack)
release_samples = int(sr * release)
attack_coef = np.exp(-1 / attack_samples) if attack_samples > 0 else 0
release_coef = np.exp(-1 / release_samples) if release_samples > 0 else 0
# Prepare gain envelope
gain_envelope = np.ones_like(audio)
gain_smoothed = 1.0
# Calculate gain reduction for each sample
for i in range(len(audio)):
# Compute instantaneous amplitude
amplitude = abs(audio[i])
# Compute gain reduction needed if above threshold
if amplitude > threshold_linear:
gain_reduction = threshold_linear + (amplitude - threshold_linear) / ratio
gain = gain_reduction / amplitude if amplitude > 0 else 1.0
else:
gain = 1.0
# Apply attack and release time constants
if gain < gain_smoothed:
# Gain is decreasing (attack phase)
gain_smoothed = attack_coef * gain_smoothed + (1 - attack_coef) * gain
else:
# Gain is increasing (release phase)
gain_smoothed = release_coef * gain_smoothed + (1 - release_coef) * gain
gain_envelope[i] = gain_smoothed
# Apply the gain envelope to the audio
compressed_audio = audio * gain_envelope
# Apply makeup gain
makeup_linear = 10 ** (makeup_gain / 20)
compressed_audio = compressed_audio * makeup_linear
# Prevent clipping
compressed_audio = np.clip(compressed_audio, -1.0, 1.0)
return compressed_audio
def main():
"""
Example usage of the compressor
"""
# Load an audio file
input_file = "output/enhanced_test3.wav" # Replace with your file
output_file = "output/compressed_test3.wav"
print(f"Loading audio file: {input_file}")
audio, sr = librosa.load(input_file, sr=None)
# Compression settings
threshold = -20 # dB threshold
ratio = 4 # compression ratio
attack = 0.01 # 10ms attack time
release = 0.2 # 200ms release time
makeup_gain = 6 # 6dB makeup gain
print(f"Applying compression (threshold: {threshold}dB, ratio: {ratio}:1, makeup gain: {makeup_gain}dB)")
compressed = compress_dynamic_range(
audio,
threshold=threshold,
ratio=ratio,
attack=attack,
release=release,
makeup_gain=makeup_gain,
sr=sr
)
# Save the compressed audio
print(f"Saving compressed audio to: {output_file}")
sf.write(output_file, compressed, sr)
# Print some stats about the audio before and after compression
print(f"Original audio - Peak: {np.max(np.abs(audio)):.2f}, RMS: {np.sqrt(np.mean(audio**2)):.4f}")
print(f"Compressed audio - Peak: {np.max(np.abs(compressed)):.2f}, RMS: {np.sqrt(np.mean(compressed**2)):.4f}")
if __name__ == "__main__":
main()