audio_cli.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #!usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # author: kuangdd
  4. # date: 2020/1/5
  5. """
  6. ### audio_cli
  7. 命令行,播放音频,去除背景噪声,音频格式转换。
  8. 支持递归处理文件夹内的全部音频。
  9. #### 命令行
  10. ##### **说明**
  11. - 用位置参数来控制。
  12. - 名称说明
  13. * inpath:输入音频路径或目录。
  14. * outpath:输出音频路径或目录,如果为目录,则输出的子目录按照inpath的子目录格式输出。
  15. * sr:音频采样率,默认16000或自动识别采样率。
  16. * in_format:输入音频格式,主要用以限制为指定后缀名的文件,如果不设置,则处理目录的全部文件。
  17. * out_format:输出音频格式,主要用以音频格式转换,设置输出音频的后缀名。
  18. - 中括号【[]】里面的是可选参数。
  19. #### **工具**
  20. - auplay: 播放音频
  21. ```
  22. auplay inpath [sr] [in_format]
  23. ```
  24. - aunoise: 语音降噪
  25. ```
  26. aunoise inpath outpath [in_format]
  27. ```
  28. - auformat: 音频格式转换
  29. ```
  30. auformat inpath outpath out_format [in_format]
  31. ```
  32. """
  33. from pathlib import Path
  34. import logging
  35. logging.basicConfig(level=logging.INFO)
  36. logger = logging.getLogger(Path(__name__).stem)
  37. import sys
  38. from functools import partial
  39. from multiprocessing import Pool
  40. from tqdm import tqdm
  41. from pathlib import Path
  42. import traceback
  43. import multiprocessing as mp
  44. from .audio_io import _sr
  45. from .audio_player import play_audio
  46. from .audio_noise_remover import remove_noise_os
  47. from .audio_editor import convert_format_os
  48. _n_process = max(1, mp.cpu_count() - 2)
  49. def play_audio_one(inpath, sr):
  50. try:
  51. play_audio(inpath, sr=sr)
  52. except Exception as e:
  53. logger.info("PlayAudioFailed: {}".format(inpath))
  54. traceback.print_exc()
  55. def play_audio_cli():
  56. fpath = Path(sys.argv[1])
  57. if len(sys.argv) >= 3:
  58. sr = int(sys.argv[2])
  59. else:
  60. sr = _sr
  61. if len(sys.argv) >= 4:
  62. in_format = sys.argv[3]
  63. else:
  64. in_format = None
  65. if fpath.is_file():
  66. play_audio_one(fpath, sr=sr)
  67. elif fpath.is_dir():
  68. tmp = "**/*" if in_format is None else "**/*.{}".format(in_format)
  69. for inpath in sorted(fpath.glob(tmp)):
  70. if not inpath.is_file():
  71. continue
  72. try:
  73. play_audio_one(inpath, sr=sr)
  74. except Exception as e:
  75. logger.info("PlayAudioFailed: {}".format(inpath))
  76. traceback.print_exc()
  77. else:
  78. assert fpath.exists()
  79. def remove_noise_one(x):
  80. outpath = Path(x["outpath"])
  81. outpath.parent.mkdir(exist_ok=True, parents=True)
  82. try:
  83. out = remove_noise_os(**x)
  84. except Exception as e:
  85. inpath = str(x["inpath"])
  86. logger.info("RemoveNoiseFailed: {}".format(inpath))
  87. traceback.print_exc()
  88. out = None
  89. return out
  90. def remove_noise_cli():
  91. inpath = Path(sys.argv[1])
  92. outpath = Path(sys.argv[2])
  93. if len(sys.argv) >= 4:
  94. in_format = sys.argv[3]
  95. else:
  96. in_format = None
  97. if inpath.is_file():
  98. remove_noise_one(dict(inpath=inpath, outpath=outpath))
  99. elif inpath.is_dir():
  100. indir = inpath
  101. outdir = outpath
  102. kw_lst = []
  103. tmp = "**/*" if in_format is None else "**/*.{}".format(in_format)
  104. for inpath in indir.glob(tmp):
  105. if not inpath.is_file():
  106. continue
  107. parts = inpath.relative_to(indir).parts
  108. outpath = outdir.joinpath(*parts)
  109. kw = dict(inpath=str(inpath), outpath=str(outpath))
  110. kw_lst.append(kw)
  111. pool_jobs(func=remove_noise_one, n_process=_n_process, kwargs_list=kw_lst, tqdm_desc='remove_noise')
  112. else:
  113. assert inpath.exists()
  114. def convert_format_one(x):
  115. outpath = Path(x["outpath"])
  116. outpath.parent.mkdir(exist_ok=True, parents=True)
  117. try:
  118. out = convert_format_os(**x)
  119. except Exception as e:
  120. inpath = str(x["inpath"])
  121. logger.info("ConvertFormatFailed: {}".format(inpath))
  122. traceback.print_exc()
  123. out = None
  124. return out
  125. def convert_format_cli():
  126. inpath = Path(sys.argv[1])
  127. outpath = Path(sys.argv[2])
  128. out_format = sys.argv[3]
  129. if len(sys.argv) >= 5:
  130. in_format = sys.argv[4]
  131. else:
  132. in_format = None
  133. if inpath.is_file():
  134. convert_format_one(dict(inpath=inpath, outpath=outpath, in_format=in_format, out_format=out_format))
  135. elif inpath.is_dir():
  136. indir = inpath
  137. outdir = outpath
  138. kw_lst = []
  139. tmp = "**/*" if in_format is None else "**/*.{}".format(in_format)
  140. for inpath in indir.glob(tmp):
  141. if not inpath.is_file():
  142. continue
  143. parts = inpath.parent.relative_to(indir).parts
  144. name = "{}.{}".format(inpath.stem, out_format)
  145. outpath = outdir.joinpath(*parts, name)
  146. kw = dict(inpath=str(inpath), outpath=str(outpath), in_format=in_format, out_format=out_format)
  147. kw_lst.append(kw)
  148. pool_jobs(func=convert_format_one, n_process=_n_process, kwargs_list=kw_lst, tqdm_desc='convert_format')
  149. else:
  150. assert inpath.exists()
  151. def pool_jobs(func, n_process=_n_process, kwargs_list=(), post_func=None, tqdm_desc="job"):
  152. """
  153. 多进程执行任务。
  154. :param func: 第一个参数为变化参数,如果多个参数组合变化,请用:【def _func(x): return func(**x)】的方式处理函数。
  155. :param n_process:
  156. :param kwargs_list:
  157. :param post_func:
  158. :param tqdm_desc:
  159. :return:
  160. """
  161. if post_func is None:
  162. post_func = lambda x: x
  163. _tqdm = lambda x: tqdm(x, desc=tqdm_desc, total=len(kwargs_list), ncols=80, mininterval=1)
  164. if n_process == 0 or n_process == 1:
  165. for kw in _tqdm(kwargs_list):
  166. out = func(kw)
  167. post_func(out)
  168. else:
  169. partial_func = partial(func)
  170. job = Pool(n_process).imap(partial_func, kwargs_list)
  171. for out in list(_tqdm(job)):
  172. post_func(out)
  173. if __name__ == "__main__":
  174. print(__file__)