Python+Tkinter制作音频格式转换器

        我们将使用Python的Tkinter库来构建一个音频格式转换器界面。由于音频转换需要实际的处理,我们将使用`pydub`库(需要安装)来进行音频格式转换。同时,我们会使用`ffmpeg`作为后端,因此请确保系统中已安装ffmpeg并添加到环境变量,或者我们将提供一种方式让用户指定ffmpeg路径。 功能要求:

1. 支持选择多个音频文件(批量转换)或单个文件(单独转换)

2. 支持选择输出格式(如mp3, wav, flac, aac等)

3. 支持选择输出目录

4. 开始转换按钮,显示转换进度(由于批量转换,我们可以用进度条或者日志方式)

5. 转换过程中显示转换状态(成功/失败) 界面设计:

        - 文件选择:一个按钮用于添加文件,一个按钮用于添加文件夹(批量添加),一个列表显示已选文件。

        - 输出格式选择:下拉菜单(Combobox)列出支持的格式。

        - 输出目录选择:一个按钮用于选择目录,一个标签显示当前选择的目录。

        - 转换按钮:开始转换。

        - 日志区域:用于显示转换进度和结果(可以用Text组件)。

步骤:

1. 导入必要的库:tkinter, ttk, filedialog, messagebox, 以及pydub(需要安装:pip install pydub)。

2. 确保ffmpeg可用。如果不可用,可以提示用户安装或指定路径(我们可以在程序初始化时设置pydub的ffmpeg路径,但为了简便,我们假设已安装)。

3. 创建主窗口,设置标题。

4. 创建并布局各个组件。 注意:由于音频转换可能耗时,我们使用多线程来避免界面卡死。 我们将创建以下类: - AudioConverterApp: 主应用类,包含UI和事件处理。

具体实现: 首先,我们导入必要的库:

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os
import threading
from pygame import mixer
from pydub import AudioSegment

注意:需要用到ffmpeg工具,请提前下载,代码需要调用该工具进行格式转换(可设置全局环境变量,这样可直接调用,也可放入代码包里面,引用包路径即可)

#局部引入        
base_dir = os.path.dirname(os.path.abspath(__file__))
ffmpeg_path = os.path.join(base_dir, "ffmpeg", "bin", "ffmpeg.exe")
AudioSegment.converter = ffmpeg_path

编写主体代码:

