介紹幾個python的音訊處理庫
圖 3比如我的機器的地址就是 192.168.152.130。然後將這個ip地址填入 圖2 的Host Name 一欄,注意預設埠為22,不要去改它,然後點選open,就會彈出一個登陸介面,接著輸入你在linux 下登陸的使用者名稱和密碼就可以ssh連上linux啦。http://www.infoworld.com/article/2617683/linux/linux-moving-files-between-unix-and-windows-systems.html這篇文章介紹了 幾種在unix與windows之間傳遞檔案的方法。我只講第一種,使用putty的pscp的secure copy(安全拷貝)。你安裝了putty之後,會自帶一個叫 pscp.exe的可執行檔案,將其目錄加入windows 環境變數。然後 cmd執行命令 pscp myfile.txt[email protected]:/home/shs 即可以把你的檔案 myfile.txt 複製到 linux 下的 /home/shs 目錄下了。解釋一下,你在執行的時候需要把shs 換成你的使用者名稱,@後面跟你的linux ip地址, /home/shs 是你要把檔案移動的位置。執行完之後,檔案就會成功拷貝過去了。其他方法不講了,有興趣可以自行搜尋,或者看我上面說的那篇文章。 回到正題,eyeD3 命令列講完之後,再來說下如何在Python中使用。還是看官方給的例子吧:
1 import eyed3 2 3 audiofile = eyed3.load("song.mp3") 4 audiofile.tag.artist = u"Nobunny" 5 audiofile.tag.album = u"Love Visions" 6 audiofile.tag.album_artist = u"Various Artists" 7 audiofile.tag.title = u"I Am a Girlfriend" 8 audiofile.tag.track_num = 4 9 10 audiofile.tag.save()
上面的程式碼,使用 import eyed3 匯入eyeD3 庫,然後使用load方法載入mp3檔案,後面的幾行分別是設定 artist,album等等 ID3 tag ,直接看程式碼就能看出來,就不說了。如果想顯示mp3檔案內部的ID3 tag資訊,直接print 相應的tag就行了,比如 print(audiofile.tag.artist)等等,當然,前提是你的MP3 metadata得儲存了這些資訊。其實還有一些更復雜和高階的用法,我就不講了,大家有興趣直接去官方文件看吧,地址:http://eyed3.nicfit.net/index.html。eyeD3 主要就是處理 MP3檔案的metadata的,至於解析音訊之類的就得用其他的庫了。
二、pydub
第一個介紹的eyeD3 一般只能處理MP3檔案,功能上相對來說也是比較簡單一點。下面介紹的pydub庫就要強大的多。老規矩,還是 先看一下它的官方介紹: Manipulate audio with a simple and easy high level interface http://pydub.com 就一句話,簡單,易用的處理音訊 的高度抽象的介面,嘿,這不就是我們要找的麼。github專案地址為:https://github.com/jiaaro/pydub/ 有1800多的star,說明這個 庫還是很受歡迎的。安裝直接很簡單,直接 pip install pydub 就可以安裝。但是需要注意的是:
Dependencies
You can open and save WAV files with pure python. For opening and saving non-wav files – like mp3 – you'll need ffmpeg orlibav.
這裡是說python自帶的wave模組只能處理 wav 格式的音訊檔案,如果要想處理類似MP3格式的檔案,就得要裝 ffmpeg或者libav了。
什麼是ffmpeg 呢?
A complete, cross-platform solution to record, convert and stream audio and video.
ffmpeg 是一個跨平臺的 可以用來 記錄、轉化音訊與視訊的工具,如果你做過數字訊號處理方面的工作,對它應該不陌生。還有一個libav,其實是從ffmpeg分出來的一個分支,功能和 ffmpeg差不多,二者你任選一個下載就可以了。windows下直接選擇可執行檔案安裝即可。
還是看官網的例子來介紹吧。
I:開啟 mp3或者mp4等檔案
可以採用如下的命令:
1 from pydub import AudioSegment 2 3 song = AudioSegment.from_wav("never_gonna_give_you_up.wav") 4 song = AudioSegment.from_mp3("never_gonna_give_you_up.mp3") 5 6 ogg_version = AudioSegment.from_ogg("never_gonna_give_you_up.ogg") 7 flv_version = AudioSegment.from_flv("never_gonna_give_you_up.flv") 8 9 mp4_version = AudioSegment.from_file("never_gonna_give_you_up.mp4", "mp4") 10 wma_version = AudioSegment.from_file("never_gonna_give_you_up.wma", "wma") 11 aac_version = AudioSegment.from_file("never_gonna_give_you_up.aiff", "aac")
可以開啟任何 ffmpeg支援的檔案型別,從上面可以看出,主要有 from_filetype()方法,filetype為具體的檔案型別,比如 wav,mp3等
或者通用的 from_file()方法,但是這個方法必須在第二個引數指定開啟檔案的型別,返回的結果都是 AudioSegment物件。
II:切割音訊
1 # pydub does things in milliseconds 2 ten_seconds = 10 * 1000 3 4 first_10_seconds = song[:ten_seconds] 5 6 last_5_seconds = song[-5000:]
注意pydub中的標準時間為毫秒,上面的程式碼就得到了音樂的前10秒和後5秒,非常簡單。
III:調整音量
1 # boost volume by 6dB 2 beginning = first_10_seconds + 6 3 4 # reduce volume by 3dB 5 end = last_5_seconds - 3
+6 就表示將音樂的音量提高6分貝,-3就表示將音樂的音量降低3分貝
IV: 拼接兩段音樂
without_the_middle = beginning + end
without_the_middle.duration_seconds
拼接之後的音樂時長是兩段音樂時長之和,可以通過 .duration_seconds方法來獲取一段音樂的時長。這與使用 len(audio)/1000.0得到的結果是一樣的。
V:將音樂翻轉(reverse)
1 # song is not modified 2 # AudioSegments are immutable 3 backwards = song.reverse()
注意 AudioSegment 物件是不可變的,上面使用reverse 方法不會改變song這個物件,而是會返回一個新的AudioSegment物件,其他的方法也是這樣,需要注意。reverse簡單來說就是 將音樂從尾部向頭部開始逆序播放,我試了一下,發現轉換之後還真的挺有意思的。
VI:crossfade(交叉漸入漸出方法)
1 # 1.5 second crossfade 2 with_style = beginning.append(end, crossfade=1500)
crossfade 就是讓一段音樂平緩地過渡到另一段音樂,上面的crossfade = 1500 表示過渡的時間是1.5秒。
VII:repeat(重複音樂片段)
# repeat the clip twice do_it_over = with_style * 2
上面的程式碼讓音樂重複播放兩次
VIII:fade in and fade out(逐漸增強與逐漸減弱)
# 2 sec fade in, 3 sec fade out awesome = do_it_over.fade_in(2000).fade_out(3000)
逐漸增強2秒,逐漸減弱3秒
XI:save(儲存)
awesome.export("mashup.mp3", format="mp3") awesome.export("mashup.mp3", format="mp3", tags={'artist': 'Various artists', 'album': 'Best of 2011', 'comments': 'This album is awesome!'})
這裡展示了兩種儲存的形式,都是使用export方法,要指定儲存的格式,使用format 引數,但第二種方法多了一個tags引數,其實看一下應該就很容易明白,是儲存 歌曲ID3 tag資訊的。
以上只是pydub 使用方法的初步介紹,還有其他非常多的功能,請自行移步官方API 文件:https://github.com/jiaaro/pydub/blob/master/API.markdown
介紹的非常詳細。
三、PyAudio
又是一個功能強大的處理音訊庫。官方介紹:
PyAudio provides Python bindings for PortAudio, the cross-platform audio I/O library. With PyAudio, you can easily use Python to play and record audio on a variety of platforms. PyAudio is inspired by:
- pyPortAudio/fastaudio: Python bindings for PortAudio v18 API.
- tkSnack: cross-platform sound toolkit for Tcl/Tk and Python.
Pyaudio 提供了對於跨平臺的 PortAudio(處理 audio輸入輸出的庫)的繫結,PyAudio可以讓你輕鬆錄製與播放音訊。
廢話不多說,直接看官方文件(https://people.csail.mit.edu/hubert/pyaudio/docs/)提供的一個quick start 的程式碼
1 """PyAudio Example: Play a wave file.""" 2 3 import pyaudio 4 import wave 5 import sys 6 7 CHUNK = 1024 8 9 if len(sys.argv) < 2: 10 print("Plays a wave file.\n\nUsage: %s filename.wav" % sys.argv[0]) 11 sys.exit(-1) 12 13 wf = wave.open(sys.argv[1], 'rb') 14 15 # instantiate PyAudio (1) 16 p = pyaudio.PyAudio() 17 18 # open stream (2) 19 stream = p.open(format=p.get_format_from_width(wf.getsampwidth()), 20 channels=wf.getnchannels(), 21 rate=wf.getframerate(), 22 output=True) 23 24 # read data 25 data = wf.readframes(CHUNK) 26 27 # play stream (3) 28 while len(data) > 0: 29 stream.write(data) 30 data = wf.readframes(CHUNK) 31 32 # stop stream (4) 33 stream.stop_stream() 34 stream.close() 35 36 # close PyAudio (5) 37 p.terminate()
當然,這個提供的是使用命令列引數接收音訊檔案的形式,CHUNK 是一次讀取的音訊byte數量,p = pyaudio.PyAudio()初始化一個
PyAudio物件,然後使用其open方法開啟一個輸入輸出流,這裡指定了output=True說明這是一個輸出流,即我們是往stream中新增data,如果這裡改為 input = True就是變成輸入流了,一般是從裝置的標準 audio device ,對於電腦來說可能就是麥克風了,來讀取音訊data。使用wave開啟一個 .wav 檔案,然後使用 readframes方法每次讀取 CHUNK 這麼多的資料,將資料寫入 stream,直到讀完為止。寫入stream的audio data 就會不斷通過麥克風播放出來了,於是我們就可以聽到音樂了。最後在結束的時候,注意要關閉相應的物件以釋放資源。
還有一種方法是使用callback(回撥函式)函式,程式碼如下:
1 """PyAudio Example: Play a wave file (callback version).""" 2 3 import pyaudio 4 import wave 5 import time 6 import sys 7 8 if len(sys.argv) < 2: 9 print("Plays a wave file.\n\nUsage: %s filename.wav" % sys.argv[0]) 10 sys.exit(-1) 11 12 wf = wave.open(sys.argv[1], 'rb') 13 14 # instantiate PyAudio (1) 15 p = pyaudio.PyAudio() 16 17 # define callback (2) 18 def callback(in_data, frame_count, time_info, status): 19 data = wf.readframes(frame_count) 20 return (data, pyaudio.paContinue) 21 22 # open stream using callback (3) 23 stream = p.open(format=p.get_format_from_width(wf.getsampwidth()), 24 channels=wf.getnchannels(), 25 rate=wf.getframerate(), 26 output=True, 27 stream_callback=callback) 28 29 # start the stream (4) 30 stream.start_stream() 31 32 # wait for stream to finish (5) 33 while stream.is_active(): 34 time.sleep(0.1) 35 36 # stop stream (6) 37 stream.stop_stream() 38 stream.close() 39 wf.close() 40 41 # close PyAudio (7) 42 p.terminate()
不細說了。
下面來看一個使用pyaudio + numpy + pylab 視覺化音訊的程式碼,下面的程式碼開啟電腦的麥克風,然後接受音訊輸入,再以影象的形式展示出來。
1 # -*- coding: utf-8 -*- 2 """ 3 Created on Fri May 12 10:30:00 2017 4 @author: Lyrichu 5 @description: show the sound in graphs 6 """ 7 import pyaudio 8 import numpy as np 9 import pylab 10 import time 11 12 RATE = 44100 13 CHUNK = int(RATE/20) # RATE/number of updates per second 14 15 def sound_plot(stream): 16 t1 = time.time() # time starting 17 data = np.fromstring(stream.read(CHUNK),dtype = np.int16) 18 pylab.plot(data) 19 pylab.title(i) 20 pylab.grid() 21 pylab.axis([0,len(data),-2**8,2**8]) 22 pylab.savefig("sound.png",dpi=50) 23 pylab.show(block = False) time.sleep(0.5) 24 pylab.close('all') 25 print("took %.2f ms." % (time.time() - t1)*1000) 26 27 if __name__ == '__main__': 28 p = pyaudio.PyAudio() 29 stream = p.open(format = pyaudio.paInt16,channels = 1,rate = RATE, 30 input = True,frames_per_buffer = CHUNK) 31 for i in range(int(20*RATE/CHUNK)): 32 # for 10 seconds 33 sound_plot(stream) 34 stream.stop_stream() 35 stream.close() 36 p.terminate()
程式碼應該比較容易理解。得到的大概是像下面這樣的圖形(圖4):
圖 4
需要注意的是,如果不是在互動式命令下執行pylab或者matplotlib的plot命令,其plt.show()函式是一個block函式,這會導致最後的
plt.close('all') 關閉所有的視窗只會在手動關閉了影象之後才會執行,所有我們無法看到連續變化的影象,為了解決這個問題,我們將plt.show()函式block引數設為False,這樣show函式就不是block函數了,可以直接執行plt.close('all')命令,為了不因為影象重新整理太快我們看不清變化,所以使用time.sleep(0.5) 暫停0.5秒。
其實還沒介紹完,還有pygame模組(python的一個做遊戲的模組)以及librosa庫(專業的數字訊號處理庫)等沒有講,等有機會再更吧。敬請關注!