[Python] wave 教學

程式語言:Python
Package:wave
官方文件

功能:讀寫 WAV 檔

基礎知識

參考此篇 [Python] Pyaudio 教學

讀檔範例

  1. # -*- coding: utf-8 -*-
  2. import wave
  3. import matplotlib.pyplot as plt
  4. import numpy as np
  5.  
  6. # 讀檔
  7. f = wave.open(r"c:\WINDOWS\Media\ding.wav", "rb")
  8.  
  9. # 格式資訊
  10. # (nchannels, sampwidth, framerate, nframes, comptype, compname)
  11. params = f.getparams()
  12. nchannels, sampwidth, framerate, nframes = params[:4]
  13.  
  14. # 波形數據
  15. str_data = f.readframes(nframes)
  16. f.close()
  17.  
  18. # bytes to np.short
  19. wave_data = np.fromstring(str_data, dtype=np.short)
  20. # 轉換為雙聲道
  21. wave_data.shape = -1, 2
  22. wave_data = wave_data.T
  23. # 總時間長度
  24. time = np.arange(0, nframes) * (1.0 / framerate)
  25.  
  26. # 音訊資訊
  27. print(nchannels, sampwidth, framerate, nframes)
  28.  
  29. # 畫波形
  30. plt.subplot(211)
  31. plt.plot(time, wave_data[0])
  32. plt.subplot(212)
  33. plt.plot(time, wave_data[1], c="g")
  34. plt.xlabel("time (seconds)")
  35. plt.show()

寫檔範例

  1. # -*- coding: utf-8 -*-
  2. import wave
  3. import numpy as np
  4. import matplotlib.pyplot as plt
  5.  
  6. time = 0.1 # second
  7. framerate = 44100 # Hz
  8.  
  9. def sinSweepFrq(f0, f1, framerate, time):
  10. '''
  11. 依線性產生從 f0 到 f1 的 sine
  12. f0 : 起始頻率
  13. f1 : 結束頻率
  14. framerate: 取樣率
  15. time: 時間長度
  16. '''
  17. nframes = time * framerate
  18. k = (f1-f0)/time
  19. t = np.linspace(0, time, num=nframes)
  20. # f = f0 + kt
  21. # w = 2 * pi * f = 2 * pi * f0 + 2 * pi * kt
  22. # w 對 t 積分得 phase
  23. # phase = 2 * pi * f0 * t + pi * kt^2
  24. phase = 2 * np.pi * f0 * t + np.pi * k * t * t
  25. return np.sin(phase)
  26.  
  27. nframes = time * framerate
  28.  
  29. n = np.linspace(0, time, num=nframes)
  30.  
  31. f_start = 20 # Hz
  32. f_stop = 1000 # Hz
  33.  
  34. sinus_f_start = np.sin(2*np.pi*f_start*n)
  35. sinus_f_stop = np.sin(2*np.pi*f_stop*n)
  36. # 產生 10秒 44.1kHz 的 20Hz - 1kHz 的 sine
  37. sinus_f_sweep = sinSweepFrq(f_start, f_stop, framerate, time)
  38.  
  39. # 先放大以免轉換 np.short 為 0,並且太小聲
  40. wave_data = sinus_f_sweep * 10000
  41. wave_data = wave_data.astype(np.short)
  42.  
  43. # 寫入檔案
  44. f = wave.open(r"sweep.wav", "wb")
  45.  
  46. # 設定聲道數、sample 大小(byte) 和取樣頻率
  47. f.setnchannels(1)
  48. f.setsampwidth(2)
  49. f.setframerate(framerate)
  50. # 寫入波形數據
  51. f.writeframes(wave_data.tostring())
  52. f.close()
  53.  
  54. # 畫圖確認
  55. fig = plt.figure()
  56.  
  57. fig.add_subplot(411)
  58. plt.plot(n, sinus_f_start)
  59. fig.add_subplot(412)
  60. plt.plot(n, sinus_f_stop)
  61. fig.add_subplot(413)
  62. plt.plot(n, sinus_f_sweep)
  63. fig.add_subplot(414)
  64. plt.plot(n, wave_data)
  65. plt.show()

wave

  • wave.open(file, mode=None)
    • file
      • string
      • file-like object
    • mode
      • 'rb' returns a Wave_read object
      • 'wb' returns a Wave_write object
  • wave.openfp(file, mode)
    • for 相容性,功能同 open()
  • exception
    • wave.Error
      • 違反 WAV 規範或應用上的錯誤

Wave_read

  • 由 open(file, 'rb') 所回傳
  • Wave_read.close()
    • 關閉
  • Wave_read.getnchannels()
    • 取得聲道數 (1 for mono, 2 for stereo)
  • Wave_read.getsampwidth()
    • 取得 sample width (bytes)
  • Wave_read.getframerate()
    • 取得取樣率
  • Wave_read.getnframes()
    • 取得 frames 數目
  • Wave_read.getcomptype()
    • 取得壓縮格式,目前只支援 'NONE',也就是無壓縮
  • Wave_read.getcompname()
    • 取得可讀的壓縮格式,通常為 'not compressed'
  • Wave_read.getparams()
    • 取得所有參數
      (nchannels, sampwidth, framerate, nframes, comptype, compname)
  • Wave_read.readframes(n)
    • 讀取 n frames 為 bytes object
  • Wave_read.rewind()
    • 回到開頭
  • Wave_read.getmarkers()
    • 回傳 None,單純只為了相容 aifc module
  • Wave_read.getmark(id)
    • Raise an error,單純只為了相容 aifc module
  • Wave_read.setpos(pos) 
    • 設定讀取位置
  • Wave_read.tell()
    • 取得目前讀取位置

Wave_write

  • 由 open(file, 'wb') 所回傳
  • 一旦寫入資料,不可再設定任何參數
  • Wave_write.close() 
    • 需確認寫入資料與 nframes 一致,才可關閉
  • Wave_write.setnchannels(n)
    • 設定聲道數 (1 for mono, 2 for stereo)
  • Wave_write.getnchannels()
    • 取得聲道數 (1 for mono, 2 for stereo)
  • Wave_write.setsampwidth(n)
    • 設定 sample width (bytes)
  • Wave_write.getsampwidth(n)
    • 取得 sample width (bytes)
  • Wave_write.setframerate(n)
    • 設定取樣率,非整數自動四捨五入
  • Wave_write.getframerate(n)
    • 取得取樣率
  • Wave_write.setnframes(n)
    • 設定 frames 數目
    • 若不一致,且 stream 可 seek,則會自動更正
  • Wave_write.getnframes(n)
    • 取得 frames 數目
  • Wave_write.setcomptype(type, name)
    • 只支援 type NONE
  • Wave_write.getcomptype()
    • 取得壓縮格式,目前只支援 'NONE',也就是無壓縮
  • Wave_write.getcompname()
    • 取得可讀的壓縮格式,通常為 'not compressed'
  • Wave_write.setparams(tuple)
    • 設定所有參數
      (nchannels, sampwidth, framerate, nframes, comptype, compname) 
  • Wave_write.getparams()
    • 取得所有參數
      (nchannels, sampwidth, framerate, nframes, comptype, compname)
  • Wave_write.tell()
    • 取得目前寫入位置
  • Wave_write.writeframesraw(data)
    • 寫入資料,但不更正 nframes,格式可為 bytes-like object
  • Wave_write.writeframes(data)
    • 寫入資料,並確認 nframes 的正確性
      stream 可 seek 的則會自動更正,格式可為 bytes-like object

參考

声音的输入输出

留言