批量检测指定目录下所有 .mp3 和 .wav 文件的 声道数(单/双声道) 和 采样率(Hz)

批量检测指定目录下所有 .mp3 和 .wav 文件的 声道数(单/双声道) 和 采样率(Hz)。

🔧 脚本:check_audio_info.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
批量检测音频文件声道数与采样率
支持格式:.mp3 / .wav
用法示例:
    python check_audio_info.py ./audios/
"""

import os
import sys
import glob
from pydub import AudioSegment

def check_audio_info(file_path: str):
    """读取单个音频文件的声道数与采样率"""
    ext = os.path.splitext(file_path)[1].lower()
    if ext not in ['.mp3', '.wav']:
        print(f"跳过不支持的格式: {file_path}")
        return

    try:
        audio = AudioSegment.from_file(file_path)
        channels = audio.channels
        sample_rate = audio.frame_rate

        print(f"🎵 文件: {os.path.basename(file_path)}")
        print(f"   ├─ 声道数: {channels} ({'单声道' if channels == 1 else '立体声'})")
        print(f"   └─ 采样率: {sample_rate} Hz\n")

    except Exception as e:
        print(f"❌ 读取文件出错: {file_path}")
        print(f"   错误信息: {e}\n")

def scan_directory(folder_path: str):
    """扫描文件夹内所有音频文件"""
    folder_path = os.path.abspath(folder_path)
    print(f"📂 正在扫描文件夹: {folder_path}\n")

    files = glob.glob(os.path.join(folder_path, "**/*.mp3"), recursive=True) \
          + glob.glob(os.path.join(folder_path, "**/*.wav"), recursive=True)

    if not files:
        print("⚠️ 没有找到音频文件 (.mp3 / .wav)")
        return

    for file_path in files:
        check_audio_info(file_path)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("用法: python check_audio_info.py <目录路径>")
        sys.exit(1)

    folder = sys.argv[1]
    if not os.path.isdir(folder):
        print(f"❌ 路径无效: {folder}")
        sys.exit(1)

    scan_directory(folder)

📦 安装依赖

pip install pydub ffmpeg-python
# 系统必须安装 ffmpeg,可通过以下命令安装:
# macOS: brew install ffmpeg
# Ubuntu: apt-get install ffmpeg

🧩 使用示例

python check_audio_info.py ./samples/

输出示例:

📂 正在扫描文件夹: /Users/meixiu/samples/

🎵 文件: voice1.wav
   ├─ 声道数: 1 (单声道)
   └─ 采样率: 16000 Hz

🎵 文件: music.mp3
   ├─ 声道数: 2 (立体声)
   └─ 采样率: 44100 Hz
classdef AudioProcessor < matlab.apps.AppBase % 属性定义(存储音频) properties (Access = public) UIFigure matlab.ui.Figure ImportButton matlab.ui.control.Button ProcessButton matlab.ui.control.Button SaveButton matlab.ui.control.Button GainSlider matlab.ui.control.Slider GainLabel matlab.ui.control.Label DelaySlider matlab.ui.control.Slider DelayLabel matlab.ui.control.Label EchoAmpSlider matlab.ui.control.Slider EchoAmpLabel matlab.ui.control.Label NoiseSlider matlab.ui.control.Slider NoiseLabel matlab.ui.control.Label WaveformAxes1 matlab.ui.control.UIAxes WaveformAxes2 matlab.ui.control.UIAxes SpectrumAxes1 matlab.ui.control.UIAxes SpectrumAxes2 matlab.ui.control.UIAxes StatusLabel matlab.ui.control.Label OriginalAudio % 原始音频据 ProcessedAudio % 处理后音频据 SampleRate % 采样率 IsMono % 是否单声道 end % 构造函(初始化界面) methods (Access = private) function createComponents(app) % 创建主窗口 app.UIFigure = uifigure('Visible', 'off'); app.UIFigure.Position = [100, 100, 800, 600]; app.UIFigure.Name = '音频处理系统'; % 导入按钮 app.ImportButton = uibutton(app.UIFigure, 'push'); app.ImportButton.Position = [20, 540, 100, 30]; app.ImportButton.Text = '导入音频'; app.ImportButton.ButtonPushedFcn = @(src, event) app.ImportButtonPushed(src, event); % 处理按钮 app.ProcessButton = uibutton(app.UIFigure, 'push'); app.ProcessButton.Position = [140, 540, 100, 30]; app.ProcessButton.Text = '开始处理'; app.ProcessButton.ButtonPushedFcn = @(src, event) app.ProcessButtonPushed(src, event); app.ProcessButton.Enable = 'off'; % 保存按钮 app.SaveButton = uibutton(app.UIFigure, 'push'); app.SaveButton.Position = [260, 540, 100, 30]; app.SaveButton.Text = '保存结果'; app.SaveButton.ButtonPushedFcn = @(src, event) app.SaveButtonPushed(src, event); app.SaveButton.Enable = 'off'; % 增益滑块 app.GainLabel = uilabel(app.UIFigure); app.GainLabel.Position = [400, 545, 50, 22]; app.GainLabel.Text = '增益(dB)'; app.GainSlider = uislider(app.UIFigure); app.GainSlider.Position = [460, 540, 200, 30]; app.GainSlider.Limits = [0, 12]; app.GainSlider.Value = 6; app.GainSlider.MajorTicks = [0, 6, 12]; app.GainSlider.MajorTickLabels = {'0', '6', '12'}; % 延迟滑块 app.DelayLabel = uilabel(app.UIFigure); app.DelayLabel.Position = [400, 515, 50, 22]; app.DelayLabel.Text = '延迟(ms)'; app.DelaySlider = uislider(app.UIFigure); app.DelaySlider.Position = [460, 510, 200, 30]; app.DelaySlider.Limits = [0, 500]; app.DelaySlider.Value = 300; app.DelaySlider.MajorTicks = [0, 250, 500]; app.DelaySlider.MajorTickLabels = {'0', '250', '500'}; % 回音衰减滑块 app.EchoAmpLabel = uilabel(app.UIFigure); app.EchoAmpLabel.Position = [400, 485, 80, 22]; app.EchoAmpLabel.Text = '回音衰减系'; app.EchoAmpSlider = uislider(app.UIFigure); app.EchoAmpSlider.Position = [460, 480, 200, 30]; app.EchoAmpSlider.Limits = [0, 1]; app.EchoAmpSlider.Value = 0.5; app.EchoAmpSlider.MajorTicks = [0, 0.5, 1]; app.EchoAmpSlider.MajorTickLabels = {'0', '0.5', '1'}; % 噪声幅度滑块 app.NoiseLabel = uilabel(app.UIFigure); app.NoiseLabel.Position = [400, 455, 80, 22]; app.NoiseLabel.Text = '噪声幅度系'; app.NoiseSlider = uislider(app.UIFigure); app.NoiseSlider.Position = [460, 450, 200, 30]; app.NoiseSlider.Limits = [0, 0.2]; app.NoiseSlider.Value = 0.1; app.NoiseSlider.MajorTicks = [0, 0.1, 0.2]; app.NoiseSlider.MajorTickLabels = {'0', '0.1', '0.2'}; % 波形图坐标轴1(原始立体声) app.WaveformAxes1 = uiaxes(app.UIFigure); app.WaveformAxes1.Position = [20, 320, 760, 180]; app.WaveformAxes1.Title = '原始音频(立体声)'; app.WaveformAxes1.XLabel = '时间(s)'; app.WaveformAxes1.YLabel = '振幅'; % 波形图坐标轴2(单声道) app.WaveformAxes2 = uiaxes(app.UIFigure); app.WaveformAxes2.Position = [20, 120, 760, 180]; app.WaveformAxes2.Title = '单声道音频'; app.WaveformAxes2.XLabel = '时间(s)'; app.WaveformAxes2.YLabel = '振幅'; % 频谱图坐标轴(可扩展) app.SpectrumAxes1 = uiaxes(app.UIFigure); app.SpectrumAxes1.Position = [20, 320, 760, 180]; app.SpectrumAxes1.Visible = 'off'; % 初始隐藏,处理后显示 app.SpectrumAxes2 = uiaxes(app.UIFigure); app.SpectrumAxes2.Position = [20, 120, 760, 180]; app.SpectrumAxes2.Visible = 'off'; % 状态标签 app.StatusLabel = uilabel(app.UIFigure); app.StatusLabel.Position = [20, 50, 760, 22]; app.StatusLabel.Text = '请点击"导入音频"开始'; app.StatusLabel.HorizontalAlignment = 'center'; % 显示窗口 app.UIFigure.Visible = 'on'; end end % 构造函 methods (Access = public) function app = AudioProcessor % 创建组件 createComponents(app); end end % 导入音频按钮回调 methods (Access = private) function ImportButtonPushed(app, ~) % 打开文件选择对话框 [filePath, fileName] = uigetfile({'*.wav', 'WAV音频文件 (*.wav)'}); if filePath == 0 return; % 未选择文件 end try % 读取音频文件 [y, Fs] = audioread(fullfile(filePath, fileName)); app.OriginalAudio = y; app.SampleRate = Fs; app.IsMono = size(y, 2) == 1; % 显示原始波形 plotOriginalWaveforms(app, y, Fs); % 启用处理按钮 app.ProcessButton.Enable = 'on'; app.StatusLabel.Text = ['已导入: ', fileName]; catch e uialert(app.UIFigure, ['读取失败: ', e.message], '错误'); end end % 开始处理按钮回调 function ProcessButtonPushed(app, ~) if isempty(app.OriginalAudio) uialert(app.UIFigure, '请先导入音频', '提示'); return; end y = app.OriginalAudio; Fs = app.SampleRate; % 1. 双声道单声道 if ~app.IsMono y_mono = mean(y, 2); else y_mono = y; end % 2. 增益调节(dB转线性因子) gain_db = app.GainSlider.Value; gain_factor = 10^(gain_db/20); % +6dB = 2倍,+12dB=4倍 y_gain = y_mono * gain_factor; % 3. 混音处理(添加白噪声) noise_amp = app.NoiseSlider.Value; noise = noise_amp * randn(size(y_gain)); y_mix = y_gain + noise; % 4. 回音效果 echo_delay_ms = app.DelaySlider.Value; echo_delay = echo_delay_ms / 1000; % 转换为秒 echo_amp = app.EchoAmpSlider.Value; y_echo = addEcho(y_mix, Fs, echo_delay, echo_amp); % 5. 减抽样处理 new_Fs = Fs/2; % 半抽样率 y_down = resample(y_echo, new_Fs, Fs); % 防混叠重采样 % 6. IIR低通滤波器设计 fc = 4000; % 截止频率4kHz [b, a] = butter(4, fc/(new_Fs/2), 'low'); % 4阶巴特沃斯滤波器 y_filtered = filter(b, a, y_down); % 保存处理结果 app.ProcessedAudio = y_filtered; % 显示处理后的波形频谱 plotProcessedResults(app, y_mono, y_filtered, Fs, new_Fs); % 启用保存按钮 app.SaveButton.Enable = 'on'; app.StatusLabel.Text = '处理完成!'; end % 保存结果按钮回调 function SaveButtonPushed(app, ~) if isempty(app.ProcessedAudio) uialert(app.UIFigure, '无处理结果可保存', '提示'); return; end [filePath, fileName] = uiputfile({'*.wav', 'WAV文件 (*.wav)'}, ... '保存处理后的音频', 'processed_audio.wav'); if filePath == 0 return; % 未选择保存 end try audiowrite(fullfile(filePath, fileName), app.ProcessedAudio, app.SampleRate/2); uialert(app.UIFigure, ['已保存至: ', fileName], '成功'); catch e uialert(app.UIFigure, ['保存失败: ', e.message], '错误'); end end % 绘制原始波形 function plotOriginalWaveforms(app, y_stereo, Fs) t = (0:length(y_stereo)-1)/Fs; % 显示原始立体声波形 cla(app.WaveformAxes1); if size(y_stereo, 2) == 2 plot(app.WaveformAxes1, t, y_stereo(:,1), 'b', t, y_stereo(:,2), 'r'); legend(app.WaveformAxes1, '左声道', '右声道'); else plot(app.WaveformAxes1, t, y_stereo); legend(app.WaveformAxes1, '单声道'); end title(app.WaveformAxes1, '原始音频波形'); xlabel(app.WaveformAxes1, '时间(s)'); ylabel(app.WaveformAxes1, '振幅'); grid(app.WaveformAxes1, 'on'); % 显示单声道波形(若为立体声) if size(y_stereo, 2) == 2 y_mono = mean(y_stereo, 2); cla(app.WaveformAxes2); plot(app.WaveformAxes2, t, y_mono); title(app.WaveformAxes2, '单声道转换后波形'); xlabel(app.WaveformAxes2, '时间(s)'); ylabel(app.WaveformAxes2, '振幅'); grid(app.WaveformAxes2, 'on'); else app.WaveformAxes2.Visible = 'off'; end end % 绘制处理结果(波形频谱) function plotProcessedResults(app, y_orig, y_proc, Fs, new_Fs) % 隐藏原始波形,显示频谱 app.WaveformAxes1.Visible = 'off'; app.WaveformAxes2.Visible = 'off'; app.SpectrumAxes1.Visible = 'on'; app.SpectrumAxes2.Visible = 'on'; % 绘制原始音频频谱 plotSpectrum(app, y_orig, Fs, app.SpectrumAxes1); title(app.SpectrumAxes1, '原始音频频谱'); % 绘制处理后音频频谱 plotSpectrum(app, y_proc, new_Fs, app.SpectrumAxes2); title(app.SpectrumAxes2, '处理后音频频谱'); end % 频谱分析函 function plotSpectrum(app, y, Fs, axesHandle) N = 2^nextpow2(length(y)); f = Fs*(0:(N/2))/N; Y = fft(y, N); P = abs(Y/N).^2; % 功率谱密度 cla(axesHandle); plot(axesHandle, f, 10*log10(P(1:N/2+1))); % 转换为dB xlabel(axesHandle, '频率(Hz)'); ylabel(axesHandle, '功率谱密度(dB/Hz)'); xlim(axesHandle, [0, Fs/2]); grid(axesHandle, 'on'); end end % 核心音频处理函(与原逻辑一致) methods (Access = private) function y_out = addEcho(y_in, Fs, delay, amp) delay_samples = round(delay * Fs); y_out = y_in; % 避免组越界 max_idx = length(y_in) - delay_samples; if max_idx > 0 y_out(delay_samples+1:end) = y_out(delay_samples+1:end) + amp * y_in(1:max_idx); end end end end
06-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MonkeyKing.sun

对你有帮助的话,可以打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值