Python 从零开始制作自己的声音 - wave模块读写wav文件详解
文章介紹wave模塊的用法、生成一定頻率音頻的算法實現。
目錄
- wave模塊
- wave.open() 函數
- Wave_read 對象
- Wave_write 對象
- 初步: 拼接音頻
- 初次實現
- 再次實現
wave模塊
wave模塊提供了一個處理 wav 聲音格式的便利接口, 可獲取wav文件頭信息, 從文件讀取數據, 也可直接將bytes格式的數據寫入wav文件。
wave.open() 函數
wave.open(file, mode=None)
函數接收兩個參數, file為文件名或文件對象, mode可取"r",“rb”,“w”,“wb"四個值, 其中"r"和"rb”, "w"和"wb"效果完全相同, 如下:
以讀模式打開的文件會返回Wave_read 對象, 寫模式打開時會返回Wave_write 對象。
Wave_read 對象
wave文件由許多幀組成, 每一幀長度為1或2字節。
Wave_read.getnchannels()
返回聲道數量(1 為單聲道,2 為立體聲)
Wave_read.getsampwidth()
返回采樣字節長度 (每一幀的字節長度)。
Wave_read.getframerate()
返回采樣頻率。
Wave_read.getnframes()
返回音頻總幀數。
Wave_read.getcomptype()和Wave_read.getcompname()
返回壓縮類型。
Wave_read.readframes(n)
讀取并返回以 bytes 對象表示的最多 n 幀音頻。
Wave_read.tell()
返回當前文件指針位置。
Wave_read.setpos(pos)
設置文件指針到指定位置。
Wave_write 對象
Wave_write.setnchannels(n)
設置聲道數。
Wave_write.setsampwidth(n)
設置采樣字節長度為 n。
Wave_write.setframerate(n)
設置采樣頻率為 n。
Wave_write.setnframes(n)
設置總幀數為 n。 如果與之后實際寫入的幀數不一致此值將會被更改( 如果輸出流不可查找則此更改嘗試將引發錯誤)。
Wave_write.setcomptype(type, name)
設置壓縮格式。目前只支持 NONE 即無壓縮格式。
Wave_write.tell()
返回當前文件指針,其指針含義和 Wave_read.tell() 以及 Wave_read.setpos() 是一致的。
Wave_write.writeframesraw(data)
寫入bytes格式的音頻數據但不更新 nframes。data的長度必須不大于setnframes設定的總幀數, 否則會引發錯誤。
Wave_write.writeframes(data)
寫入bytes格式的音頻幀并確保 nframes 是正確的。 這里data的長度可以大于setnframes設定的總幀數。
Wave_write.close()
確保 nframes 是正確的,并在文件被 wave 打開時關閉它。 此方法會在對象收集時被調用。 如果輸出流不可查找且 nframes 與實際寫入的幀數不匹配時引發異常。
初步: 拼接音頻
程序先將兩段音頻中的數據讀入data1和data2中, 再將讀取的數據寫入result.wav。兩段音頻的采樣頻率、采樣字節長度需要一致。
import wavesampwidth = 1 framerate = 22050with wave.open('音樂.wav','rb') as f1:sampwidth = f1.getsampwidth()framerate = f1.getframerate()nframes1=f1.getnframes()data1=f1.readframes(nframes1)with wave.open('音樂.wav','rb') as f2:nframes2=f2.getnframes()data2=f2.readframes(nframes2)with wave.open('result.wav','wb') as fw:fw.setnchannels(1)fw.setsampwidth(sampwidth)fw.setframerate(framerate)#fw.setnframes(nframes1+nframes2)fw.writeframesraw(data1)fw.writeframesraw(data2)初次實現
現在開始制作自己的聲音。程序生成一段頻率為200Hz, 長度為1.8秒的蜂鳴聲。
import wave from winsound import PlaySound,SND_FILENAMEfile = 'test.wav' len_= 1.8 # 秒 frequency = 200 sampwidth = 1 #每一幀寬度(采樣字節長度) framerate = 22050 # 采樣頻率 (越大音質越好) length = int(framerate * len_ * sampwidth) para = [0b00000000]*(framerate//frequency//2*sampwidth)\+[0b11111111]*(framerate//frequency//2*sampwidth) # 音頻的一小段 data=bytes(para)# 生成wav文件 with wave.open(file,'wb') as f:f.setnchannels(1)f.setsampwidth(sampwidth)f.setframerate(framerate)#f.setnframes(length)f.writeframes(data * (length // len(data))) # 調用writeframes函數無需預先設置nframes, 但調用writeframesraw函數需要PlaySound(file,SND_FILENAME) # 播放生成的wav再次實現
上述程序有缺點, 如para中0b0000000和0b11111111的長度是整數且相同, 導致生成的聲音頻率不精確; 缺乏對正弦波的支持等。
這里增加了生成器, 用于生成音頻幀。
與Python內置的音頻合成對比:
import winsound # Beep(freq,duration),參數分別是頻率和毫秒為單位的持續時間 winsound.Beep(200,1800)發現, 前述程序很好地仿真了調用內置的Beep函數發聲。
但音質有區別, 這是采樣字節長度為1(只有8位)導致的, 還需要加大采樣字節長度。
最終的程序如下:
使用matplotlib庫查看生成的聲波:
import matplotlib.pyplot as plt # --snip-- plt.plot(range(len(lst)),lst) plt.show()
寫在最后:
程序還可再做改進, 例如模擬各種樂器的音色, 也就是細微改變生成的聲波形狀。如果程序中加入共振峰, 還可實現簡單的語音合成?
但是, Windows系統已經自帶了語音合成, 何必再開發一個呢?
下篇: Python 調用Windows內置的語音合成,并生成wav文件
總結
以上是生活随笔為你收集整理的Python 从零开始制作自己的声音 - wave模块读写wav文件详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TextMeshPro备用字体疑问
- 下一篇: 国产杂牌机java_国货精品 山寨 杂牌