python中的多线程编程与暂停、播放音频的结合

摘要:
='':stream.writedata=self.wf.readframes#停止数据流stream.stop_stream()stream.close()#关闭PyAudiop.terminate()if__name__=="__main__":aaa=playWavAudio()aaa.play()多线程的代码:importthreadingimporttimeclassJob:def__init__:super.__init__self.__flag=threading.Event()#用于暂停线程的标识self.__flag.set()#设置为Trueself.__running=threading.Event()#用于停止线程的标识self.__running.set()#将running设置为Truedefrun:whileself.__running.isSet():self.__flag.wait()#为True时立即返回,为False时阻塞直到内部的标识位为True后返回printtime.sleep#printdefpause:self.__flag.clear()#设置为False,让线程阻塞printdefresume:self.__flag.set()#设置为True,让线程停止阻塞printdefstop:#self.__flag.set()#将线程从暂停状态恢复,如果已经暂停的话(要是停止的话我就直接让他停止了,干嘛还要执行这一句语句啊,把这句注释了之后就没有滞后现象了。

先给两个原文链接:

https://blog.csdn.net/u013755307/article/details/19913655

https://www.cnblogs.com/scolia/p/6132950.html

播放wav音频的原代码:

#引入库
importpyaudio
importwave
importsys
#定义数据流块
chunk = 1024
#只读方式打开wav文件
f = wave.open(r"../resource/3.wav","rb")
p =pyaudio.PyAudio()
#打开数据流
stream = p.open(format =p.get_format_from_width(f.getsampwidth()),
                channels =f.getnchannels(),
                rate =f.getframerate(),
                output =True)
#读取数据
data =f.readframes(chunk)
#播放
while data !="":
    stream.write(data)
    data =f.readframes(chunk)
#停止数据流
stream.stop_stream()
stream.close()
#关闭 PyAudio
p.terminate()

对其进行封装之后的代码:

#-*-coding:utf-8-*-
#引入库
importpyaudio
importwave
importsys
#定义数据流块
CHUNK = 1024
#if len(sys.argv) < 2:
#print("Plays a wave file.

Usage: %s filename.wav" % sys.argv[0])
#sys.exit(-1)
classplayWavAudio():
    def __init__(self):
        #只读方式打开wav文件
        self.wf = wave.open(r'../resource/3.wav', 'rb')   #(sys.argv[1], 'rb')
    defplay(self):
        p = pyaudio.PyAudio()   #创建一个播放器
        #打开数据流
        stream = p.open(format=p.get_format_from_width(self.wf.getsampwidth()),
                        channels=self.wf.getnchannels(),
                        rate=self.wf.getframerate(),
                        output=True)
        #读取数据
        data =self.wf.readframes(CHUNK)
        #播放
        while data != '':
            stream.write(data)
            data =self.wf.readframes(CHUNK)
        #停止数据流
stream.stop_stream()
        stream.close()
        #关闭 PyAudio
p.terminate()
if __name__ == "__main__":
    aaa =playWavAudio()
    aaa.play()

多线程(暂停,恢复,停止)的代码:

importthreading
importtime
classJob(threading.Thread):
    def __init__(self, *args, **kwargs):
        super(Job, self).__init__(*args, **kwargs)
        self.__flag = threading.Event()  #用于暂停线程的标识
        self.__flag.set()  #设置为True
        self.__running = threading.Event()  #用于停止线程的标识
        self.__running.set()  #将running设置为True
    defrun(self):
        while self.__running.isSet():
            self.__flag.wait()  #为True时立即返回, 为False时阻塞直到内部的标识位为True后返回
            print(time.time())
            time.sleep(1)
            #print("sleep 1s")
    defpause(self):
        self.__flag.clear()  #设置为False, 让线程阻塞
        print("pause")
    defresume(self):
        self.__flag.set()  #设置为True, 让线程停止阻塞
        print("resume")
    defstop(self):
        #self.__flag.set()  # 将线程从暂停状态恢复, 如果已经暂停的话(要是停止的话我就直接让他停止了,干嘛还要执行这一句语句啊,把这句注释了之后就没有滞后现象了。)
        self.__running.clear()  #设置为False
        print("停止!")
if __name__ == "__main__":
    a =Job()
    a.start()
    time.sleep(3)
    a.pause()
    time.sleep(6)
    a.resume()
    time.sleep(3)
    a.pause()
    time.sleep(2)
    a.stop()

