windows 在 Python 中播放期间更改音频的音高(和速度)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3982007/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Change the pitch (and speed) of audio during playback in Python
提问by dln385
I'm working on a Python program that plays music. One feature will be a slider that the user can drag up or down to change the pitch of the music as it plays.
我正在开发一个播放音乐的 Python 程序。一个功能是一个滑块,用户可以向上或向下拖动以在播放时改变音乐的音高。
For example, if the pitch is set to 2, then the music will sound one octave higher, it will play twice as fast, and it will last half as long. All I'm really changing is the playback speed, but I need to do so interactively in real-time.
例如,如果音高设置为 2,那么音乐听起来会高一个八度,播放速度会提高一倍,持续时间会减半。我真正改变的是播放速度,但我需要实时交互。
A good example of this functionality implemented in flash can be found here. (It takes a little bit to load, be patient.)
可以在此处找到在 Flash 中实现的此功能的一个很好的示例。(加载需要一点时间,请耐心等待。)
I've looked into many python audio packages, but I haven't found one that can change the pitch of a sound that is currently playing. I have multiple versions of Python, so there is no requirement for what version the package supports. I'm developing this on Windows 7.
我研究了许多 python 音频包,但我还没有找到可以改变当前正在播放的声音的音高的包。我有多个版本的 Python,所以对包支持的版本没有要求。我正在 Windows 7 上开发这个。
Any suggestions?
有什么建议?
采纳答案by Craig McQueen
It sounds as though you want to resample the audio on-the-fly.
听起来好像您想即时重新采样音频。
Perhaps you could try using the scikits.sampleratemodule. It uses the Secret Rabbit Code library.
也许您可以尝试使用scikits.samplerate模块。它使用Secret Rabbit Code 库。
回答by dln385
With Craig McQueen's help, I have created a proof-of-concept program.
在Craig McQueen的帮助下,我创建了一个概念验证程序。
This program plays a monowav file called "music.wav" (located in the same folder as the program) and displays a short and wide window. The pitch of the music changes when you click and drag in the window. The left side of the window is two octaves lower, and the right side is two octaves higher.
该程序播放一个名为“music.wav”的单声道wav 文件(与程序位于同一文件夹中)并显示一个短而宽的窗口。当您在窗口中单击并拖动时,音乐的音高会发生变化。窗口左侧低两个八度,右侧高两个八度。
There is some strange behavior here that I'm not sure how to fix. If the pitch is currently low, then there's about a 2 second delay before the pitch changes. However, the pitch changes in real-time for high pitches. (The delay increases smoothly as the pitch gets lower). I only add more sound to the buffer if soundOutput.getLeft() < 0.2
. That is to say, if the amount of sound left on the buffer is less than 0.2 seconds. Therefore there should be no delay. For troubleshooting, I included code that writes soundOutput.getLeft()
to a file. It tends to stay at or very near 0 all the time.
这里有一些奇怪的行为,我不知道如何解决。如果音高当前较低,则在音高改变之前会有大约 2 秒的延迟。但是,对于高音,音高会实时变化。(随着音调变低,延迟会平滑增加)。如果soundOutput.getLeft() < 0.2
. 也就是说,如果缓冲区上剩余的声音量小于 0.2 秒。因此,不应有任何延误。为了排除故障,我包含了写入soundOutput.getLeft()
文件的代码。它往往始终保持在或非常接近 0。
Decreasing the frames read to waveRead.readframes(100)
decreases the delay, but also makes the sound choppy. Increasing the frames read significantly increases the delay.
减少读取的帧数以waveRead.readframes(100)
减少延迟,但也会使声音断断续续。增加读取的帧数会显着增加延迟。
import os, sys, wave, pygame, numpy, pymedia.audio.sound, scikits.samplerate
class Window:
def __init__(self, width, height, minOctave, maxOctave):
"""
width, height: the width and height of the screen.
minOctave, maxOctave: the highest and lowest pitch changes. 0 is no change.
"""
self.minOctave = minOctave
self.maxOctave = maxOctave
self.width = width
self.mouseDown = False
self.ratio = 1.0 # The resampling ratio
waveRead = wave.open(os.path.join(sys.path[0], "music.wav"), 'rb')
sampleRate = waveRead.getframerate()
channels = waveRead.getnchannels()
soundFormat = pymedia.audio.sound.AFMT_S16_LE
soundOutput = pymedia.audio.sound.Output(sampleRate, channels, soundFormat)
pygame.init()
screen = pygame.display.set_mode((width, height), 0)
screen.fill((255, 255, 255))
pygame.display.flip()
fout = open(os.path.join(sys.path[0], "musicdata.txt"), 'w') # For troubleshooting
byteString = waveRead.readframes(1000) # Read at most 1000 samples from the file.
while len(byteString) != 0:
self.handleEvent(pygame.event.poll()) # This does not wait for an event.
fout.write(str(soundOutput.getLeft()) + "\n") # For troubleshooting
if soundOutput.getLeft() < 0.2: # If there is less than 0.2 seconds left in the sound buffer.
array = numpy.fromstring(byteString, dtype=numpy.int16)
byteString = scikits.samplerate.resample(array, self.ratio, "sinc_fastest").astype(numpy.int16).tostring()
soundOutput.play(byteString)
byteString = waveRead.readframes(500) # Read at most 500 samples from the file.
waveRead.close()
return
def handleEvent(self, event):
if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE):
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
self.mouseDown = True
self.setRatio(event.pos)
if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
self.mouseDown = False
if event.type == pygame.MOUSEMOTION and self.mouseDown:
self.setRatio(event.pos)
return None
def setRatio(self, point):
self.ratio = 2 ** -(self.minOctave + point[0] * (self.maxOctave - self.minOctave) / float(self.width))
print(self.ratio)
def main():
Window(768, 100, -2.0, 2.0)
if __name__ == '__main__':
main()
It's a pain to try to get all the packages I use to work well together. I'm using Python 2.6.6, PyGame 1.9.1 for python 2.6, NumPy 1.3.0 for python 2.6, PyMedia 1.3.7.3 for python 2.6, and scikits.samplerate 0.3.1 for python 2.6. Note that scikits.samplerate conflicts with NumPy 1.4 or greater, and one of the packages (I forget which one) requires setuptools
试图让我使用的所有软件包协同工作是一种痛苦。我使用Python 2.6.6,PyGame 1.9.1 for python 2.6,NumPy 1.3.0 for python 2.6,PyMedia 1.3.7.3 for python 2.6和scikits.samplerate 0.3.1 for python 2.6。请注意,scikits.samplerate 与 NumPy 1.4 或更高版本冲突,其中一个包(我忘记是哪个)需要setuptools
回答by Craig McQueen
You might want to look at using wxPythonto create a media player, and investigate the SetPlaybackRate()
function. wxWidget docs here.
您可能想看看使用wxPython来创建媒体播放器,并研究该SetPlaybackRate()
功能。wxWidget 文档在这里。
That SetPlaybackRate()
function is not supported on all platforms, and I've not tried it myself to see whether it does exactly what you want, and how well it works or not.
SetPlaybackRate()
并非所有平台都支持该功能,我自己也没有尝试过,以查看它是否完全符合您的要求,以及它的效果如何。
回答by Bhaskar Chaudhary
setup tools is required for scikits.samplerate 0.3.1
scikits.samplerate 0.3.1 需要设置工具
if you dont do that you will keep getting an error ImportError: No module named pkg_resources
如果你不这样做,你会不断收到错误 ImportError: No module named pkg_resources