2010-10-20 360 views
3

我正在研究播放音樂的Python程序。一個功能將是一個滑塊,用戶可以上下拖動以改變音樂播放的音調。在Python播放過程中改變音頻的音調(和速度)

例如,如果間距設置爲2,那麼音樂就會響起一個八度,它將發揮快兩倍,而且它會持續一半的時間。我真正在改變的是播放速度,但我需要實時交互。

的閃光燈實現了這個功能的一個很好的例子可以發現here。 (需要一點點加載,耐心等待。)

我已經看過很多python音頻包,但我還沒有找到可以改變當前正在播放的聲音的音調。我有多個版本的Python,因此不需要該軟件包支持的版本。我正在開發Windows 7上的這個。

有什麼建議嗎?

回答

1

這聽起來好像你想重新取樣即時音頻。

也許你可以嘗試使用scikits.samplerate模塊。它使用Secret Rabbit Code library

+0

的[只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

+0

我假設你已經知道如何在Python中實現音頻樣本的基本回放。 – 2010-10-21 00:57:45

+0

對不起,讓我重述一下我的陳述。我需要一種方法來播放聲音,使我能夠實時重新採樣。我會檢查python文檔,但我不知道有什麼辦法可以做到這一點。 – dln385 2010-10-21 01:03:03

3

隨着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.6scikits.samplerate 0.3.1 for python 2.6。請注意,scikits.samplerate與NumPy 1.4或更高版本衝突,並且其中一個包(我忘記了哪一個)需要setuptools

0

scikits.samplerate 0.3需要安裝工具。1

,如果你不這樣做,你會不斷收到錯誤導入錯誤:沒有模塊名爲pkg_resources才能

+0

只是一個更新,它現在拋出這個錯誤,如果你沒有安裝setuptools並且是最新的: >>> from scikits.samplerate import resample Traceback(最新最後調用): 文件 「」,1號線,從_samplerate進口重採樣,available_convertors,src_version_str,\ 導入錯誤 文件 「scikits /採樣率/ __ init__.py」,第6行,在 :無模塊名爲_samplerate – Jay 2015-05-06 22:37:26