原文解释:

python中的多线程编程与暂停、播放音频的结合第1张python中的多线程编程与暂停、播放音频的结合第2张
我们都知道python中可以是threading模块实现多线程, 但是模块并没有提供暂停, 恢复和停止线程的方法, 一旦线程对象调用start方法后, 只能等到对应的方法函数运行完毕. 也就是说一旦start后, 线程就属于失控状态. 不过, 我们可以自己实现这些. 一般的方法就是循环地判断一个标志位, 一旦标志位到达到预定的值, 就退出循环. 这样就能做到退出线程了. 但暂停和恢复线程就有点难了, 我一直也不清除有什么好的方法, 直到我看到threading中Event对象的wait方法的描述时.
复制代码
wait([timeout])
    Block until the internal flag is true. If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls set() to set the flag to true, oruntil the optional timeout occurs.
    阻塞, 直到内部的标志位为True时. 如果在内部的标志位在进入时为True时, 立即返回. 否则, 阻塞直到其他线程调用set()方法将标准位设为True, 或者到达了可选的timeout时间.
    When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (orfractions thereof).
    This method returns the internal flag on exit, so it will always return True except if a timeout is given andthe operation times out.
    当给定了timeout参数且不为None, 它应该是一个浮点数,以秒为单位指定操作的超时(或是分数)。
    此方法在退出时返回内部标志,因此除非给定了超时且操作超时,否则它将始终返回True。
    Changed in version 2.7: Previously, the method always returned None.
    2.7版本以前, 这个方法总会返回None.
复制代码
  利用wait的阻塞机制, 就能够实现暂停和恢复了, 再配合循环判断标识位, 就能实现退出了, 下面是代码示例:
这完成了暂停, 恢复和停止的功能. 但是这里有一个缺点: 无论是暂停还是停止, 都不是瞬时的, 必须等待run函数内部的运行到达标志位判断时才有效. 也就是说操作会滞后一次.
  但是这有时也不一定是坏事. 如果run函数中涉及了文件操作或数据库操作等, 完整地运行一次后再退出, 反而能够执行剩余的资源释放操作的代码(例如各种close). 不会出现程序的文件操作符超出上限, 数据库连接未释放等尴尬的情况.
原文解析

这里我修改了原作者的一个地方,就是把self.__flag.set()这一句删掉了,因为你要是想直接停止线程的话就不需要以后再执行其他操作了。删了这一句之后原作者所说的滞后现象就没了,原因未知。

将播放音频的代码和线程控制的代码整合后(只播放一次的):

from threading import *
importtime
from playsound importplaysound
importpyaudio
importwave
#定义数据流块
CHUNK = 1024
classMyThread(Thread):
    definit(self,filename):
        self.wf = wave.open(filename, 'rb')  #(sys.argv[1], 'rb')
        self.p = pyaudio.PyAudio()  #创建一个播放器
    #def init(self,filename):
        #打开数据流
        self.stream = self.p.open(format=self.p.get_format_from_width(self.wf.getsampwidth()),
                             channels=self.wf.getnchannels(),
                             rate=self.wf.getframerate(),
                             output=True)
        #读取数据
        self.data =self.wf.readframes(CHUNK)
        self.__flag =  Event()  #用于暂停线程的标识
        self.__flag.set()
        self.ifdo =True;
    defrun (self):
        while self.ifdo and self.data != '':
            self.__flag.wait()
            print('I am running...')
            #time.sleep(2)
            #播放
self.stream.write(self.data)
            self.data =self.wf.readframes(CHUNK)
        #self.data = ''
    defpause(self):
        self.__flag.clear()  #设置为False, 让线程阻塞
        print("pause")
    defresume(self):
        self.__flag.set()  #设置为True, 让线程停止阻塞
        print("resume")
    defstop (self):
        print('I am stopping it...')
        self.ifdo =False
    #def restart(self):
    #self.ifdo
if __name__ == "__main__":
    tr =MyThread()
    tr.init("c2.wav")
    #tr.setDaemon(True)
tr.start()
    print('I will pause it...')
    time.sleep(2)
    tr.pause()
    print("i will resume it...")
    time.sleep(2)
    tr.resume()
    print("i will stop it...")
    time.sleep(2)
    tr.stop()
    #time.sleep(1)
    #tr.stop()
    #

