我的目标是使用Python在计算机游戏环境中播放具有以下要求的声音。
取一些输入WAV文件并随机改变音高至原始的+/- 50%。使用PyDub更改采样率似乎是一种简单的方法。
播放声音。
能够快速调用此功能,以便长时间和短时间的声音在实际播放中重叠。
我花了超过24个工时来寻找满足所有这些要求的方法。我之前在Visual Basic中已经完成了这项工作,我对Python的难度感到惊讶。
目前我所知道的是:
PyGame.Mixer可以同时播放重叠的声音,但必须以相同的采样率播放它们。似乎没有办法改变音高。
PyDub可以通过更改采样率来改变音高,但它不能通过基本播放播放重叠的声音。并且,我必须将输出声音写入文件,然后立即将其加载回来,这感觉很浪费。
WinSound可以播放PyDub的不同采样率声音,但不能同时播放,甚至不能使用线程播放。
Playsound包不适用于python 3.6。
如果我使用线程,PyAudio可以播放PyDub的并发播放的并发播放声音,但是,任何次数都会导致可怕的内存问题,导致Python崩溃。
我的问题:如何在不造成问题的情况下实现上述3个目标?
这是我到目前为止最好的结果(这是PyAudio版本,如果测试超过一次或两次会导致崩溃):
from pydub import AudioSegment
from random import random, seed
from time import sleep
import os
import threading
import pyaudio
import wave
def PlayAsyncWithRandPitch(WavPath):
MyBaseFilename = os.path.basename(WavPath)
sound = AudioSegment.from_file(WavPath, format="wav")
seed()
octaves = ((random()-0.50))
print("random octave factor for this sound is: "+str(octaves))
print("current sound frame rate:"+str(sound.frame_rate))
new_sample_rate = int(sound.frame_rate * (2.0 ** octaves))
print("new sound frame rate:"+str(new_sample_rate))
newpitchsound = sound._spawn(sound.raw_data, overrides={'frame_rate': new_sample_rate})
MyTotalNewPath = os.getcwd()+"\\Soundfiles\\Temp\\Mod_"+MyBaseFilename
newpitchsound.export(MyTotalNewPath, format="wav")
SoundThread = threading.Thread(target=PAPlay, args=(MyTotalNewPath,))
SoundThread.start()
#=======================================================================================
#This function is just code for playing a sound in PyAudio
def PAPlay(filename):
CHUNK = 1024
wf = wave.open(filename, 'rb')
p = pyaudio.PyAudio()
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True)
data = wf.readframes(CHUNK)
while data != '':
stream.write(data)
data = wf.readframes(CHUNK)
stream.stop_stream()
stream.close()
p.terminate()
return
if __name__ == "__main__":
#Example sounds to test if more than one can play at once
PlayAsyncWithRandPitch(os.getcwd()+'\\Soundfiles\\RifleMiss.WAV')
sleep(0.2)
PlayAsyncWithRandPitch(os.getcwd()+'\\Soundfiles\\splash.wav')
sleep(0.2)
PlayAsyncWithRandPitch(os.getcwd()+'\\Soundfiles\\sparkhit1.WAV')
sleep(5.0)
提前感谢您的帮助!
答案 0 :(得分:1)
感谢另一个小时的谷歌搜索,我能够通过找到一个关于PyDub的模糊注释来解决它。有一种方法可以实际更改采样率,但“实际上并非”更改采样率。它被称为花栗鼠方法。
https://github.com/jiaaro/pydub/issues/157#issuecomment-252366466
我真的不假装理解这里的细微差别,但似乎概念是“将声音,设置样本率改为某些修改后的值,然后转换采样率回到传统的44,100 HZ值。“
他们给出了这个非常有效的例子:
from pydub import AudioSegment
sound = AudioSegment.from_file('./test/data/test1.mp3')
# shift the pitch up by half an octave (speed will increase proportionally)
octaves = 0.5
new_sample_rate = int(sound.frame_rate * (2.0 ** octaves))
# keep the same samples but tell the computer they ought to be played at the
# new, higher sample rate. This file sounds like a chipmunk but has a weird sample rate.
chipmunk_sound = sound._spawn(sound.raw_data, overrides={'frame_rate': new_sample_rate})
# now we just convert it to a common sample rate (44.1k - standard audio CD) to
# make sure it works in regular audio players. Other than potentially losing audio quality (if
# you set it too low - 44.1k is plenty) this should now noticeable change how the audio sounds.
chipmunk_ready_to_export = chipmunk_sound.set_frame_rate(44100)
这对我来说没有多大意义,但确实有效:)希望这可以帮助那些人。
答案 1 :(得分:0)
这种方法似乎有点可疑。我解释了如何在以下link上使用Java对C ++人员进行varispeed。
主要思想是使用线性插值从样本之间获取值,并以1:1以外的速率逐步通过样本数据。如果您要求150%并且需要样本0,则样本1.5(在1和2之间的中间位置,插入值。