class AudioConverterApp:def __init__(self, root):self.root = rootself.root.title("音频格式转换器")self.root.geometry("800x800")self.root.resizable(True, True)# 设置应用图标try:self.root.iconbitmap("audio_icon.ico")except:pass# 创建样式self.style = ttk.Style()self.style.configure('TFrame', background='#f0f0f0')self.style.configure('Header.TLabel', font=('Arial', 16, 'bold'), background='#4a6baf', foreground='white')self.style.configure('TButton', font=('Arial', 10), padding=5)self.style.map('TButton', background=[('active', '#4a6baf')])self.style.configure('Progress.Horizontal.TProgressbar', thickness=20, background='#4a6baf')# 创建主框架self.main_frame = ttk.Frame(root)self.main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)# 创建标题self.header_frame = ttk.Frame(self.main_frame)self.header_frame.pack(fill=tk.X, pady=(0, 20))self.title_label = ttk.Label(self.header_frame,text="音频格式转换器",style='Header.TLabel',anchor=tk.CENTER)self.title_label.pack(fill=tk.X, ipady=10)# 创建控制面板self.control_frame = ttk.LabelFrame(self.main_frame, text="转换设置")self.control_frame.pack(fill=tk.X, pady=10)# 输入文件选择self.input_frame = ttk.Frame(self.control_frame)self.input_frame.pack(fill=tk.X, padx=10, pady=10)ttk.Label(self.input_frame, text="输入文件:").grid(row=0, column=0, sticky=tk.W, padx=(0, 5))self.input_entry = ttk.Entry(self.input_frame, width=50)self.input_entry.grid(row=0, column=1, sticky=tk.EW, padx=5)self.browse_button = ttk.Button(self.input_frame,text="浏览文件...",command=self.browse_files,width=10)self.browse_button.grid(row=0, column=2, padx=(5, 0))# 输出格式选择self.format_frame = ttk.Frame(self.control_frame)self.format_frame.pack(fill=tk.X, padx=10, pady=10)ttk.Label(self.format_frame, text="输出格式:").grid(row=0, column=0, sticky=tk.W, padx=(0, 5))self.format_var = tk.StringVar(value="mp3")self.format_combobox = ttk.Combobox(self.format_frame,textvariable=self.format_var,width=8,state="readonly")self.format_combobox['values'] = ('mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a')self.format_combobox.grid(row=0, column=1, sticky=tk.W, padx=5)# 输出目录选择self.output_frame = ttk.Frame(self.control_frame)self.output_frame.pack(fill=tk.X, padx=10, pady=10)ttk.Label(self.output_frame, text="输出目录:").grid(row=0, column=0, sticky=tk.W, padx=(0, 5))self.output_entry = ttk.Entry(self.output_frame, width=50)self.output_entry.grid(row=0, column=1, sticky=tk.EW, padx=5)self.output_button = ttk.Button(self.output_frame,text="浏览目录...",command=self.browse_output,width=10)self.output_button.grid(row=0, column=2, padx=(5, 0))# 添加批量转换区域self.batch_frame = ttk.LabelFrame(self.control_frame, text="批量转换")self.batch_frame.pack(fill=tk.X, padx=10, pady=10)self.batch_button = ttk.Button(self.batch_frame,text="添加文件夹...",command=self.browse_folder,width=15)self.batch_button.pack(side=tk.LEFT, padx=5, pady=5)self.clear_button = ttk.Button(self.batch_frame,text="清空列表",command=self.clear_file_list,width=10)self.clear_button.pack(side=tk.RIGHT, padx=5, pady=5)# 文件列表self.list_frame = ttk.LabelFrame(self.main_frame, text="待转换文件")self.list_frame.pack(fill=tk.BOTH, expand=True, pady=10)# 创建带滚动条的文件列表self.scrollbar = ttk.Scrollbar(self.list_frame)self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)self.file_list = tk.Listbox(self.list_frame,yscrollcommand=self.scrollbar.set,selectmode=tk.EXTENDED,height=8)self.file_list.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)self.scrollbar.config(command=self.file_list.yview)# 状态和进度条self.status_frame = ttk.Frame(self.main_frame)self.status_frame.pack(fill=tk.X, pady=(10, 0))self.progress_var = tk.DoubleVar()self.progress_bar = ttk.Progressbar(self.status_frame,variable=self.progress_var,style='Progress.Horizontal.TProgressbar',mode='determinate',length=500)self.progress_bar.pack(fill=tk.X, pady=5)self.status_var = tk.StringVar(value="就绪")self.status_label = ttk.Label(self.status_frame,textvariable=self.status_var,anchor=tk.W)self.status_label.pack(fill=tk.X)# 控制按钮self.button_frame = ttk.Frame(self.main_frame)self.button_frame.pack(fill=tk.X, pady=10)self.convert_button = ttk.Button(self.button_frame,text="开始转换",command=self.start_conversion,width=15)self.convert_button.pack(side=tk.LEFT, padx=5)self.play_button = ttk.Button(self.button_frame,text="播放音频",command=self.play_audio,width=15,state=tk.DISABLED)self.play_button.pack(side=tk.LEFT, padx=5)self.cancel_button = ttk.Button(self.button_frame,text="取消",command=self.cancel_conversion,width=15)self.cancel_button.pack(side=tk.RIGHT, padx=5)# 初始化变量self.files_to_convert = []self.converting = Falseself.cancel_requested = False# 初始化音频播放器mixer.init()# 配置网格权重self.input_frame.columnconfigure(1, weight=1)self.output_frame.columnconfigure(1, weight=1)def browse_files(self):files = filedialog.askopenfilenames(title="选择音频文件",filetypes=(("音频文件", "*.mp3 *.wav *.ogg *.flac *.aac *.m4a"),("所有文件", "*.*")))if files:self.files_to_convert.extend(files)self.update_file_list()def browse_folder(self):folder = filedialog.askdirectory(title="选择包含音频文件的文件夹")if folder:# 查找文件夹中的音频文件audio_files = []for root, _, files in os.walk(folder):for file in files:if file.lower().endswith(('.mp3', '.wav', '.ogg', '.flac', '.aac', '.m4a')):audio_files.append(os.path.join(root, file))if audio_files:self.files_to_convert.extend(audio_files)self.update_file_list()else:messagebox.showinfo("无音频文件", "所选文件夹中没有找到支持的音频文件")def browse_output(self):folder = filedialog.askdirectory(title="选择输出文件夹")if folder:self.output_entry.delete(0, tk.END)self.output_entry.insert(0, folder)def update_file_list(self):self.file_list.delete(0, tk.END)for file in self.files_to_convert:self.file_list.insert(tk.END, os.path.basename(file))def clear_file_list(self):self.files_to_convert = []self.file_list.delete(0, tk.END)def start_conversion(self):if not self.files_to_convert:messagebox.showwarning("无文件", "请先添加要转换的音频文件")returnoutput_folder = self.output_entry.get().strip()if not output_folder:messagebox.showwarning("无输出目录", "请选择输出目录")returnif not os.path.exists(output_folder):try:os.makedirs(output_folder)except Exception as e:messagebox.showerror("错误", f"无法创建输出目录: {str(e)}")return# 禁用控制按钮self.convert_button.config(state=tk.DISABLED)self.browse_button.config(state=tk.DISABLED)self.output_button.config(state=tk.DISABLED)self.batch_button.config(state=tk.DISABLED)self.clear_button.config(state=tk.DISABLED)self.play_button.config(state=tk.DISABLED)# 重置进度条self.progress_var.set(0)self.converting = Trueself.cancel_requested = False# 在后台线程中运行转换threading.Thread(target=self.convert_files, args=(output_folder,), daemon=True).start()def convert_files(self, output_folder):total_files = len(self.files_to_convert)success_count = 0failed_files = []for i, file_path in enumerate(self.files_to_convert):if self.cancel_requested:breakself.status_var.set(f"正在转换: {os.path.basename(file_path)} ({i + 1}/{total_files})")self.progress_var.set(i / total_files * 100)try:#引入ffmpeg工具路径,非全局变量,如果为全局变量,则下方三行代码可注掉base_dir = os.path.dirname(os.path.abspath(__file__))ffmpeg_path = os.path.join(base_dir, "ffmpeg", "bin", "ffmpeg.exe")         AudioSegment.converter = ffmpeg_pathsound = AudioSegment.from_file(file_path)output_format = self.format_var.get()output_path = os.path.join(output_folder,os.path.splitext(os.path.basename(file_path))[0] + '.' + output_format)sound.export(output_path, format=output_format)success_count += 1except Exception as e:failed_files.append(os.path.basename(file_path))print(f"转换失败: {str(e)}")# 更新进度self.progress_var.set((i + 1) / total_files * 100)# 更新UIself.root.after(0, self.conversion_completed, success_count, total_files, failed_files)def conversion_completed(self, success_count, total_files, failed_files):self.converting = Falseself.progress_var.set(100)# 启用按钮self.convert_button.config(state=tk.NORMAL)self.browse_button.config(state=tk.NORMAL)self.output_button.config(state=tk.NORMAL)self.batch_button.config(state=tk.NORMAL)self.clear_button.config(state=tk.NORMAL)self.play_button.config(state=tk.NORMAL)# 显示结果if success_count == total_files:self.status_var.set(f"转换完成! 成功转换 {success_count} 个文件")messagebox.showinfo("完成", f"成功转换 {success_count} 个文件")else:self.status_var.set(f"转换完成! 成功: {success_count}, 失败: {total_files - success_count}")if failed_files:failed_list = "\n".join(failed_files)messagebox.showwarning("部分完成",f"成功转换 {success_count} 个文件\n失败 {len(failed_files)} 个文件:\n{failed_list}")def cancel_conversion(self):if self.converting:self.cancel_requested = Trueself.status_var.set("正在取消转换...")else:self.root.destroy()def play_audio(self):if not self.files_to_convert:messagebox.showwarning("无文件", "没有可播放的音频文件")return# 获取选中的文件selected_indices = self.file_list.curselection()if not selected_indices:messagebox.showwarning("未选择", "请先选择一个音频文件")returnselected_index = selected_indices[0]if 0 <= selected_index < len(self.files_to_convert):file_path = self.files_to_convert[selected_index]try:# 停止当前播放if mixer.music.get_busy():mixer.music.stop()# 加载并播放音频mixer.music.load(file_path)mixer.music.play()self.status_var.set(f"正在播放: {os.path.basename(file_path)}")except Exception as e:messagebox.showerror("播放错误", f"无法播放音频文件: {str(e)}")if __name__ == "__main__":root = tk.Tk()app = AudioConverterApp(root)root.mainloop()

