如何用脚本批量生成音频频谱图?

wen 实用脚本 1

本文目录导读:

如何用脚本批量生成音频频谱图?

  1. 方法1:使用 Python + Librosa + Matplotlib
  2. 方法2:使用 SoX 命令行工具
  3. 方法3:使用 FFmpeg + Python
  4. 方法4:完整的高级版本(带参数控制)
  5. 使用方法
  6. 推荐的目录结构

方法1:使用 Python + Librosa + Matplotlib

import os
import librosa
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
from pathlib import Path
def create_spectrogram(audio_path, output_path, sr=22050):
    """
    生成单个音频文件的频谱图
    """
    # 加载音频文件
    y, sr = librosa.load(audio_path, sr=sr)
    # 生成频谱图
    plt.figure(figsize=(12, 8))
    # 方法1:Mel频谱图
    D = librosa.amplitude_to_db(np.abs(librosa.stft(y)), ref=np.max)
    librosa.display.specshow(D, sr=sr, x_axis='time', y_axis='hz')
    plt.colorbar(format='%+2.0f dB')
    # 方法2:或者使用梅尔频谱
    # mel_spec = librosa.feature.melspectrogram(y=y, sr=sr)
    # mel_db = librosa.amplitude_to_db(mel_spec, ref=np.max)
    # librosa.display.specshow(mel_db, sr=sr, x_axis='time', y_axis='mel')
    plt.title(f'Spectrogram - {Path(audio_path).stem}')
    plt.tight_layout()
    # 保存图片
    plt.savefig(output_path, dpi=150, bbox_inches='tight')
    plt.close()
def batch_process(input_dir, output_dir, file_extensions=['.mp3', '.wav', '.flac']):
    """
    批量处理音频文件
    """
    # 创建输出目录
    Path(output_dir).mkdir(parents=True, exist_ok=True)
    # 遍历输入目录
    audio_files = []
    for ext in file_extensions:
        audio_files.extend(list(Path(input_dir).glob(f'**/*{ext}')))
    print(f"找到 {len(audio_files)} 个音频文件")
    # 批量处理
    for i, audio_path in enumerate(audio_files, 1):
        try:
            output_path = Path(output_dir) / f"{audio_path.stem}_spectrogram.png"
            create_spectrogram(str(audio_path), str(output_path))
            print(f"[{i}/{len(audio_files)}] 处理完成: {audio_path.name}")
        except Exception as e:
            print(f"[{i}/{len(audio_files)}] 处理失败: {audio_path.name} - {e}")
# 使用示例
if __name__ == "__main__":
    input_directory = "input_audio"  # 输入音频目录
    output_directory = "output_spectrograms"  # 输出图片目录
    batch_process(input_directory, output_directory)

方法2:使用 SoX 命令行工具

