Spaces:
Running
on
Zero
Running
on
Zero
| from pydub import AudioSegment | |
| import numpy as np | |
| def write_audio_file(output_file_path, numpy_array, sample_rate, output_format, bitrate): | |
| """ | |
| Записывает аудиофайл из numpy массива в указанном формате с помощью pydub. | |
| Параметры: | |
| output_file_path (str): Путь для сохранения файла (без расширения) | |
| numpy_array (numpy.ndarray): Аудиоданные в виде numpy массива | |
| sample_rate (int): Частота дискретизации (в Гц) | |
| output_format (str): Формат выходного файла ('mp3', 'flac', 'wav', 'aiff', 'm4a', 'aac', 'ogg', 'opus') | |
| encoder_settings (dict, optional): Cловарь с настройками кодировки аудио | |
| """ | |
| try: | |
| # Проверка и нормализация входных данных | |
| if not isinstance(numpy_array, np.ndarray): | |
| raise ValueError("Input must be a numpy array") | |
| # Преобразование в правильную форму (samples, channels) | |
| if len(numpy_array.shape) == 1: | |
| numpy_array = numpy_array.reshape(-1, 1) # Моно | |
| elif len(numpy_array.shape) == 2: | |
| if numpy_array.shape[0] == 2: # Если (channels, samples) | |
| numpy_array = numpy_array.T # Транспонируем в (samples, channels) | |
| else: | |
| raise ValueError("Input array must be 1D or 2D") | |
| # Нормализация до диапазона [-1.0, 1.0] если нужно | |
| if np.issubdtype(numpy_array.dtype, np.floating): | |
| numpy_array = np.clip(numpy_array, -1.0, 1.0) | |
| numpy_array = (numpy_array * 32767).astype(np.int16) | |
| elif numpy_array.dtype != np.int16: | |
| numpy_array = numpy_array.astype(np.int16) | |
| # Создание AudioSegment | |
| if numpy_array.shape[1] == 1: # Моно | |
| audio_segment = AudioSegment( | |
| numpy_array.tobytes(), | |
| frame_rate=sample_rate, | |
| sample_width=2, # 16-bit = 2 bytes | |
| channels=1 | |
| ) | |
| else: # Стерео | |
| # Для стерео нужно чередовать байты левого и правого каналов | |
| interleaved = np.empty((numpy_array.shape[0] * 2,), dtype=np.int16) | |
| interleaved[0::2] = numpy_array[:, 0] # Левый канал | |
| interleaved[1::2] = numpy_array[:, 1] # Правый канал | |
| audio_segment = AudioSegment( | |
| interleaved.tobytes(), | |
| frame_rate=sample_rate, | |
| sample_width=2, | |
| channels=2 | |
| ) | |
| # Формирование параметров экспорта | |
| parameters = {} | |
| if bitrate: | |
| parameters['bitrate'] = bitrate | |
| # Поддержка различных форматов | |
| format_mapping = { | |
| 'mp3': 'mp3', | |
| 'flac': 'flac', | |
| 'wav': 'wav', | |
| 'aiff': 'aiff', | |
| 'm4a': 'ipod', # для m4a в pydub используется кодек ipod | |
| 'aac': 'adts', # для aac в pydub используется adts | |
| 'ogg': 'ogg', | |
| 'opus': 'opus' | |
| } | |
| if output_format not in format_mapping: | |
| raise ValueError(f"Unsupported format: {output_format}. Supported formats are: {list(format_mapping.keys())}") | |
| # Добавление расширения файла, если его нет | |
| if not output_file_path.lower().endswith(f'.{output_format}'): | |
| output_file_path = f"{output_file_path}.{output_format}" | |
| # Экспорт в нужный формат | |
| audio_segment.export(output_file_path, format=format_mapping[output_format], **parameters) | |
| except Exception as e: | |
| raise RuntimeError(f"Error writing audio file: {str(e)}") |