audio_io.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. #!usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # author: kuangdd
  4. # date: 2019/12/1
  5. """
  6. ### audio_io
  7. 语音IO,语音保存、读取,支持wav和mp3格式,语音形式转换(np.array,bytes,io.BytesIO),支持【.】操作符的字典。
  8. """
  9. from pathlib import Path
  10. import logging
  11. logging.basicConfig(level=logging.INFO)
  12. logger = logging.getLogger(Path(__name__).stem)
  13. from scipy.io import wavfile
  14. from pathlib import Path
  15. import numpy as np
  16. import librosa
  17. import io
  18. import json
  19. from dotmap import DotMap
  20. _sr = 16000
  21. _int16_max = 2 ** 15 - 1
  22. class Dict2Obj(DotMap):
  23. """
  24. 修正DotMap的get方法生成DotMap对象的bug。
  25. Dict2Obj的get方法和dict的get功能相同。
  26. """
  27. def __getitem__(self, k):
  28. if k not in self._map:
  29. return None
  30. else:
  31. return self._map[k]
  32. def parse(self, json_string):
  33. if json_string.strip():
  34. _hp = json.loads(json_string)
  35. for k, v in _hp.items():
  36. self[k] = v
  37. return self
  38. def load_wav(path, sr=None, with_sr=False):
  39. """
  40. 导入语音信号。支持wav和mp3格式。
  41. :param path: 文件路径。
  42. :param sr: 采样率,None: 自动识别采样率。
  43. :param with_sr: 是否返回采样率。
  44. :return: np.ndarray
  45. """
  46. return load_wav_librosa(path, sr=sr, with_sr=with_sr)
  47. def save_wav(wav, path, sr=_sr):
  48. save_wav_wavfile(wav, path=path, sr=sr)
  49. def load_wav_librosa(path, sr=_sr, with_sr=False):
  50. wav, sr = librosa.core.load(path, sr=sr)
  51. return (wav, sr) if with_sr else wav
  52. def load_wav_wavfile(path, sr=None, with_sr=False):
  53. sr, wav = wavfile.read(path)
  54. wav = wav / np.max(np.abs(wav))
  55. return (wav, sr) if with_sr else wav
  56. def save_wav_librosa(wav, path, sr=_sr):
  57. librosa.output.write_wav(path, wav, sr=sr)
  58. def save_wav_wavfile(wav, path, sr=_sr, volume=1.):
  59. out = wav * _int16_max * volume / max(0.01, np.max(np.abs(wav)))
  60. # proposed by @dsmiller
  61. wavfile.write(path, sr, out.astype(np.int16))
  62. def anything2bytesio(src, sr=_sr, volume=1.):
  63. if isinstance(src, (str, Path)):
  64. src = load_wav(src, sr=sr)
  65. if isinstance(src, (list, np.ndarray, np.matrix)):
  66. out_io = io.BytesIO()
  67. save_wav_wavfile(src, out_io, sr=sr, volume=volume)
  68. elif isinstance(src, bytes):
  69. out_io = io.BytesIO(src)
  70. elif isinstance(src, io.BytesIO):
  71. out_io = src
  72. else:
  73. raise TypeError
  74. return out_io
  75. def anything2wav(src, sr=_sr, volume=1.):
  76. if isinstance(src, (list, np.ndarray, np.matrix)):
  77. return np.array(src)
  78. else:
  79. bysio = anything2bytesio(src, sr=sr, volume=volume)
  80. return load_wav_wavfile(bysio, sr=sr)
  81. def anything2bytes(src, sr=_sr, volume=1.):
  82. if isinstance(src, bytes):
  83. return src
  84. else:
  85. bysio = anything2bytesio(src, sr=sr, volume=volume)
  86. return bysio.getvalue()
  87. if __name__ == "__main__":
  88. print(__file__)
  89. inpath = r"../hello.wav"
  90. bys = anything2bytesio(inpath, sr=16000)
  91. print(bys)
  92. wav = anything2wav(bys, sr=16000)
  93. print(wav)