python 使用tkinter,pydub,AudioSegment把FLAC,ogg, wav等格式音频转换成192k比特率的mp3

直接上效果图

在这里插入图片描述
可以使用python的pysimplegui-exemaker打包一个exe程序

把FLAC,WAV,OGG等音频转MP3音频

在音频处理领域,我们经常需要对音频文件进行各种操作,例如剪辑、合并、转码等。而 Python 中的 AudioSegment 是一个强大的库,可以帮助我们处理各种音频格式的文件。
1.支持的格式

  • AudioSegment 是 pydub 库的一部分,通过使用 ffmpeg 库来实现对音频文件格式的支持。因此,AudioSegment 实际上支持所有 ffmpeg 支持的音频格式。

2.下面是一些常见的音频格式:

  • WAV (Waveform Audio File Format,无损音频文件格式)
  • MP3 (MPEG Audio Layer 3,有损音频文件格式)
  • FLAC (Free Lossless Audio Codec,无损音频文件格式)
  • OGG (Ogg Vorbis,开放音频文件格式)
  • AAC (Advanced Audio Coding,高级音频编码格式)

当然,除了上述格式外,AudioSegment 还支持其他许多音频格式,例如 AMR、WMA、AIFF 等。具体介绍及使用百度自了解

上代码:python文件为audioConvert.py

"""
    把FLAC,WAV,OGG等音频转MP3音频

    AudioSegment 支持哪个格式
    在音频处理领域,我们经常需要对音频文件进行各种操作,例如剪辑、合并、转码等。而 Python 中的 AudioSegment 是一个强大的库,可以帮助我们处理各种音频格式的文件。
    支持的格式
    AudioSegment 是 pydub 库的一部分,通过使用 ffmpeg 库来实现对音频文件格式的支持。因此,AudioSegment 实际上支持所有 ffmpeg 支持的音频格式。下面是一些常见的音频格式:
    WAV (Waveform Audio File Format,无损音频文件格式)
    MP3 (MPEG Audio Layer 3,有损音频文件格式)
    FLAC (Free Lossless Audio Codec,无损音频文件格式)
    OGG (Ogg Vorbis,开放音频文件格式)
    AAC (Advanced Audio Coding,高级音频编码格式)
    当然,除了上述格式外,AudioSegment 还支持其他许多音频格式,例如 AMR、WMA、AIFF 等。
"""
import os
import re

from pydub import AudioSegment
from pydub.utils import mediainfo
from queue import Queue
import threading