UI界面效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89855.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89855.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Haproxy算法精简化理解及企业级高功能实战

文章目录4. Haproxy的算法4.1 静态算法4.1.1 static-rr&#xff1a;基于权重的轮询调度1. 示例&#xff1a;4.1.2 first1. 示例2. 测试效果&#xff1a;4.2 动态算法4.2.1 roundrobin1. 示例2. 动态调整权重4.2.2 leastconn1. 示例4.3 其他算法4.3.1 source1. 示例2. 测试4.3.2…

git fork的项目远端标准协作流程 仓库设置[设置成upstream]

这是一个在开源协作中非常常见的配置。 简单来说&#xff0c;upstream 在这里指的是你 Fork 来的那个原始的、官方的仓库。 下面我们来详细解释一下这个 git remote -v 输出的含义&#xff1a; 1. 两条“遥控器” (Remotes) 你的 git 配置了两个远程仓库的地址&#xff0c;就像…

[FFmpeg] 输入输出访问 | 管道系统 | AVIOContext 与 URLProtocol | 门面模式

链接&#xff1a;https://trac.ffmpeg.org/ docs&#xff1a;FFmpeg FFmpeg 是一个强大的多媒体框架&#xff0c;旨在处理媒体处理的各个阶段。 它就像一个数字媒体工厂&#xff0c;包含以下部门&#xff1a;打包/解包&#xff08;容器处理&#xff09;、 转译/压缩&#xff…

