隨着Craig McQueen的幫助下,我創建了驗證的概念方案。
此程序播放單聲道 wav文件名爲「music.wav」(與程序位於同一文件夾中)並顯示一個短而寬的窗口。當您在窗口中單擊並拖動時,音樂的音高會發生變化。窗戶左側低兩個八度,右側高兩個八度。
有一些奇怪的行爲在這裏,我不知道如何解決。如果音高目前很低,那麼在音高改變之前大約有2秒的延遲。但是,高音調的音高實時變化。 (音高越低,延遲越平穩)。如果soundOutput.getLeft() < 0.2
只給緩衝區添加更多聲音。也就是說,如果緩衝區中留下的聲音量小於0.2秒。因此不應該有任何延誤。爲了排除故障,我提供了將soundOutput.getLeft()
寫入文件的代碼。它傾向於始終保持在0或非常接近0的水平。
減少幀讀取到減少延遲,但也使聲音波濤洶涌。增加讀取的幀會顯着增加延遲。
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()
這是一個痛苦,試圖讓所有我用它來很好地協同工作軟件包。我正在使用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
的[只scikits.samplerate做的事情(HTTP://www.ar.media.kyoto-u。 ac.jp/members/david/softwares/samplerate/sphinx/fullapi.html)是將一個numpy數組重新採樣到另一個數組中。我明白,如果我採用44100Hz的聲音,將其重新採樣到22050Hz,然後以44100Hz的頻率播放它,它將會提高一個八度。但是現在我需要一種播放聲音的方式,並且可以即時進行重採樣,這是原始問題的重要組成部分。 – dln385 2010-10-21 00:44:55
我假設你已經知道如何在Python中實現音頻樣本的基本回放。 – 2010-10-21 00:57:45
對不起,讓我重述一下我的陳述。我需要一種方法來播放聲音,使我能夠實時重新採樣。我會檢查python文檔,但我不知道有什麼辦法可以做到這一點。 – dln385 2010-10-21 01:03:03