class AudioConverterMp3:
    """
    :param source: 源文件夹
    :param target: 输出文件夹
    :param source_type: 源格式
    :param target_type: 输出格式
    :param printlog: 输出日志对象方法 没有传值用默认print否则printlog(message)
    """

    def __init__(self, source='F:\夸克网盘\Flac音乐+歌词', target='F:\夸克网盘\MP3音乐', source_type='flac', target_type='mp3', printlog=print):
        self.source = source  # 源文件夹
        self.target = target  # 输出文件夹
        self.source_type = source_type  # 源格式
        self.target_type = target_type  # 输出格式
        self.printlog = printlog  # 输出日志对象方法 没有传值用默认print否则printlog(message)
        self.count = 0  # 待转化音频文件总数
        self.queue = Queue()  # 队列,为什么要用队列?因为如果不用队列,多线程处理音频文件时,会出现文件读写冲突,导致程序崩溃
        self.get_audio_files()  # 获取源文件夹下所有flac音频文件

    def get_audio_files(self):
        """
        获取源文件夹下所有音频文件,加入队列
        :return: 文件列表
        """
        for index, file in enumerate([song for song in os.listdir(self.source) if song.endswith('.' + self.source_type)]):
            self.queue.put([index, file])
            self.count += 1
        self.printlog(f'本次待转化音频文件总数:{self.count}个,开始处理...')

    def audio_to_mp3(self, index, source_file):
        """
        把音频转MP3音频
        :param index: 序号
        :param source_file: 源文件
        :return: None
        """
        try:
            song = AudioSegment.from_file(os.path.join(self.source, source_file), self.source_type)  # 读取音频文件
            target_file = source_file[:-len(self.source_type)] + self.target_type  # 输出文件
            tags = mediainfo(os.path.join(self.source, source_file)).get('TAG')  # 输出音频信息(元数据)
            song.export(os.path.join(self.target, target_file), format=self.target_type, bitrate='192k', tags=tags)  # 保存音频为mp3格式
            self.printlog(f"{threading.current_thread().name} 提供 {source_file} 转换:{self.source_type} -> {self.target_type} 完成")  # 输出结果
        except Exception as e:
            error_dir = os.path.join(os.path.dirname(self.source), "error-transfer-song")
            if not os.path.exists(error_dir):
                os.makedirs(error_dir)
            source_file = re.findall(r"from '(.+?)':", str(e))[0]
            os.rename(os.path.join(self.source, source_file), os.path.join(error_dir, source_file))  # 发生错误时,将源文件移动到error-transfer-song文件夹下
            self.printlog(f'\n\n{source_file} 转码失败,已移动到 {error_dir} 文件夹下\n\n发生错误代码:{e}\n\n')

    def multiple_thread(self):
        """
        多线程处理音频文件
        多线程处理音频文件,使用队列,队列中存放音频文件路径,每个线程从队列中取出一个音频文件进行处理。
        队列的使用,可以保证多个线程同时处理音频文件,避免文件读写冲突。
        :return: None
        """
        while not self.queue.empty():
            index, file = self.queue.get()
            if os.path.exists(os.path.join(self.target, file[:-len(self.source_type)] + self.target_type)):
                self.printlog(f'{index + 1}/{self.count}: {file} 已转换,跳过...')
                continue
            self.audio_to_mp3(index, file)

    # 运行程序
    def run(self):
        """
        运行程序
        多线程处理,根据CPU核心数启动线程数,可以充分利用CPU资源,提高处理速度。
        :return: None
        """
        tasks = []
        for i in range(os.cpu_count()):
            t = threading.Thread(target=self.multiple_thread, name=f'线程-{i}')
            t.start()
            tasks.append(t)
        for t in tasks:
            t.join()
        self.printlog('\n全部文件处理完成!\n')


# 程序测试用入口,,当文件直接运行时,即非模块导入调用,执行以下代码
if __name__ == '__main__':
    audio_to_mp3 = AudioConverterMp3()
    audio_to_mp3.run()

python图形界面教程(tkinter)

主要用到 tkinderLabel标签显示文体,Radiobuttio 单选按钮选择源文件格式,tkinter.filedialog.askdirectory 选择文件目录,滚动文本ScrolledText等具体介绍及使用百度自了解。

在Python的Tkinter GUI中动态输出日志时,如果遇到卡顿问题,通常是因为主事件循环被过度占用,导致界面无法及时更新。为了解决这个问题,可以使用多线程或者异步编程的方式,让日志输出在另一个线程中执行,从而不影响主事件循环的运行。

上代码:python文件为main.py(主文件)

# python图形界面:    

from threading import Thread
from tkinter import *
from tkinter import messagebox
from tkinter.filedialog import askdirectory
from tkinter.scrolledtext import ScrolledText
from audioConvert import AudioConverterMp3