微服务的编程测评系统2

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言工程创建创建ck-oj创建oj-modules创建具体微服务oj-system推送码云管理员登录逻辑分析docker安装mysqldocker客户端docker desktop安装安装mysqlmysql-plus和数据…

AR智能巡检:电力运维的数字化变革

在电力行业快速发展的当下&#xff0c;传统运维方式已难以满足现代电网对高效、安全的需求。近年来&#xff0c;增强现实&#xff08;AR www.teamhelper.cn &#xff09;技术的兴起为电力巡检带来了全新的解决方案。通过实时数据可视化、远程协作和智能分析&#xff0c;AR技术…

NeRF和3DGS原理详细

NeRF和3DGS一、传统三维表征方法1.1 显示表征1.2 隐式表征二、NeRF&#xff08;Nerual Radiance Field&#xff09;2.1 NeRF场景表示2.2 NeRF训练流程2.3 NeRF体渲染2.4 NeRF位置编码2.5 NeRF体素分层采样&#xff08;Volume Hierarchical Sampling&#xff09;2.6 NeRF网络结构…

035_ClaudeCode_MCP_介绍

035_ClaudeCode_MCP_介绍 摘要 Model Context Protocol&#xff08;MCP&#xff09;是一个开放的标准化协议&#xff0c;专为大型语言模型提供上下文数据而设计。作为Claude Code生态系统的重要组成部分&#xff0c;MCP如同"AI应用程序的USB-C端口"&#xff0c;提供…

Python 程序无法找到 Oracle 的 64 位客户端库 (libclntsh.so)

数据库错误: DPI-1047: Cannot locate a 64-bit Oracle Client library: "libclntsh.so: cannot open shared object file: No such file or directory". See https://oracle.github.io/odpi/doc/installation.html#linux for help 这个错误表明 Python 程序无法找到…

Kubernetes常用命令总结

文章目录Kubernetes常用命令总结1. 集群管理命令kubectl cluster-infokubectl get nodeskubectl describe node <node-name>kubectl top nodes2. Pod相关命令kubectl get podskubectl get pods -o widekubectl describe pod <pod-name>kubectl logs <pod-name&g…

roboflow使用教程

如何利用roboflow标注自己的训练集、调用开源数据集 官网&#xff1a;Roboflow: Computer vision tools for developers and enterprises&#xff08;国内代理进不去&#xff09; 先注册登陆进去 训练自己的数据集 点击“New Project”,名字按照自己的需求来 我不想写了&am…

IDEA中使用Tomcat两种方式

