File size: 5,248 Bytes
59603db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
"""
ASR模块的工具函数
包含音频预处理、格式转换等工具函数
"""

import numpy as np


def ensure_minimum_audio_duration(
        audio_array: np.ndarray, min_duration: float = 1.0, sample_rate: int = 16000
) -> np.ndarray:
    """
    确保音频数组满足最小时长要求,如果不足则用静音填充

    Args:
        audio_array: 输入音频数组
        min_duration: 最小时长要求(秒),默认1秒
        sample_rate: 采样率,默认16000Hz

    Returns:
        处理后的音频数组
    """
    audio_duration = audio_array.shape[-1] / sample_rate

    if audio_duration < min_duration:
        padding_seconds = min_duration - audio_duration
        audio_array = padding_silence(audio_array, padding_seconds, sample_rate)

    return audio_array


def padding_silence(
        audio_data: np.ndarray, duration_seconds: float, sample_rate: int = 16000
) -> np.ndarray:
    """
    为音频数据添加静音填充

    Args:
        audio_data: 原始音频数据
        duration_seconds: 需要填充的时长(秒)
        sample_rate: 采样率

    Returns:
        填充后的音频数据
    """
    frequency = 440.0
    duration = duration_seconds + 0.1
    t = np.linspace(
        0, duration, int(sample_rate * duration), endpoint=False, dtype=audio_data.dtype
    )
    silence = 0.5 * np.sin(2 * np.pi * frequency * t)
    audio_data = np.concatenate([audio_data, silence])
    return audio_data


def validate_audio_array(audio_array: np.ndarray) -> bool:
    """
    验证音频数组是否有效

    Args:
        audio_array: 音频数组

    Returns:
        bool: 是否为有效的音频数组
    """
    if audio_array is None:
        return False

    if not isinstance(audio_array, np.ndarray):
        return False

    if audio_array.size == 0:
        return False

    if len(audio_array.shape) > 2:
        return False

    return True


def normalize_audio(audio_array: np.ndarray, target_peak: float = 0.95) -> np.ndarray:
    """
    标准化音频数组的音量

    Args:
        audio_array: 输入音频数组
        target_peak: 目标峰值,默认0.95

    Returns:
        标准化后的音频数组
    """
    if not validate_audio_array(audio_array):
        raise ValueError("Invalid audio array")

    # 获取当前峰值
    current_peak = np.max(np.abs(audio_array))

    if current_peak == 0:
        return audio_array

    # 计算缩放因子
    scale_factor = target_peak / current_peak

    # 应用缩放
    normalized_audio = audio_array * scale_factor

    return normalized_audio


def convert_sample_rate(
        audio_array: np.ndarray,
        source_rate: int,
        target_rate: int
) -> np.ndarray:
    """
    转换音频采样率
    
    Args:
        audio_array: 输入音频数组
        source_rate: 源采样率
        target_rate: 目标采样率
    
    Returns:
        转换后的音频数组
    """
    if source_rate == target_rate:
        return audio_array

    try:
        import librosa
        return librosa.resample(audio_array, orig_sr=source_rate, target_sr=target_rate)
    except ImportError:
        # 如果没有librosa,使用简单的重采样
        ratio = target_rate / source_rate
        new_length = int(len(audio_array) * ratio)
        indices = np.linspace(0, len(audio_array) - 1, new_length)
        return np.interp(indices, np.arange(len(audio_array)), audio_array)


def trim_silence(
        audio_array: np.ndarray,
        threshold: float = 0.01,
        sample_rate: int = 16000
) -> np.ndarray:
    """
    修剪音频开头和结尾的静音部分
    
    Args:
        audio_array: 输入音频数组
        threshold: 静音检测阈值
        sample_rate: 采样率
    
    Returns:
        修剪后的音频数组
    """
    if not validate_audio_array(audio_array):
        return audio_array

    # 计算音频的绝对值
    audio_abs = np.abs(audio_array)

    # 找到非静音部分的开始和结束
    non_silent = audio_abs > threshold

    if not np.any(non_silent):
        # 如果全是静音,返回最小长度的音频
        min_samples = int(0.1 * sample_rate)  # 100ms
        return audio_array[:min_samples] if len(audio_array) > min_samples else audio_array

    # 找到第一个和最后一个非静音样本
    start_idx = np.argmax(non_silent)
    end_idx = len(non_silent) - np.argmax(non_silent[::-1])

    return audio_array[start_idx:end_idx]


def get_audio_duration(audio_array: np.ndarray, sample_rate: int = 16000) -> float:
    """
    获取音频时长(秒)
    
    Args:
        audio_array: 音频数组
        sample_rate: 采样率
    
    Returns:
        音频时长(秒)
    """
    if not validate_audio_array(audio_array):
        return 0.0

    return audio_array.shape[-1] / sample_rate


def create_silence(duration_seconds: float, sample_rate: int = 16000) -> np.ndarray:
    """
    创建指定时长的静音
    
    Args:
        duration_seconds: 静音时长(秒)
        sample_rate: 采样率
    
    Returns:
        静音音频数组
    """
    num_samples = int(duration_seconds * sample_rate)
    return np.zeros(num_samples, dtype=np.float32)