class AudioToMP3UI(object):
    """
    把音频转MP3格式音频
    1. 选择源音频文件路径和目标音频文件路径
    2. 点击“开 始 转 码”按钮,开始转码
    3. 转码完成后,会弹出提示框,提示转码完成
    4. 转码完成后,可以到目标音频文件路径下查看转码后的音频文件
    5. 日志信息会实时显示在滚动文本框中
    """

    def __init__(self):
        self.et_source = None  # 源文件路径输入框
        self.et_target = None  # 目标文件路径输入框
        self.scrolltext = None  # 滚动文本框
        self.thread = None  # 线程对象
        self.root = Tk()  # 创建GUI窗口
        self.root.title("把音频转MP3格式音频")  # 设置窗口标题
        width = 600
        height = 500
        x = self.root.winfo_screenwidth() // 2 - width // 2  # 计算窗口宽度居中位置
        y = self.root.winfo_screenheight() // 2 - height // 2  # 计算窗口高度居中位置
        self.root.geometry(f"{width}x{height}+{x}+{y}")  # 设置窗口大小和位置
        self.source_type = StringVar()  # 源文件格式选择变量
        self.frame_type = Frame(self.root)  # 创建Frame容器
        self.frame_type.pack()  # 放置Frame容器
        self.frame_path = Frame(self.root)  # 创建Frame容器
        self.frame_path.pack()  # 放置Frame容器
        self.frame_info = Frame(self.root)  # 创建Frame容器
        self.frame_info.pack()  # 放置Frame容器 AMR、WMA、AIFF

    # 选择源文件格式
    def create_source_type_ui(self):
        lb_type = Label(self.frame_type, text="源文件格式:")  # 创建标签
        lb_type.grid(column=0, row=0, padx=8, pady=4)  # 放置标签
        rb_type1 = Radiobutton(self.frame_type, text="wav", variable=self.source_type, value="wav")  # 创建单选按钮
        rb_type1.grid(column=1, row=0, padx=3)  # 放置标签
        rb_type2 = Radiobutton(self.frame_type, text="mp3", variable=self.source_type, value="mp3")  # 创建单选按钮
        rb_type2.grid(column=2, row=0, padx=3)  # 放置标签
        rb_type3 = Radiobutton(self.frame_type, text="flac", variable=self.source_type, value="flac")  # 创建单选按钮
        rb_type3.grid(column=3, row=0, padx=3)  # 放置标签
        rb_type4 = Radiobutton(self.frame_type, text="ogg", variable=self.source_type, value="ogg")  # 创建单选按钮
        rb_type4.grid(column=4, row=0, padx=3)  # 放置标签
        rb_type5 = Radiobutton(self.frame_type, text="aac", variable=self.source_type, value="aac")  # 创建单选按钮
        rb_type5.grid(column=5, row=0, padx=3)  # 放置标签
        rb_type6 = Radiobutton(self.frame_type, text="amr", variable=self.source_type, value="amr")  # 创建单选按钮
        rb_type6.grid(column=6, row=0, padx=3)  # 放置标签
        rb_type7 = Radiobutton(self.frame_type, text="wma", variable=self.source_type, value="wma")  # 创建单选按钮
        rb_type7.grid(column=7, row=0, padx=3)  # 放置标签
        rb_type8 = Radiobutton(self.frame_type, text="aiff", variable=self.source_type, value="aiff")  # 创建单选按钮
        rb_type8.grid(column=8, row=0, padx=3)  # 放置标签
        self.source_type.set("flac")  # 设置默认选择flac格式

    def select_type_command(self):
        print("选择源文件格式:" + self.source_type.get())  # 打印选择的源文件格式
        return self.source_type.get()

    # 设置源文件路径和目标文件路径输入框和打开文件目录按钮
    def create_source_target_dir_ui(self):
        # 设置源文件路径输入框和打开文件目录按钮
        lb_source = Label(self.frame_path, text="源音频文件路径:")  # 创建标签
        lb_source.grid(column=0, row=0, pady=20)  # 放置标签
        self.et_source = Entry(self.frame_path, width=60, bd=5)  # 创建源目录输入框
        self.et_source.grid(column=1, row=0, padx=5)  # 放置输入框
        btn_source = Button(self.frame_path, text="点选", command=self.select_source_dir_command)  # 创建选择源目录按钮
        btn_source.grid(column=2, row=0)  # 放置按钮
        # 设置目标文件路径输入框和打开文件目录按钮
        lb_target = Label(self.frame_path, text="导出音频文件路径:")  # 创建标签
        lb_target.grid(column=0, row=1, pady=0)  # 放置标签
        self.et_target = Entry(self.frame_path, width=60, bd=5)  # 创建目标目录输入框
        self.et_target.grid(column=1, row=1, padx=5)  # 放置输入框
        btn_target = Button(self.frame_path, text="点选", command=self.select_target_dir_command)  # 创建选择目标目录按钮
        btn_target.grid(column=2, row=1)  # 放置按钮
        btn_start = Button(self.frame_path, text="开 始 转 码", command=self.convert_format)  # 创建开始转码按钮
        btn_start.grid(column=0, row=2, ipadx=80, padx=45, pady=15, columnspan=3)

    # 设置选择源文件目录按钮事件
    def select_source_dir_command(self):
        dirname = askdirectory(title='请选择->源音频文件路径')  # 弹出选择源目录对话框
        if dirname != '':
            self.et_source.delete(0, END)  # 清空输入框内容
            self.et_source.insert(0, dirname)  # 显示选择的目录
        else:
            messagebox.showinfo("提醒", "您没有选择任何目录!")  # 提示用户没有选择目录

    # 设置选择目标文件目录按钮事件
    def select_target_dir_command(self):
        dirname = askdirectory(title='请选择->导出音频文件路径')  # 弹出选择目标目录对话框
        if dirname != '':
            self.et_target.delete(0, END)  # 清空输入框内容
            self.et_target.insert(0, dirname)  # 显示选择的目录
        else:
            messagebox.showinfo("提醒", "您没有选择任何目录!")  # 提示用户没有选择目录

    # 设置滚动文本框
    def create_scrolltext_ui(self):
        self.scrolltext = ScrolledText(self.frame_info, width=78, height=21, padx=10, pady=8)  # 创建滚动文本框
        self.scrolltext.pack()  # 放置滚动文本框
        self.scrolltext.insert(END, "1. 选择源音频文件路径和目标音频文件路径\n"
                                    "2. 点击“开 始 转 码”按钮,开始转码\n"
                                    "3. 转码完成后,会弹出提示框,提示转码完成\n"
                                    "4. 转码完成后,可以到目标音频文件路径下查看转码后的音频文件\n")    # 设置提示信息

    # 设置开始转码按钮事件
    def convert_format(self):
        source_path = self.et_source.get()  # 获取源文件路径
        target_path = self.et_target.get()  # 获取目标文件路径
        if source_path == '' or target_path == '':
            messagebox.showinfo("提醒", "请选择源文件路径和目标文件路径!")    # 提示用户没有选择目录
        else:
            self.scrolltext.insert(END, f'源文件路径:《{source_path}》 \n')  # 显示源文件路径
            self.scrolltext.insert(END, f'目标文件路径:《{target_path}》 \n')  # 显示目标文件路径
            self.scrolltext.insert(END, "开始转码!\n")  # 显示开始转码信息
            self.root.update()  # 更新UI显示
            # 转码代码
            audio_to_mp3 = AudioConverterMp3(source_path, target_path, self.source_type.get(), printlog=self.printlog)  # 创建AudioConverterMp3对象
            # 在Python的Tkinter GUI中动态输出日志时,如果遇到卡顿问题,通常是因为主事件循环被过度占用,导致界面无法及时更新。
            # 为了解决这个问题,可以使用多线程或者异步编程的方式,让日志输出在另一个线程中执行,从而不影响主事件循环的运行。
            self.thread = Thread(target=audio_to_mp3.run)    # 创建线程对象
            self.thread.start()  # 启动线程

    # 输出日志信息,用于显示执行过程打印的日志信息
    def printlog(self, info):
        self.scrolltext.insert(END, info + '\n')  # 显示日志信息
        self.scrolltext.see(END)  # 滚动到最后一行
        self.root.update()  # 更新UI显示

    # 运行GUI
    def run(self):
        self.create_source_type_ui()  # 创建源文件格式选择按钮
        self.create_source_target_dir_ui()  # 创建源文件路径输入框和打开文件目录按钮
        self.create_scrolltext_ui()  # 创建滚动文本框
        self.root.mainloop()    # 运行GUI


if __name__ == '__main__':
    trans_mp3 = AudioToMP3UI()
    trans_mp3.run()

  • 35
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值