python用tkinter写了一个文本转音频的可视化界面,音频转化用的是ffmpeg,具体代码如下
# 判断想要生成的音频类型
# 调用ffmpeg进行音频转换
try:
if audio_type == "mp3":
command = create_mp3_command(file_path, save_path, sample_rate, bitrate, audio_channel)
subprocess.run(command)
else :
command = create_wav_command(file_path, save_path, sample_rate, bitrate, sample_format, audio_channel)
subprocess.run(command)
# 裁剪生成的音频
trim_silence(save_path, save_path, audio_type, sample_rate, bitrate)
res = f"Audio saved in {save_path}"
# print(res)
return (True,res)
except Exception as e:
res = f"Exception occurred: {e}"
# print(res)
return (False, res)
在上面的代码中,我通过对想要生成的音频格式来生成不同的处理命令
# 返回ffmpeg的处理MP3的command
def create_mp3_command(file_path, save_path, sample_rate, bitrate, audio_channel):
"""
构建 ffmpeg 命令的函数
:param file_path: 输入文件路径 (str)
:param save_path: 输出文件路径 (str)
:param sample_rate: 采样率 (str)
:param bitrate: 比特率 (str)
:param sample_format: 采样格式 (str)
:param audio_channel: 声道数 (str)
:return: ffmpeg 命令列表 (list)
"""
command = [
"ffmpeg",
"-i", file_path,
"-loglevel", "quiet", # 屏蔽ffmpeg log
"-ar", sample_rate, # 设置采样率为 16kHz
"-b:a", bitrate, # 设置比特率为 40kbps
"-ac", audio_channel, # 设置音频通道数为 2(立体声)
"-c:a", "libmp3lame", # 使用libmp3lame编码器
"-q:a", "9", # 设置质量参数为 9,确保使用恒定比特率
"-filter:a", f"volume=1.5", # 调整音量
"-y", save_path # 覆盖输出文件
]
return command
# 返回ffmpeg的处理wav的command
def create_wav_command(file_path, save_path, sample_rate, bitrate, sample_format, audio_channel):
"""
构建 ffmpeg 命令的函数
:param file_path: 输入文件路径 (str)
:param save_path: 输出文件路径 (str)
:param sample_rate: 采样率 (str)
:param bitrate: 比特率 (str)
:param sample_format: 采样格式 (str)
:param audio_channel: 声道数 (str)
:return: ffmpeg 命令列表 (list)
"""
command = [
"ffmpeg",
"-i", file_path,
"-loglevel", "quiet", # 屏蔽 ffmpeg log
"-ar", sample_rate, # 采样率
"-ac", audio_channel, # 声道数
"-b:a", bitrate, # 比特率
"-sample_fmt", data_list.BIT_DEPTH[sample_format], # 采样格式
"-filter:a", "volume=1.5", # 调整音量
"-y", # 覆盖输出文件
save_path
]
return command
根据MP3和wav生成不同的命令
在界面中,我有一个主界面,点击按钮button会开启子线程来运行该音频转换,并且弹出一个进度调的弹窗,代码如下:
check_value = utils.check_value(speech_key, service_region, self.file_path, self.save_path)
if check_value[0]:
config.FILE_PATH = self.save_path
# 初始化总进度数初始化为100
progress_window = ProgressWindow(total_progress=100)
threading.Thread(target=utils.start_transform, args=(progress_window, self.file_path, self.save_path, language, speed, audio_type, sample_rate, bitrate, sample_format, audio_channel)).start()
progress_window.start_progress()
else:
messagebox.showerror("输入错误", check_value[1])
# 防止编译的exe出现命令窗口
subprocess.run(command, creationflags=subprocess.CREATE_NO_WINDOW)
在添加了creationflags=subprocess.CREATE_NO_WINDOW之后,我生成wav文件确实没有了命令弹窗,但是,当我切换到MP3,命令窗口还是没有消失
command = create_mp3_command(file_path, save_path, sample_rate, bitrate, audio_channel)
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
subprocess.run(command, startupinfo=startupinfo, creationflags=subprocess.CREATE_NO_WINDOW)
据说如此修改可以比上者更加有效的屏蔽命令窗口
但是以上方法都没有作用,mp3的subprocess还是会照样弹出命令窗口,有人遇到过此类问题吗?有什么解决方法吗?求帮助
你这个wav和mp3命令没区别啊. wav用CREATE_NO_WINDOW可以,mp3应该也可以才对.是不是mp3忘了加CREATE_NO_WINDOW了
加了的,运行出来wav没问题,mp3就是有弹窗,都快碎了,找不到原因
@qricis: 我试了你的代码,没有你说的问题
import tkinter
import tkinter.messagebox
import subprocess
# 返回ffmpeg的处理MP3的command
def create_mp3_command(file_path, save_path, sample_rate, bitrate, audio_channel):
"""
构建 ffmpeg 命令的函数
:param file_path: 输入文件路径 (str)
:param save_path: 输出文件路径 (str)
:param sample_rate: 采样率 (str)
:param bitrate: 比特率 (str)
:param sample_format: 采样格式 (str)
:param audio_channel: 声道数 (str)
:return: ffmpeg 命令列表 (list)
"""
command = [
"ffmpeg",
"-i", file_path,
"-loglevel", "quiet", # 屏蔽ffmpeg log
"-ar", sample_rate, # 设置采样率为 16kHz
"-b:a", bitrate, # 设置比特率为 40kbps
"-ac", audio_channel, # 设置音频通道数为 2(立体声)
"-c:a", "libmp3lame", # 使用libmp3lame编码器
"-q:a", "9", # 设置质量参数为 9,确保使用恒定比特率
"-filter:a", f"volume=1.5", # 调整音量
"-y", save_path # 覆盖输出文件
]
return command
# 返回ffmpeg的处理wav的command
def create_wav_command(file_path, save_path, sample_rate, bitrate, sample_format, audio_channel):
"""
构建 ffmpeg 命令的函数
:param file_path: 输入文件路径 (str)
:param save_path: 输出文件路径 (str)
:param sample_rate: 采样率 (str)
:param bitrate: 比特率 (str)
:param sample_format: 采样格式 (str)
:param audio_channel: 声道数 (str)
:return: ffmpeg 命令列表 (list)
"""
command = [
"ffmpeg",
"-i", file_path,
"-loglevel", "quiet", # 屏蔽 ffmpeg log
"-ar", sample_rate, # 采样率
"-ac", audio_channel, # 声道数
"-b:a", bitrate, # 比特率
"-sample_fmt", sample_format, # 采样格式
"-filter:a", "volume=1.5", # 调整音量
"-y", # 覆盖输出文件
save_path
]
return command
audio_type = "wav"
file_path = "dtmf.wav"
save_path = "dtmf_out.wav"
sample_rate = "8000"
bitrate = "40000"
audio_channel = "1"
sample_format = "s16"
root = tkinter.Tk()
def mp3():
command = create_mp3_command(file_path, save_path, sample_rate, bitrate, audio_channel)
subprocess.run(command, creationflags=subprocess.CREATE_NO_WINDOW)
btnMp3 = tkinter.Button(root, text='mp3', command=mp3)
btnMp3.place(x=30, y=70, width=50, height=20)
def wav():
command = create_wav_command(file_path, save_path, sample_rate, bitrate, sample_format, audio_channel)
subprocess.run(command, creationflags=subprocess.CREATE_NO_WINDOW)
btnWav = tkinter.Button(root, text='wav', command=wav)
btnWav.place(x=90, y=70, width=50, height=20)
root.mainloop()
@www378660084: 我试了你的没有问题,但是我的是会弹出的,是因为试运行在的子线程
![](https://img2024.cnblogs.com/blog/3491085/202407/3491085-20240726172900952-994337261.png)
这一点前提忘记说了!!
@qricis: 我觉得跟子线程也没关系.可能跟你进度条的实现有点关系,你可以在这个基础上试试,看看添加什么代码会弹出窗口
import tkinter
import tkinter.messagebox
import subprocess
import threading
# 返回ffmpeg的处理MP3的command
def create_mp3_command(file_path, save_path, sample_rate, bitrate, audio_channel):
"""
构建 ffmpeg 命令的函数
:param file_path: 输入文件路径 (str)
:param save_path: 输出文件路径 (str)
:param sample_rate: 采样率 (str)
:param bitrate: 比特率 (str)
:param sample_format: 采样格式 (str)
:param audio_channel: 声道数 (str)
:return: ffmpeg 命令列表 (list)
"""
command = [
"ffmpeg",
"-i", file_path,
"-loglevel", "quiet", # 屏蔽ffmpeg log
"-ar", sample_rate, # 设置采样率为 16kHz
"-b:a", bitrate, # 设置比特率为 40kbps
"-ac", audio_channel, # 设置音频通道数为 2(立体声)
"-c:a", "libmp3lame", # 使用libmp3lame编码器
"-q:a", "9", # 设置质量参数为 9,确保使用恒定比特率
"-filter:a", f"volume=1.5", # 调整音量
"-y", save_path # 覆盖输出文件
]
return command
# 返回ffmpeg的处理wav的command
def create_wav_command(file_path, save_path, sample_rate, bitrate, sample_format, audio_channel):
"""
构建 ffmpeg 命令的函数
:param file_path: 输入文件路径 (str)
:param save_path: 输出文件路径 (str)
:param sample_rate: 采样率 (str)
:param bitrate: 比特率 (str)
:param sample_format: 采样格式 (str)
:param audio_channel: 声道数 (str)
:return: ffmpeg 命令列表 (list)
"""
command = [
"ffmpeg",
"-i", file_path,
"-loglevel", "quiet", # 屏蔽 ffmpeg log
"-ar", sample_rate, # 采样率
"-ac", audio_channel, # 声道数
"-b:a", bitrate, # 比特率
"-sample_fmt", sample_format, # 采样格式
"-filter:a", "volume=1.5", # 调整音量
"-y", # 覆盖输出文件
save_path
]
return command
audio_type = "wav"
file_path = "dtmf.wav"
save_path = "dtmf_out.wav"
sample_rate = "8000"
bitrate = "40000"
audio_channel = "1"
sample_format = "s16"
root = tkinter.Tk()
def mp3():
def go():
command = create_mp3_command(file_path, save_path, sample_rate, bitrate, audio_channel)
subprocess.run(command, creationflags=subprocess.CREATE_NO_WINDOW)
threading.Thread(target=go).start()
btnMp3 = tkinter.Button(root, text='mp3', command=mp3)
btnMp3.place(x=30, y=70, width=50, height=20)
def wav():
def go():
command = create_wav_command(file_path, save_path, sample_rate, bitrate, sample_format, audio_channel)
subprocess.run(command, creationflags=subprocess.CREATE_NO_WINDOW)
threading.Thread(target=go).start()
btnWav = tkinter.Button(root, text='wav', command=wav)
btnWav.place(x=90, y=70, width=50, height=20)
root.mainloop()
@www378660084: 我刚尝试把所有与progress_window的代码都屏蔽了,程序还是会弹出命令窗口o(╥﹏╥)o,所以跟进度条还是没关系,会跟代码分几个py文件写有关吗?
@www378660084: 在调用ffmpeg,是在循环当中的,以下是循环的代码
# 当生成的音频文件数量小于获取到的表格中的行数时,循环
while(total_progress):
# 获取两者中的非交集
files_list = list(processed_set-set(files))
# 将非交集的数据生成音频
for file in files_list:
# 文本转音频
result = azure_utils.synthesize_speech_with_ssml(file, language, speed, audio_type)
# 使用ffmpeg对音频进行处理
ffpmeg_result = ffmpeg_utils.get_ffmpeg_para(result, file, audio_type, sample_rate, bitrate, sample_format, audio_channel)
if ffpmeg_result[0]:
pg_window.update_progress(ffpmeg_result[1])
pg_window.increment_progress()
else:
pg_window.update_progress(ffpmeg_result[1])
pg_window.finish_button.config(state=tk.NORMAL)
delete_dir(config.TEMP)
delete_dir(config.RELEASE)
return
# 重新计算生成的音频文件数量
files = selectFile(save_path)
# 初始化进度条的长度
total_progress = len(processed_set - set(files))
if (total_progress > 0) :
pg_window.reset_progress()
pg_window.set_progress(total_progress)
else :
pg_window.update_progress("Finish")
delete_dir(config.TEMP)
break
pg_window.finish_button.config(state=tk.NORMAL)
几天把代码拆解了,终于找到了命令窗口弹出的原因,不在之前的界面,在运行之后的音频裁剪部分:
# 裁剪音频,将整段音频的前后空白处裁剪到20ms左右
def trim_silence(audio_path, output_path, audio_type, sample_rate, bitrate, silence_duration=100, trim_buffer=20, silence_thresh=-30, chunk_size=10):
# 加载音频文件
audio = AudioSegment.from_file(audio_path)
# 检测非静音部分
nonsilent_ranges = detect_nonsilent(audio, min_silence_len=chunk_size, silence_thresh=silence_thresh)
# 如果找到非静音部分
if nonsilent_ranges:
start_trim = max(0, nonsilent_ranges[0][0] - trim_buffer)
end_trim = min(len(audio), nonsilent_ranges[-1][1] + trim_buffer)
# 修剪音频
trimmed_audio = audio[start_trim:end_trim]
else:
# 如果整段音频都是静音,返回原音频
trimmed_audio = audio
# 创建指定时长的静音
silence = AudioSegment.silent(duration=int(silence_duration), frame_rate=int(sample_rate))
# 将静音添加到音频文件的前后
padded_audio = silence + trimmed_audio + silence
# 删除旧文件(如果存在)
if os.path.exists(output_path):
os.remove(output_path)
# 保存添加静音后的音频文件
padded_audio.export(output_path, format=audio_type, bitrate=bitrate)
以上代码造成了mp3文件输出反复出现弹窗,尝试查找原因
原因已找到,在上述代码中,有两行代码可能内部调用了ffmpeg的命令,因此造成了命令窗口的弹出:
# 裁剪音频,将整段音频的前后空白处裁剪到20ms左右
def trim_silence(audio_path, output_path, audio_type, sample_rate, bitrate, silence_duration=100, trim_buffer=20, silence_thresh=-30, chunk_size=10):
# 加载音频文件 内部调用了ffmpeg
audio = AudioSegment.from_file(audio_path)
# 保存添加静音后的音频文件 内部同样调用了ffmpeg
padded_audio.export(output_path, format=audio_type, bitrate=bitrate)
将上述代码修改为直接使用ffmpeg即可:
# 裁剪音频前后端的静音部分
def trim_silence(audio_path, output_path, audio_type, sample_rate, bitrate, silence_duration=100, silence_thresh=-60, chunk_size=10):
# 临时文件
temp_output_start_trim = "temp_output_start_trim." + audio_type
temp_output_end_trim = "temp_output_end_trim." + audio_type
# 去除开头静音
input_audio = ffmpeg.input(audio_path)
filtered_audio_start_trim = (
input_audio
.filter('silenceremove', start_periods=1, start_duration=chunk_size / 1000, start_threshold=f'{silence_thresh}dB',
stop_periods=0, stop_duration=0, stop_threshold=f'{silence_thresh}dB')
.output(temp_output_start_trim, ar=sample_rate, ac=1, b=bitrate, format=audio_type)
.overwrite_output()
)
command = ffmpeg.compile(filtered_audio_start_trim)
subprocess.run(command, creationflags=subprocess.CREATE_NO_WINDOW)
# 去除结尾静音
input_audio_trimmed = ffmpeg.input(temp_output_start_trim)
filtered_audio_end_trim = (
input_audio_trimmed
.filter('silenceremove', start_periods=0, start_duration=0, start_threshold=f'{silence_thresh}dB',
stop_periods=1, stop_duration=chunk_size / 1000, stop_threshold=f'{silence_thresh}dB')
.output(temp_output_end_trim, ar=sample_rate, ac=1, b=bitrate, format=audio_type)
.overwrite_output()
)
command = ffmpeg.compile(filtered_audio_end_trim)
subprocess.run(command, creationflags=subprocess.CREATE_NO_WINDOW)
# 加载处理后的音频并添加静音部分
trimmed_audio = ffmpeg.input(temp_output_end_trim)
silence = ffmpeg.input('anullsrc=r=' + sample_rate, f='lavfi', t=silence_duration / 1000)
# 创建输出音频,将静音部分添加到前后
padded_audio = ffmpeg.concat(silence, trimmed_audio, silence, v=0, a=1)
output_audio = padded_audio.output(output_path, ar=sample_rate, ac=1, b=bitrate, format=audio_type).overwrite_output()
# 运行FFmpeg命令并捕获错误
# run_ffmpeg_command(output_audio)
command = ffmpeg.compile(output_audio)
subprocess.run(command, creationflags=subprocess.CREATE_NO_WINDOW)
# 删除临时文件
if os.path.exists(temp_output_start_trim):
os.remove(temp_output_start_trim)
if os.path.exists(temp_output_end_trim):
os.remove(temp_output_end_trim)
特此记录
已找到问题所在地,详情请见内部评论
应该是你用的这个库在加载mp3信息时候调用了cmd,这个库有人提过这个问题 https://github.com/jiaaro/pydub/issues/698
@www378660084: 谢谢!我去看看