
本文旨在解决使用 PyAudio 库播放声音时,如何在不预先设定播放时长的情况下,实现声音的持续播放,并通过外部事件(例如按键释放)来停止声音。我们将分析问题代码,找出循环播放的错误原因,并提供修改方案,最终实现灵活的声音控制。
在使用 PyAudio 库进行音频编程时,一个常见的需求是在不预先确定播放时长的情况下,持续播放声音,并根据外部事件(例如,MIDI 控制器的按键释放)来停止播放。原始代码尝试通过一个 while 循环来实现这个功能,但存在一些逻辑上的问题,导致声音无法持续播放,或者无法正确停止。
原始代码的核心问题在于 while play == True 循环内部的逻辑。让我们再次审视一下:
while play == True:
start_time = time.time()
stream.write(vysledek)
time.sleep(1)
play = False
stream.stop_stream()
play = True这段代码的意图是循环播放声音数据 vysledek。然而,在每次循环迭代中,它会执行以下操作:
因此,循环只执行一次,导致声音只播放一秒钟。此外,stream.stop_stream() 被放置在循环内部,导致每次播放结束后立即停止音频流,这与持续播放的需求相悖。
要实现持续播放,我们需要修改代码,移除不必要的 time.sleep(1) 和 play = False,并将 stream.stop_stream() 移到循环外部。更重要的是,我们需要根据MIDI消息来控制play变量,从而控制声音的播放和停止。
以下是修改后的代码示例:
import time
from rtmidi.midiutil import open_midiinput
import numpy as np
import pyaudio
p = pyaudio.PyAudio()
play = False # 初始化为False,只有按下按键才播放
volume = 0.5
fs = 44100
fA = 440.0
fB = 493.88
fC = 523.25
fD = 587.33
frekvence = 440
frekvence_seznam = {
(144, 32): fA,
(144, 33): fB,
(144, 34): fC,
(144, 35): fD,
}
port = 0
midiin, port_name = open_midiinput(port)
stream = None # 初始化stream为None
try:
while True:
msg = midiin.get_message()
if msg:
message = msg
klic = message[0]
lepsi_klic = tuple(klic[:2])
print(message[0])
if lepsi_klic in frekvence_seznam:
print("je to tam")
frekvence = frekvence_seznam[lepsi_klic]
period = 2 * np.pi
x = period * np.arange(fs * 1) * frekvence / fs # duration改为1,或者更小的值,减少计算量
sinus = np.sin(x)
square = np.sign(sinus)
triangle = 2/np.pi * np.arcsin(np.sin(x))
saw = abs((x % period) - 1)
curvy_triangle = (abs((x % period) - 1)) ** 2
samples = (triangle).astype(np.float32)
vysledek = volume * samples
# 启动播放
if not stream: # 如果stream未初始化,则初始化
stream = p.open(format=pyaudio.paFloat32,
channels=1,
rate=fs,
output=True)
play = True # 开始播放
elif lepsi_klic == (128, 32) or lepsi_klic == (128, 33) or lepsi_klic == (128, 34) or lepsi_klic == (128, 35): # 假设128代表按键释放
print("停止播放")
play = False # 停止播放
elif lepsi_klic == (144, 81):
break # 退出主循环
if play and stream: # 只有在play为True且stream已初始化时才播放
stream.write(vysledek)
except KeyboardInterrupt:
print("Interrupted by user")
finally:
if stream:
stream.stop_stream()
stream.close()
p.terminate()
midiin.close_port()
del midiin修改说明:
通过修改循环逻辑,并根据 MIDI 消息动态控制播放状态,我们成功实现了在不预先设定播放时长的情况下,持续播放声音,并通过外部事件来停止播放的功能。这个方法可以应用于各种需要实时控制音频播放的场景,例如音乐游戏、交互式音频装置等。
以上就是无需预设时长,实现声音的持续播放与停止的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号