下面是循环播放版本的:

from threading import *
importtime
from playsound importplaysound
importpyaudio
importwave
#定义数据流块
CHUNK = 1024
classMyMusic(Thread):
    definit(self,filename):
        self.filename =filename
        self.wf = wave.open(filename, 'rb')  #(sys.argv[1], 'rb')
        self.p = pyaudio.PyAudio()  #创建一个播放器
    #def init(self,filename):
        #打开数据流
        self.stream = self.p.open(format=self.p.get_format_from_width(self.wf.getsampwidth()),
                             channels=self.wf.getnchannels(),
                             rate=self.wf.getframerate(),
                             output=True)
        #读取数据
        self.data =self.wf.readframes(CHUNK)
        self.__flag =  Event()  #用于暂停线程的标识
        self.__flag.set()
        self.ifdo =True;
    defrun (self):
        whileself.ifdo :
            while len(self.data) > 5:
                self.__flag.wait()
                print('I am running...')
                #time.sleep(2)
                #播放
self.stream.write(self.data)
                self.data =self.wf.readframes(CHUNK)
            self.wf = wave.open(self.filename, 'rb')
            self.data =self.wf.readframes(CHUNK)
        #self.data = ''
    defpause(self):
        self.__flag.clear()  #设置为False, 让线程阻塞
        print("pause")
    defresume(self):
        self.__flag.set()  #设置为True, 让线程停止阻塞
        print("resume")
    defstop (self):
        print('I am stopping it...')
        self.ifdo =False
    #def restart(self):
    #self.ifdo
if __name__ == "__main__":
    tr =MyMusic()
    tr.init("../resource/2.wav")
    #tr.setDaemon(True)
tr.start()
    print('I will pause it...')
    time.sleep(2)
    #tr.pause()
    print("i will resume it...")
    time.sleep(2)
    tr.resume()
    print("i will stop it...")
    time.sleep(2)
    #tr.stop()
    #time.sleep(1)
    #tr.stop()
    #tr.join()

免责声明:文章转载自《python中的多线程编程与暂停、播放音频的结合》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇利用windows的rar工具创建自解压安装文件的方法关于Git在Eclipse中的使用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

python 行转列

#encoding=utf-8 print '中国' #二维阵列变换 行转化成列,列转化成行 lista=[[1,2,3],[4,5,6],[7,8,9],[10,11,12]] #使用列表推导 listb=[[r[col] for r in lista] for col in range(len(li...

python与c#的交互模块pythonnet

 今天总结一下python与c#的交互模块pythonnet,其实微软也是有相应的解释器的,就是Ironpython,可是毕竟Ironpython还有很多东西没有从python那边继承过来,所以有时候用起来并不是那么爽。但是好在强大的社区总会给我们惊喜,pythonnet就是其中一个让我惊喜的模块,它可以平滑的和C#进行交互。但是网上这方面的资料还是太少了...

python基础练习题(题目 递归输出)

day19 --------------------------------------------------------------- 实例027:递归输出 题目 利用递归函数调用方式,将所输入的5个字符,以相反顺序打印出来。 分析:相反顺序可以用列表来,直接pop方法。 1 def reverseprint(a): 2 lit = list(...

Python基础汇总001_txt文件读写、字典使用等

1.利用python读取文件 (1)Python引入了with语句来自动帮我们调用close()方法 <1>读取指定路径下的文件 with open('/path/to/file', 'r') as f: print(f.read()) <2>写文件 with open('/Users/michael/test.txt',...

Semaphore 与ThreadPoolExecutor 的使用

1、 Semaphore 信号量  (阻塞) 优点:可以控制线程的数量,不会超出线程范围 缺点:当线程死锁时,永远没法释放,导致一直阻塞 在java中,提供了信号量Semaphore的支持。 Semaphore类是一个计数信号量,必须由获取它的线程释放, 通常用于限制可以访问某些资源(物理或逻辑的)线程数目。 一个信号量有且仅有3种操作,且它们全部是原子的...

Python实现Windows CMD命令行彩色输出

#! /usr/bin/env python #coding=utf-8   importctypes,sys   STD_INPUT_HANDLE =-10 STD_OUTPUT_HANDLE =-11 STD_ERROR_HANDLE =-12   # 字体颜色定义 ,关键在于颜色编码,由2位十六进制组成,分别取0~f,前一位指的是背景...