fix&feat: hiển thị tools chỉnh sửa audioclip

This commit is contained in:
2026-07-19 10:19:25 +07:00
parent 615e0e8530
commit 95dc9346ef
6 changed files with 5146 additions and 36 deletions
+51
View File
@@ -31,6 +31,57 @@ class SubTabDSPEngine:
gain = target_amplitude / max_amplitude
return y * gain
@staticmethod
def apply_volume_automation_envelope(y: np.ndarray, sr: int, nodes: list) -> np.ndarray:
"""
Applies a user-drawn volume automation envelope onto an acoustic signal NumPy array.
nodes: A list of point dictionaries, e.g., [{"time": 0.0, "db": 0.0}, {"time": 2.5, "db": -12.0}, ...]
"""
if not nodes:
return y
# Sort envelope nodes chronologically by time axis
nodes = sorted(nodes, key=lambda x: x["time"])
# 1. Map node variables into distinct coordinates arrays
node_times = np.array([node["time"] for node in nodes])
node_dbs = np.array([node["db"] for node in nodes])
# Hard-clamp boundary constraints matching the operational floor [-30.0dB, +3.0dB]
node_dbs = np.clip(node_dbs, -30.0, 3.0)
# 2. Evaluate absolute timeline timestamps for every index position inside the signal array
total_samples = len(y)
sample_times = np.arange(total_samples) / sr
# 3. Linearly interpolate localized decibel thresholds across every single sample step
# Handle edge cases for interpolation: if sample_times is outside node_times range,
# np.interp uses the first/last value of node_dbs.
interpolated_dbs = np.interp(sample_times, node_times, node_dbs, left=node_dbs[0], right=node_dbs[-1])
# 4. Map logarithmic values into standard linear gain scale arrays
linear_gains = 10.0 ** (interpolated_dbs / 20.0)
# 5. Multiply the raw amplitude vector array by the linear gain modifier mask
return y * linear_gains
@staticmethod
def pitch_shift(y: np.ndarray, sr: int, n_steps: float) -> np.ndarray:
"""
Shift the pitch of an audio signal by a specified number of semitones.
Args:
y: Input audio signal
sr: Sample rate
n_steps: Number of semitones to shift (positive = higher pitch, negative = lower pitch)
Returns:
Pitch-shifted audio signal
"""
if n_steps == 0:
return y
return librosa.effects.pitch_shift(y, sr=sr, n_steps=n_steps)
@staticmethod
def merge_back_to_parent(
parent_track_audio: np.ndarray,