Catalogue1 集成本地Tomcat2 Tomcat Maven插件&#xff08;推荐&#xff09;1 集成本地Tomcat 将本地Tomcat集成到Idea中&#xff0c;然后进行项目部署即可 点击编辑配置 点击加号 添加local的Tomcat 配置Application Server 可以修改一下Name 至此&#xff0c;配置完成 …

服务器上的文件复制到本地 Windows 系统

在 Windows 上通过 SSH 连接到 Linux 服务器后&#xff0c;如果需要将服务器上的文件复制到本地 Windows 系统&#xff0c;可以使用以下几种方法&#xff1a;方法 1&#xff1a;使用 scp&#xff08;Secure Copy&#xff09;命令 scp&#xff08;基于 SSH 的安全复制&#xff0…

大语言模型置信度增强实战指南

LLM怎么简单增强置信度 在大语言模型(LLM)的应用中,“置信度增强”核心目标是提升模型输出的可靠性(减少错误/幻觉) 并让模型更清晰地表达自身的不确定性(避免“一本正经地胡说”)。常用方式可分为“输出优化”“知识补充”“校准调整”三大类, 一、基于“推理过程优…

NLP:人名分类器案例分享

本文目录&#xff1a;一、案例介绍&#xff08;一&#xff09;关于人名分类&#xff08;二&#xff09;人名分类数据预览二、案例步骤&#xff08;一&#xff09;导入工具包&#xff08;二&#xff09;数据预处理1. 获取常用的字符数量2. 国家名种类数和个数3.读数据到内存4.构…

3分钟实战!用DeepSeek+墨刀AI生成智能对话APP原型图

如今&#xff0c;AI生成原型图已经逐渐成为产品经理的一项常用辅助技能&#xff0c;不仅能加快设计进程&#xff0c;还能显著提升前期沟通效率。最近我尝试将大语言模型工具与AI原型工具结合测试&#xff0c;目标是看看是否能生成更高质量的原型页面。直到我使用DeepSeek墨刀AI…

CentOS网络配置与LAMP环境搭建指南

一、CentOS配置网络1、查看网卡名称ifconfig2、找到网卡对应配置文件网卡存放路径 &#xff1a;/etc/sysconfig/network-scriptscd /etc/sysconfig/network-scripts3、修改网卡对应配置文件使用 vi/vim 打开文件&#xff0c;查看以下内容vim ifcfg-ens33将ONBOOTno 改为 ONBOOT…

TinyMCE 富文本编辑器在 vue2 中的使用 @tinymce/tinymce-vue

TinyMCE是一款功能强大、高度可定制的富文本编辑器。官方文档 TinyMCE DOCS tinymce-vue包的版本4及更高版本支持Vue.js 3。但不支持Vue.js 2.x。对于Vue.js 2。X应用程序&#xff0c;使用tinymce-vue版本3。 安装TinyMCE和Vue集成包 npm install tinymce/tinymce-vue3 tiny…

LP-MSPM0G3507学习--04GPIO控制

关键函数&#xff1a; DL_GPIO_readPins(GPIO_Regs* gpio, uint32_t pins):同时读一组端口DL_GPIO_writePins(GPIO_Regs* gpio, uint32_t pins)&#xff1a;同时写一组端口DL_GPIO_setPins(GPIO_Regs* gpio, uint32_t pins)&#xff1a;对指定某组端口的某管脚置高DL_GPIO_cle…

LVS(Linux virtual server)-实现四层负载均衡

一、简介LVS:Linux Virtual Server&#xff0c;负载调度器&#xff0c;内核集成&#xff0c;章文嵩&#xff0c;阿里的四层SLB(Server LoadBalance)是基 于LVSkeepalived实现LVS 官网: http://www.linuxvirtualserver.org/二、LVS运行原理2.1LVS 的集群结构2.2lvs相关概念RS&am…

Kubernetes CNI网络插件性能瓶颈排查与优化实践

Kubernetes CNI网络插件性能瓶颈排查与优化实践 CNI&#xff08;Container Network Interface&#xff09;是 Kubernetes 网络层的核心组件&#xff0c;不同 CNI 插件实现了容器间网络通信、多租户隔离、流量限速等功能。然而在大规模集群或高并发业务场景下&#xff0c;CNI 插…