import numpy as np import wave import sys import tkinter as tk from tkinter import filedialog import os # ================= НАСТРОЙКИ ================= FS = 12500 # Частота дискретизации (должна совпадать с записью) ADC_BITS = 24 # Разрядность исходных данных # 📢 КОЭФФИЦИЕНТ УСИЛЕНИЯ (GAIN) # 1.0 = без изменений # 10.0 = усилить в 10 раз (20 дБ) # 100.0 = усилить в 100 раз (40 дБ) GAIN = 5 # Разрядность WAV. Пишется обычный PCM: float-WAV открывают далеко не все # программы, а 64-битный float, который получался раньше, -- почти никакие. # 16 -- открывается везде; 24 -- полная разрядность записи WAV_BITS = 16 def convert_bin_to_wav(input_filename, output_filename, gain): print(f"Чтение файла: {os.path.basename(input_filename)}...") # --- 1. Чтение 24-битного Big Endian файла --- # (Используем ту же логику чтения, что и в анализаторе) raw = np.fromfile(input_filename, dtype=np.uint8) n_samples = len(raw) // 3 raw = raw[:n_samples * 3] data = raw.reshape(-1, 3) # Сборка 3 байт в int32 samples = (data[:, 0].astype(np.int32) << 16) | \ (data[:, 1].astype(np.int32) << 8) | \ data[:, 2].astype(np.int32) # Обработка знака (Two's complement) mask = (samples & 0x800000) != 0 samples[mask] -= 0x1000000 # --- 2. Нормализация (перевод в диапазон -1.0 ... 1.0) --- # Сразу float64: numpy 1.x всё равно приводит к нему при делении на 8388607 max_val = 2 ** (ADC_BITS - 1) - 1 # 8,388,607 audio_float = samples.astype(np.float64) / max_val # Убираем постоянную составляющую (DC Offset), чтобы динамик не "выпирало" audio_float -= np.mean(audio_float) # --- 3. Применение усиления --- print(f"Применяем усиление: x{gain}") audio_float *= gain # --- 4. Проверка на клиппинг (перегрузку) --- max_amp = np.max(np.abs(audio_float)) if max_amp > 1.0: clipped_samples = np.sum(np.abs(audio_float) > 1.0) percent_clipped = (clipped_samples / len(audio_float)) * 100 print(f"ВНИМАНИЕ: Перегрузка сигнала! Пик: {max_amp:.2f}") print(f" Будет обрезано {percent_clipped:.2f}% сэмплов (Hard Clipping).") print(" Рекомендуется уменьшить GAIN.") # Обрезаем все, что выше 1.0 или ниже -1.0 audio_float = np.clip(audio_float, -1.0, 1.0) else: print(f"Сигнал в норме. Пиковый уровень: {max_amp:.2f} (из 1.0)") # --- 5. Сохранение WAV (PCM) --- print(f"Сохранение в WAV ({WAV_BITS}-bit PCM, {FS} Гц)...") full = 2 ** (WAV_BITS - 1) - 1 pcm = np.round(audio_float * full).astype(" 1: input_path = sys.argv[1] else: root = tk.Tk() root.withdraw() input_path = filedialog.askopenfilename( title="Выберите .bin файл для конвертации", filetypes=[("Binary files", "*.bin")] ) if input_path: # Формируем имя выходного файла folder = os.path.dirname(input_path) name = os.path.basename(input_path).rsplit('.', 1)[0] output_path = os.path.join(folder, f"{name}_gain{GAIN}.wav") try: convert_bin_to_wav(input_path, output_path, GAIN) except Exception as e: print(f"Ошибка при конвертации: {e}")