多线程的音频打标记的python实现(原创)
技术难度:
①需要一个UI界面,并且其中可进行相关参数的自调,最开始使用的是pygame的框架,后来转用tk界面;
②需要可以播放音频文件,MP3、WMA等格式;
③需要在播放音频的同时进行打标签操作,多线程技术;
④对音频进行相关拆分、叠加、重组,使用ffmpeg库进行相关操作;
一,UI界面
二,文件内容
使用 双击启动音频标记程序.bat 文件进行相对位置的文件启动,并且在 lib 中把所需的 ffmpeg 文件都已加载进去
三,程序源码
其中使用 threading 库的多线程功能,并且也使用到tk按钮中传递对象的功能。
1 #-*- coding:utf-8 -*- 2 #edited by Mufasa 3 #文本标记软件 4 5 # import pygame #已经确定 6 import time 7 import threading 8 import tkinter,time,decimal,math,string,os 9 import tkinter.filedialog 10 import shutil 11 import tkinter as tk 12 import subprocess 13 from pydub import AudioSegment #已经确定 14 15 16 def out_comma(data,num_1,num_2): 17 txt='' 18 if len(data)==1: 19 for n in range(num_2): 20 txt=txt+data[0]+',' 21 txt=txt[:-1]+'。' 22 else: 23 for i in data: 24 for n in range(num_1): 25 txt=txt+i+',' 26 if num_1!=0: 27 txt=txt[:-1]+'。' 28 for n in range(num_2): 29 for i in data: 30 txt=txt+i+',' 31 txt=txt[:-1]+'。' 32 return txt 33 34 35 36 37 class assist(): 38 def write_txt_data(data,path): 39 ls = os.linesep 40 #data 为数组类型 41 fobj = open(path,'w') 42 fobj.writelines(['%s%s'%(x,ls)for x in data]) 43 fobj.close() 44 def read_txt_data(path): 45 fobj = open(path,'r') 46 string = [] 47 for eachline in fobj: 48 if eachline[:-1] != '': 49 string.append(eachline[:-1]) 50 fobj.close() 51 return string 52 53 54 class out_aboutcode(tk.Toplevel): 55 def __init__(self): 56 super().__init__() 57 self.title('关于程序')# 弹窗界面 58 self.setup_UI() 59 def setup_UI(self): 60 row1 = tk.Frame(self) 61 row1.pack(fill="x") 62 # tk.Label(row1, text='欢迎使用音频标记软件!软件基于Python36设计\n\n使用说明:\n1,先选择需要进行标记的音频文件;\n2,点击——标记音频按钮,开始进行标记其中[ , ]符为小段标记点,[ . ]为大段标记点;\n3,标记的音频播放完毕后,点击—生成标记按钮,直接转换成标记文件并存储在\\data\\文件名\\目录下;\n\n欢迎使用').pack(side=tk.LEFT) 63 tk.Label(row1, text='欢迎使用音频标记软件!软件基于Python36设计\n\n使用说明:\n1,先点击[ 选择音频 ],选定您要进行标记的音频文件(默认支持MP3和wav格式)\n2,点击[ 标记音频 ],在文件的文本输入框中输入 , . 这两种符号分别进行小段和大段标记\n3,点击[ 生成标记 ],将音频的标记信息进行存储\n4,点击[ 设置音频 ],对音频的播放模式进行个性化设置\n\n祝使用愉快(*^_^*)').pack(side=tk.LEFT) 64 65 row4 = tk.Frame(self) 66 row4.pack(fill="x") 67 tk.Button(row4, text="关闭窗口", command=self.cancel).pack(side=tk.RIGHT) 68 def cancel(self): 69 self.destroy() 70 71 ''' 72 data_set.txt 73 [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] 74 程序A ["逗号次数","逗号停顿","句号次数","句号停顿" , "大段次数" , "大段停顿" , "全体音频文件播放次数" , "产生此音频"] 75 [3,0,3,0,1,1,2,1] 76 A 0 1 2 3 77 [3,0,3,0,1,1,2,1,3,0,0,0,1,1,0,1] 78 79 ["3","0","3","0","1","1","2","1","3","0","0","0","1","1","0","1"] 80 81 [3,0,0,0,1,1,0,1] 82 程序B ["逗号次数","逗号停顿","句号次数","句号停顿" , "大段次数" , "大段停顿" , "全体音频文件播放次数" , "产生此音频"] 83 ''' 84 85 class out_setconfig(tk.Toplevel): 86 def __init__(self): 87 super().__init__() 88 self.title('参数设置')# 弹窗界面 89 self.data_set_path = os.path.dirname(os.path.realpath(__file__))+"\\data_set.txt" 90 isExists = os.path.exists(self.data_set_path ) 91 if isExists == False: #bug,之前没有设置 92 self.setup_eror() 93 else: 94 self.setup_UI() 95 96 def setup_eror(self): 97 row1 = tk.Frame(self) 98 row1.pack(fill="x") 99 tk.Label(row1, text='程序第一次运行!\n\n已进行参数初始化操作\n').pack(side=tk.LEFT) 100 row4 = tk.Frame(self) 101 row4.pack(fill="x") 102 assist.write_txt_data(["3","0","3","0","1","1","2","1","3","0","1","0","2","0","0","1"],self.data_set_path ) 103 tk.Button(row4, text="关闭窗口", command=self.cancel).pack(side=tk.RIGHT) 104 def setup_UI(self): 105 106 self.A00 = tk.StringVar() 107 self.A01 = tk.StringVar() 108 self.A10 = tk.StringVar() 109 self.A11 = tk.StringVar() 110 self.A20 = tk.StringVar() 111 self.A21 = tk.StringVar() 112 self.A30 = tk.StringVar() 113 # self.chvarEn = tk.IntVar() 114 self.A31 = tk.IntVar() 115 116 self.B00 = tk.StringVar() 117 self.B01 = tk.StringVar() 118 self.B10 = tk.StringVar() 119 self.B11 = tk.StringVar() 120 self.B20 = tk.StringVar() 121 self.B21 = tk.StringVar() 122 self.B30 = tk.StringVar() 123 self.B31 = tk.IntVar() 124 125 data = assist.read_txt_data(self.data_set_path) 126 # print(data) 127 self.A00.set(data[0]) 128 self.A01.set(data[1]) 129 self.A10.set(data[2]) 130 self.A11.set(data[3]) 131 self.A20.set(data[4]) 132 self.A21.set(data[5]) 133 self.A30.set(data[6]) 134 # d = int(data[7]) 135 # self.A31.set(d) 136 137 self.B00.set(data[8]) 138 self.B01.set(data[9]) 139 self.B10.set(data[10]) 140 self.B11.set(data[11]) 141 self.B20.set(data[12]) 142 self.B21.set(data[13]) 143 self.B30.set(data[14]) 144 # d = int(data[15]) 145 # self.B31.set(d) 146 # self.B31.set(int(data[15])) 147 148 row1 = tk.Frame(self) 149 row1.pack(fill="x") 150 151 tk.Label(row1,text='程序A',width=30 ).grid(row=0,column=0,columnspan=2) 152 tk.Label(row1,text='逗号次数:',width=15).grid(row=1,column=0) 153 tk.Label(row1,text='逗号停顿(秒):',width=15).grid(row=2,column=0) 154 tk.Label(row1,text='句号次数:',width=15).grid(row=3,column=0) 155 tk.Label(row1,text='句号停顿(秒)',width=15).grid(row=4,column=0) 156 tk.Label(row1,text='括号次数',width=15).grid(row=5,column=0) 157 tk.Label(row1,text='括号停顿(秒)',width=15).grid(row=6,column=0) 158 tk.Label(row1,text='全部音频次数',width=15).grid(row=7,column=0) 159 tk.Label(row1,text='是否生成音频',width=15).grid(row=8,column=0) 160 161 162 tk.Entry(row1, textvariable=self.A00, width=13).grid(row=1,column=1) 163 tk.Entry(row1, textvariable=self.A01, width=13).grid(row=2,column=1) 164 tk.Entry(row1, textvariable=self.A10, width=13).grid(row=3,column=1) 165 tk.Entry(row1, textvariable=self.A11, width=13).grid(row=4,column=1) 166 tk.Entry(row1, textvariable=self.A20, width=13).grid(row=5,column=1) 167 tk.Entry(row1, textvariable=self.A21, width=13).grid(row=6,column=1) 168 tk.Entry(row1, textvariable=self.A30, width=13).grid(row=7,column=1) 169 checkA = tk.Checkbutton(row1, text="播放", variable=self.A31) 170 checkA.select() 171 checkA.grid(column=1, row=8, sticky=tk.W) 172 173 174 tk.Label(row1,text='程序B',width=30 ).grid(row=0,column=2,columnspan=2) 175 tk.Label(row1,text='逗号次数:',width=15).grid(row=1,column=2) 176 tk.Label(row1,text='逗号停顿(秒):',width=15).grid(row=2,column=2) 177 tk.Label(row1,text='句号次数:',width=15).grid(row=3,column=2) 178 tk.Label(row1,text='句号停顿(秒)',width=15).grid(row=4,column=2) 179 tk.Label(row1,text='大段次数',width=15).grid(row=5,column=2) 180 tk.Label(row1,text='大段停顿(秒)',width=15).grid(row=6,column=2) 181 tk.Label(row1,text='全部音频次数',width=15).grid(row=7,column=2) 182 tk.Label(row1,text='是否生成音频',width=15).grid(row=8,column=2) 183 184 185 tk.Entry(row1, textvariable=self.B00, width=13).grid(row=1,column=3) 186 tk.Entry(row1, textvariable=self.B01, width=13).grid(row=2,column=3) 187 tk.Entry(row1, textvariable=self.B10, width=13).grid(row=3,column=3) 188 tk.Entry(row1, textvariable=self.B11, width=13).grid(row=4,column=3) 189 tk.Entry(row1, textvariable=self.B20, width=13).grid(row=5,column=3) 190 tk.Entry(row1, textvariable=self.B21, width=13).grid(row=6,column=3) 191 tk.Entry(row1, textvariable=self.B30, width=13).grid(row=7,column=3) 192 checkB = tk.Checkbutton(row1, text="播放", variable=self.B31) 193 checkB.select() 194 checkB.grid(column=3, row=8, sticky=tk.W) 195 self.A31.set(int(data[7])) 196 self.B31.set(int(data[15])) 197 198 tk.Button(row1, text="取消", command=self.cancel, width=13).grid(row=9,column=0) 199 tk.Button(row1, text="确定", command=self.ok, width=13).grid(row=9,column=3) 200 201 def ok(self): 202 self.userinfo_A = [self.A00.get(), self.A01.get(),self.A10.get(),self.A11.get(),self.A20.get(),self.A21.get(),self.A30.get(),self.A31.get()] # 设置数据 203 self.userinfo_B = [self.B00.get(), self.B01.get(),self.B10.get(),self.B11.get(),self.B20.get(),self.B21.get(),self.B30.get(),self.B31.get()] # 设置数据 204 # print(self.userinfo) 205 # print(self.userinfo_A[7]) 206 # print(self.userinfo_B[7]) 207 self.userinfo_A[7] = str(self.userinfo_A[7]) 208 self.userinfo_B[7] = str(self.userinfo_B[7]) 209 data = self.userinfo_A + self.userinfo_B 210 # print(data) 211 assist.write_txt_data(data,os.path.dirname(os.path.realpath(__file__))+"\\data_set.txt") 212 self.destroy() # 销毁窗口 213 def cancel(self): 214 self.userinfo = None # 空! 215 self.destroy() 216 217 ################################ 218 class main_code(tk.Tk): 219 def __init__(self): 220 super().__init__() 221 self.audio_path = "" 222 self.run = True 223 self.vartext = tkinter.StringVar() 224 225 self.txt='' 226 227 228 self.mark_text = '欢迎使用!' 229 self.insert_text = '' 230 self.vartext.set(self.mark_text) 231 self.filename = "" 232 self.audio_path = "" 233 self.audio_len = 0 234 self.data_play = [] 235 self.sound = 0 236 self.title('音频标记') 237 self.setupUI() 238 239 def setupUI(self): 240 241 242 row4 = tk.Frame(self) 243 row4.pack(fill="x") 244 245 tk.Button(row4,text='导入文本',width=27,command=self.select).grid(row=0,column=0) 246 tk.Button(row4,text='设置文本',width=27,command=self.setup_config).grid(row=0,column=1) 247 tk.Button(row4,text='生成文本',width=27,command=self.lay).grid(row=0,column=2) 248 249 label = tkinter.Label(row4,height=3,textvariable=self.vartext, bg='white', font=('黑体', 10), anchor='w').grid(row=1,column=0,columnspan=3) 250 251 252 entry1 = tkinter.Entry(row4,width=85) 253 entry1.bind('<Key>', self.insert_mark) 254 entry1.grid(row=2,column=0,columnspan=3) 255 self.insert_text = entry1.get() 256 257 258 def select(self): #获取audio_path和audio_len 259 self.audio_path = tkinter.filedialog.askopenfilename(initialdir = 'C:\\Users\\Administrator\\Desktop',filetypes=( ("txt or docx files", "*.txt;*.docx"),("All files", "*.*"))) 260 if self.audio_path=="": 261 self.vartext.set('未导入任何文件') 262 else: 263 p,f=os.path.split(self.audio_path) 264 path = os.path.dirname(os.path.realpath(__file__)) + '\\data\\' + str(os.path.splitext(f)[0]) 265 isExists = os.path.exists(path) 266 if not isExists: #如果不存在这个目录 267 os.makedirs(path) #创建一个新的路径 268 shutil.copyfile(self.audio_path,path+'\\'+f) 269 if str(os.path.splitext(f)[1])=='.txt': 270 file_object = open(self.audio_path,'r', encoding='UTF-8') 271 try: 272 file_context = file_object.read() 273 finally: 274 file_object.close() 275 self.txt=file_context 276 self.vartext.set('已导入txt文本') 277 # print(1) 278 elif str(os.path.splitext(f)[1])=='.docx': 279 import docx 280 document = docx.Document(self.audio_path) 281 txt='' 282 for paragraph in document.paragraphs: 283 txt+=paragraph.text 284 self.txt=txt 285 self.vartext.set('已导入docx文本') 286 self.audio_path=path+'\\'+f#更新数据路径 287 288 def insert_mark(self,event): #非主动线程 289 # while self.run: 290 # self.insert_text = self.insert_text + event.char 291 pass 292 def lay(self): 293 # txt=entry1.get() 294 print(self.insert_text) 295 print(123) 296 297 ''' 298 self.vartext.set('正在生成文本标记文件') 299 # data_set = assist.read_txt_data(os.path.dirname(os.path.realpath(__file__))+"\\data_set.txt") 300 mark_set=[1,1,0,1,1,0,1,1] 301 import re 302 txt_comma=re.split(u'。',self.txt[:-1]) 303 p,f=os.path.split(self.audio_path) 304 # print(p) 305 # print(f) 306 for i in range(len(txt_comma)): 307 txt_comma[i]=txt_comma[i].split(',') 308 309 # print(txt_comma) 310 if mark_set[0]==1: 311 txt_A='' 312 for i in txt_comma: 313 txt_A=txt_A+out_comma(i,mark_set[1],mark_set[2]) 314 # print(txt_A) 315 fobj=open(p+'\\'+str(os.path.splitext(f)[0])+'_A'+str(os.path.splitext(f)[1]),'w') 316 fobj.write(txt_A) 317 fobj.close() 318 319 if mark_set[4]==1: 320 txt_B='' 321 for i in txt_comma: 322 txt_B=txt_B+out_comma(i,mark_set[5],mark_set[6]) 323 # print(txt_B) 324 fobj=open(p+'\\'+str(os.path.splitext(f)[0])+'_B'+str(os.path.splitext(f)[1]),'w') 325 fobj.write(txt_B) 326 fobj.close() 327 ''' 328 329 330 331 332 333 def setup_config(self): 334 res = self.ask_userinfo() 335 if res is None: return 336 def ask_userinfo(self): 337 inputDialog = out_setconfig() 338 self.wait_window(inputDialog) # 这一句很重要!!! 339 340 341 342 if __name__ == '__main__': 343 app = main_code() 344 app.mainloop()
探究未知是最大乐趣