批量修改音频声道数的脚本

wen 实用脚本 2

本文目录导读:

批量修改音频声道数的脚本

  1. 方案一:使用pydub(推荐,支持多种格式)
  2. 安装依赖
  3. 使用方法
  4. 方案二:使用ffmpeg命令行(无需Python)
  5. 方案三:使用sox(更轻量级)

使用pydub(推荐,支持多种格式)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
批量修改音频声道数脚本
支持格式: mp3, wav, flac, ogg, m4a 等
"""
import os
import argparse
from pydub import AudioSegment
from concurrent.futures import ThreadPoolExecutor
import logging
# 设置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# 支持的音频格式
SUPPORTED_FORMATS = {'.mp3', '.wav', '.flac', '.ogg', '.m4a', '.wma', '.aac'}
def change_audio_channels(input_path, output_path, channels, sample_rate=None, bitrate=None):
    """
    修改单个音频文件的声道数
    Args:
        input_path: 输入文件路径
        output_path: 输出文件路径
        channels: 目标声道数 (1=单声道, 2=立体声)
        sample_rate: 采样率 (可选)
        bitrate: 比特率 (可选)
    """
    try:
        # 读取音频文件
        audio = AudioSegment.from_file(input_path)
        # 修改声道数
        if channels == 1:
            audio = audio.set_channels(1)
            logger.info(f"转换为单声道: {input_path}")
        elif channels == 2:
            audio = audio.set_channels(2)
            logger.info(f"转换为立体声: {input_path}")
        else:
            logger.error(f"不支持的声道数: {channels},仅支持1(单声道)或2(立体声)")
            return False
        # 修改采样率(如果指定)
        if sample_rate:
            audio = audio.set_frame_rate(sample_rate)
        # 导出文件
        export_params = {"format": os.path.splitext(output_path)[1][1:]}
        if bitrate:
            export_params["bitrate"] = bitrate
        audio.export(output_path, **export_params)
        logger.info(f"成功导出: {output_path}")
        return True
    except Exception as e:
        logger.error(f"处理文件 {input_path} 时出错: {e}")
        return False
def batch_process(input_dir, output_dir, channels, sample_rate=None, bitrate=None, 
                  recursive=False, max_workers=4, overwrite=False, keep_structure=True):
    """
    批量处理音频文件
    Args:
        input_dir: 输入目录
        output_dir: 输出目录
        channels: 目标声道数
        sample_rate: 采样率
        bitrate: 比特率
        recursive: 是否递归处理子目录
        max_workers: 最大线程数
        overwrite: 是否覆盖已有文件
        keep_structure: 是否保持目录结构
    """
    # 创建输出目录
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    # 收集所有音频文件
    audio_files = []
    if recursive:
        for root, dirs, files in os.walk(input_dir):
            for file in files:
                if os.path.splitext(file)[1].lower() in SUPPORTED_FORMATS:
                    audio_files.append(os.path.join(root, file))
    else:
        for file in os.listdir(input_dir):
            if os.path.splitext(file)[1].lower() in SUPPORTED_FORMATS:
                audio_files.append(os.path.join(input_dir, file))
    if not audio_files:
        logger.warning(f"在 {input_dir} 中没有找到支持的音频文件")
        return
    logger.info(f"找到 {len(audio_files)} 个音频文件")
    # 准备处理任务
    tasks = []
    for input_path in audio_files:
        if keep_structure:
            # 保持目录结构
            rel_path = os.path.relpath(input_path, input_dir)
            output_path = os.path.join(output_dir, rel_path)
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
        else:
            # 所有文件放在同一目录
            filename = os.path.basename(input_path)
            output_path = os.path.join(output_dir, filename)
        # 检查文件是否已存在
        if os.path.exists(output_path) and not overwrite:
            logger.info(f"跳过已存在的文件: {output_path}")
            continue
        tasks.append((input_path, output_path, channels, sample_rate, bitrate))
    # 多线程处理
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = [executor.submit(change_audio_channels, *task) for task in tasks]
        for future in futures:
            try:
                future.result()
            except Exception as e:
                logger.error(f"处理任务时出错: {e}")
def main():
    parser = argparse.ArgumentParser(description="批量修改音频声道数")
    parser.add_argument("-i", "--input", required=True, help="输入目录或文件")
    parser.add_argument("-o", "--output", required=True, help="输出目录")
    parser.add_argument("-c", "--channels", type=int, required=True, 
                        choices=[1, 2], help="目标声道数 (1=单声道, 2=立体声)")
    parser.add_argument("-sr", "--sample-rate", type=int, help="采样率 (可选)")
    parser.add_argument("-br", "--bitrate", type=str, help="比特率 (可选,如 '192k')")
    parser.add_argument("-r", "--recursive", action="store_true", help="递归处理子目录")
    parser.add_argument("-w", "--workers", type=int, default=4, help="处理线程数 (默认: 4)")
    parser.add_argument("--overwrite", action="store_true", help="覆盖已存在的文件")
    parser.add_argument("--no-structure", action="store_true", 
                        help="不保持目录结构,所有文件输出到同一目录")
    args = parser.parse_args()
    # 检查输入是文件还是目录
    if os.path.isfile(args.input):
        # 处理单个文件
        input_format = os.path.splitext(args.input)[1].lower()
        if input_format not in SUPPORTED_FORMATS:
            logger.error(f"不支持的音频格式: {input_format}")
            return
        # 创建输出目录
        os.makedirs(args.output, exist_ok=True)
        # 生成输出文件名
        filename = os.path.basename(args.input)
        output_path = os.path.join(args.output, filename)
        # 处理单个文件
        if change_audio_channels(args.input, output_path, args.channels, 
                                 args.sample_rate, args.bitrate):
            logger.info(f"成功处理文件: {args.input}")
        else:
            logger.error(f"处理文件失败: {args.input}")
    elif os.path.isdir(args.input):
        # 批量处理目录
        batch_process(
            args.input, 
            args.output, 
            args.channels,
            args.sample_rate,
            args.bitrate,
            args.recursive,
            args.workers,
            args.overwrite,
            not args.no_structure
        )
    else:
        logger.error(f"输入路径不存在: {args.input}")
if __name__ == "__main__":
    main()

安装依赖

# 安装pydub
pip install pydub
# 安装音频处理后端(至少安装一个)
# 方案一:安装ffmpeg
# Ubuntu/Debian:
sudo apt-get install ffmpeg
# macOS:
brew install ffmpeg
# Windows: 下载ffmpeg并添加到PATH
# 方案二:安装libav
# Ubuntu/Debian:
sudo apt-get install libav-tools

使用方法

# 1. 批量转换目录下所有音频为单声道
python change_channels.py -i ./input_audio -o ./output_audio -c 1 -r
# 2. 转换为立体声并指定采样率
python change_channels.py -i ./input -o ./output -c 2 -sr 44100 -r
# 3. 转换为单声道并指定比特率
python change_channels.py -i ./input -o ./output -c 1 -br 192k -r
# 4. 处理单个文件
python change_channels.py -i song.mp3 -o ./output -c 1
# 5. 使用多线程加速(默认4线程)
python change_channels.py -i ./input -o ./output -c 1 -w 8 -r
# 6. 覆盖已存在的文件
python change_channels.py -i ./input -o ./output -c 2 -r --overwrite
# 7. 不保持目录结构
python change_channels.py -i ./input -o ./output -c 1 -r --no-structure

使用ffmpeg命令行(无需Python)

如果不想安装Python,可以直接使用ffmpeg命令行:

#!/bin/bash
# batch_change_channels.sh
# 批量转换当前目录下所有音频为单声道
for file in *.mp3 *.wav *.flac; do
    if [ -f "$file" ]; then
        filename="${file%.*}"
        ffmpeg -i "$file" -ac 1 "${filename}_mono.${file##*.}"
    fi
done

使用sox(更轻量级)

#!/bin/bash
# batch_change_channels_sox.sh
# 批量转换所有wav为单声道
for file in *.wav; do
    if [ -f "$file" ]; then
        filename="${file%.*}"
        sox "$file" -c 1 "${filename}_mono.wav"
    fi
done

选择建议:

  • 推荐使用Python脚本,功能最全面,支持多种格式
  • 如果只需要简单处理,可以使用ffmpeg命令行
  • sox适合处理wav格式文件

抱歉,评论功能暂时关闭!