#!/bin/bash
# batch_spectrogram.sh
INPUT_DIR="input_audio"
OUTPUT_DIR="output_spectrograms"
mkdir -p "$OUTPUT_DIR"
# 批量处理所有.wav文件
for file in "$INPUT_DIR"/*.wav; do
    if [ -f "$file" ]; then
        filename=$(basename "$file" .wav)
        echo "处理文件: $filename"
        sox "$file" -n spectrogram -o "$OUTPUT_DIR/${filename}_spectrogram.png"
    fi
done
# 处理其他格式(需要先转换)
for file in "$INPUT_DIR"/*.mp3; do
    if [ -f "$file" ]; then
        filename=$(basename "$file" .mp3)
        echo "处理文件: $filename"
        # 先转换为WAV,然后生成频谱
        sox "$file" -t wav - | sox - -n spectrogram -o "$OUTPUT_DIR/${filename}_spectrogram.png"
    fi
done
echo "批量处理完成!"

方法3:使用 FFmpeg + Python

import subprocess
import os
from pathlib import Path
def generate_spectrogram_ffmpeg(input_file, output_file, width=1920, height=1080):
    """
    使用FFmpeg生成频谱图
    """
    cmd = [
        'ffmpeg',
        '-i', input_file,
        '-lavfi', f'spectrogram=s={width}x{height}:mode=combined:color=rainbow',
        '-frames:v', '1',
        output_file,
        '-y'  # 覆盖已存在的文件
    ]
    try:
        subprocess.run(cmd, check=True, capture_output=True)
        return True
    except subprocess.CalledProcessError as e:
        print(f"FFmpeg处理失败: {e.stderr.decode()}")
        return False
def batch_process_ffmpeg(input_dir, output_dir):
    """
    使用FFmpeg批量处理
    """
    Path(output_dir).mkdir(parents=True, exist_ok=True)
    audio_formats = ['.mp3', '.wav', '.flac', '.m4a', '.ogg']
    files_processed = 0
    for ext in audio_formats:
        for audio_file in Path(input_dir).glob(f'*{ext}'):
            output_file = Path(output_dir) / f"{audio_file.stem}_spectrogram.png"
            if generate_spectrogram_ffmpeg(str(audio_file), str(output_file)):
                files_processed += 1
                print(f"处理完成: {audio_file.name}")
            else:
                print(f"处理失败: {audio_file.name}")
    return files_processed
# 使用示例
if __name__ == "__main__":
    input_dir = "input_audio"
    output_dir = "output_spectrograms"
    count = batch_process_ffmpeg(input_dir, output_dir)
    print(f"成功处理 {count} 个文件")

方法4:完整的高级版本(带参数控制)

import os
import librosa
import librosa.display
import matplotlib.pyplot as plt
import numpy as np
from pathlib import Path
import argparse
from concurrent.futures import ThreadPoolExecutor
class SpectrogramGenerator:
    def __init__(self, input_dir, output_dir, 
                 spectrogram_type='mel',  # 'mel', 'stft', 'chroma'
                 size=(12, 8), dpi=150,
                 colormap='viridis', max_workers=4):
        self.input_dir = Path(input_dir)
        self.output_dir = Path(output_dir)
        self.spectrogram_type = spectrogram_type
        self.size = size
        self.dpi = dpi
        self.colormap = colormap
        self.max_workers = max_workers
        # 确保输出目录存在
        self.output_dir.mkdir(parents=True, exist_ok=True)
    def generate_spectrogram(self, audio_path):
        """生成单个频谱图"""
        try:
            y, sr = librosa.load(str(audio_path), sr=None)
            plt.figure(figsize=self.size)
            if self.spectrogram_type == 'mel':
                # 梅尔频谱
                mel_spec = librosa.feature.melspectrogram(y=y, sr=sr)
                mel_db = librosa.amplitude_to_db(mel_spec, ref=np.max)
                librosa.display.specshow(mel_db, sr=sr, x_axis='time', 
                                        y_axis='mel', cmap=self.colormap)
            elif self.spectrogram_type == 'stft':
                # STFT频谱
                D = librosa.amplitude_to_db(np.abs(librosa.stft(y)), ref=np.max)
                librosa.display.specshow(D, sr=sr, x_axis='time', 
                                        y_axis='hz', cmap=self.colormap)
            elif self.spectrogram_type == 'chroma':
                # 色度频谱
                chroma = librosa.feature.chroma_stft(y=y, sr=sr)
                librosa.display.specshow(chroma, sr=sr, x_axis='time', 
                                        y_axis='chroma', cmap=self.colormap)
            plt.colorbar(format='%+2.0f dB')
            plt.title(f'{self.spectrogram_type.upper()} Spectrogram - {audio_path.stem}')
            plt.tight_layout()
            output_path = self.output_dir / f"{audio_path.stem}_{self.spectrogram_type}_spectrogram.png"
            plt.savefig(str(output_path), dpi=self.dpi, bbox_inches='tight')
            plt.close()
            return True, audio_path.name
        except Exception as e:
            return False, f"{audio_path.name}: {str(e)}"
    def batch_process(self):
        """批量处理所有音频文件"""
        audio_extensions = ['.mp3', '.wav', '.flac', '.m4a', '.ogg', '.wma']
        audio_files = []
        for ext in audio_extensions:
            audio_files.extend(list(self.input_dir.glob(f'*{ext}')))
        print(f"找到 {len(audio_files)} 个音频文件")
        # 使用线程池并行处理
        with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
            results = list(executor.map(self.generate_spectrogram, audio_files))
        # 统计结果
        success = sum(1 for r in results if r[0])
        failed = len(results) - success
        print(f"处理完成:成功 {success} 个,失败 {failed} 个")
        # 显示失败的文件
        if failed > 0:
            print("失败的文件:")
            for result in results:
                if not result[0]:
                    print(f"  - {result[1]}")
def main():
    parser = argparse.ArgumentParser(description='批量生成音频频谱图')
    parser.add_argument('input_dir', help='输入音频目录')
    parser.add_argument('output_dir', help='输出图片目录')
    parser.add_argument('--type', choices=['mel', 'stft', 'chroma'],
                       default='mel', help='频谱图类型')
    parser.add_argument('--width', type=int, default=12, help='图片宽度(英寸)')
    parser.add_argument('--height', type=int, default=8, help='图片高度(英寸)')
    parser.add_argument('--dpi', type=int, default=150, help='图片分辨率')
    parser.add_argument('--colormap', default='viridis', help='颜色映射')
    parser.add_argument('--workers', type=int, default=4, help='并行处理线程数')
    args = parser.parse_args()
    generator = SpectrogramGenerator(
        input_dir=args.input_dir,
        output_dir=args.output_dir,
        spectrogram_type=args.type,
        size=(args.width, args.height),
        dpi=args.dpi,
        colormap=args.colormap,
        max_workers=args.workers
    )
    generator.batch_process()
if __name__ == "__main__":
    main()

使用方法

安装依赖

# 安装Python依赖
pip install librosa matplotlib numpy
# 或者安装FFmpeg
# Ubuntu/Debian
sudo apt-get install ffmpeg
# macOS
brew install ffmpeg
# Windows
# 下载FFmpeg并添加到PATH

运行脚本

# 使用高级版(推荐)
python spectrogram_generator.py input_audio output_spectrograms --type mel --workers 8
# 使用基本版
python batch_spectrogram.py

推荐的目录结构

project/
├── input_audio/          # 存放音频文件
│   ├── song1.mp3
│   ├── song2.wav
│   └── song3.flac
├── output_spectrograms/  # 输出频谱图
│   ├── song1_mel_spectrogram.png
│   ├── song2_mel_spectrogram.png
│   └── song3_mel_spectrogram.png
├── batch_spectrogram.py  # 脚本文件
└── requirements.txt      # 依赖文件

这些脚本可以根据需求进行调整,比如修改频谱图样式、输出格式、并行处理数量等。

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