achanger.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. #!usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # author: kuangdd
  4. # date: 2019/12/22
  5. """
  6. ### audio_changer
  7. 变声器,变高低音,变语速,变萝莉音,回声。
  8. """
  9. from pathlib import Path
  10. import logging
  11. logging.basicConfig(level=logging.INFO)
  12. logger = logging.getLogger(Path(__name__).stem)
  13. import numpy as np
  14. import librosa
  15. from .audio_io import _sr
  16. def change_pitch(wav, sr=_sr, rate=0.):
  17. """
  18. 调音高。
  19. :param rate:-20~20,float,0:原声
  20. :param wav:
  21. :param sr:
  22. :return:
  23. """
  24. return librosa.effects.pitch_shift(wav, sr=sr, n_steps=rate)
  25. def change_speed(wav, sr=_sr, rate=0.):
  26. """
  27. 调语速。
  28. :param rate:0~5,float,0:原声
  29. :param wav:
  30. :param sr:
  31. :return:
  32. """
  33. return librosa.effects.time_stretch(wav, rate)
  34. def change_sample(wav, sr=_sr, rate=1):
  35. """
  36. 调采样率,语速和音高同时改变。
  37. :param rate:0~5,float,1:原声
  38. :param wav:
  39. :param sr:
  40. :return:
  41. """
  42. return librosa.resample(wav, orig_sr=sr, target_sr=int(sr * rate))
  43. def change_reback(wav, sr=_sr, rate=1):
  44. """
  45. 回声。
  46. :param rate:1~10,int,1:原声
  47. :param wav:
  48. :param sr:
  49. :return:
  50. """
  51. frequencies, D = librosa.ifgram(wav, sr=sr)
  52. D = pool(D, size=(1, rate))
  53. D = repeat(D, rate)
  54. return librosa.istft(D)
  55. def change_pitchspeed(wav, sr=_sr, rate=1):
  56. """
  57. 音高和语速同时变化。
  58. :param rate:0~10,float,1:原声
  59. :param wav:
  60. :param sr:
  61. :return:
  62. """
  63. frequencies, D = librosa.ifgram(wav, sr=sr)
  64. n = int(D.shape[0] * rate)
  65. if n <= D.shape[0]:
  66. D = drop(D, D.shape[0] - n, mode="r")
  67. else:
  68. D = rewardshape(D, (n, D.shape[1]))
  69. return librosa.istft(D)
  70. def change_attention(wav, sr=_sr, rate=0):
  71. """
  72. 突出高音或低音段。
  73. :param rate:-100~100,int,0:原声
  74. :param wav:
  75. :param sr:
  76. :return:
  77. """
  78. frequencies, D = librosa.ifgram(wav, sr=sr)
  79. D = roll(D, rate)
  80. return librosa.istft(D)
  81. def change_male(wav, sr=_sr, rate=0):
  82. """
  83. 变男声。
  84. :param rate:0~1025,int,0,1,1025:原声
  85. :param wav:
  86. :param sr:
  87. :return:
  88. """
  89. frequencies, D = librosa.ifgram(wav, sr=sr)
  90. D = pool_step(D, rate)
  91. return librosa.istft(D)
  92. def change_stretch(wav, sr=_sr, rate=1):
  93. """
  94. 成倍拉伸延长。
  95. :param rate:1~10,int,1:原声
  96. :param wav:
  97. :param sr:
  98. :return:
  99. """
  100. frequencies, D = librosa.ifgram(wav, sr=sr)
  101. D = spread(D, rate)
  102. return librosa.istft(D)
  103. def change_vague(wav, sr=_sr, rate=1):
  104. """
  105. 模糊。
  106. :param rate:1~10,int,1:原声
  107. :param wav:
  108. :param sr:
  109. :return:
  110. """
  111. frequencies, D = librosa.ifgram(wav, sr=sr)
  112. D = pool(D, (1, rate))
  113. D = spread(D, (1, rate))
  114. return librosa.istft(D)
  115. class CheckStep(object):
  116. def __init__(self, step):
  117. self.step = step
  118. self.index = 0
  119. def __call__(self, *args):
  120. self.index += 1
  121. return self.index % self.step != 0
  122. def spread(D, size=(3, 3)):
  123. """传播,重复每个数据点。"""
  124. if isinstance(size, tuple):
  125. if size[0] > 1:
  126. D = np.repeat(D, size[0], axis=0)
  127. if size[1] > 1:
  128. D = np.repeat(D, size[1], axis=1)
  129. if size[0] * size[1] > 1:
  130. D = D / (size[0] * size[1])
  131. elif isinstance(size, int):
  132. D = np.repeat(D, size, axis=1)
  133. return D
  134. def drop(D, n, mode="l"):
  135. """丢弃,mode:left,right,side,center"""
  136. if n == 0:
  137. return D
  138. if mode == "l":
  139. return D[n:]
  140. elif mode == "r":
  141. return D[:-n]
  142. elif mode == "s":
  143. return D[n // 2:-(n // 2)]
  144. elif mode == "c":
  145. if n < len(D):
  146. return np.vstack((D[:n // 2], D[-(n // 2):]))
  147. else:
  148. return ()
  149. else:
  150. raise AssertionError
  151. def repeat(D, n, axis=0):
  152. """重复"""
  153. return np.repeat(D, n, axis=axis)
  154. def roll(D, n):
  155. """循环移动"""
  156. return np.roll(D, n, axis=0)
  157. def rewardshape(D, shape):
  158. """填充"""
  159. x = shape[0] - D.shape[0]
  160. y = shape[1] - D.shape[1]
  161. if x > 0:
  162. bottomlist = np.zeros([x, D.shape[1]])
  163. D = np.r_[D, bottomlist]
  164. if y > 0:
  165. rightlist = np.zeros([D.shape[0], y])
  166. D = np.c_[D, rightlist]
  167. return D
  168. def pool_step(D, step):
  169. """步长池化"""
  170. _shape = D.shape
  171. if step < 2:
  172. return D
  173. cs = CheckStep(step)
  174. return rewardshape(np.array(list(filter(cs, D))), _shape)
  175. def pool(D, size=(3, 3), shapeed=False):
  176. """池化"""
  177. _shape = D.shape
  178. if isinstance(size, tuple):
  179. if size[1] > 1:
  180. D = _pool(D, size[1])
  181. if size[0] > 1:
  182. D = _pool(D.T, size[0]).T
  183. elif isinstance(size, int):
  184. D = _pool(D.T, size).T
  185. if shapeed:
  186. D = rewardshape(D, _shape)
  187. return D
  188. def _pool(D, poolsize):
  189. """池化方法"""
  190. x = D.shape[1] // poolsize
  191. restsize = D.shape[1] % poolsize
  192. if restsize > 0:
  193. x += 1
  194. rightlist = np.zeros([D.shape[0], poolsize - restsize])
  195. D = np.c_[D, rightlist]
  196. D = D.reshape((-1, poolsize))
  197. D = D.sum(axis=1).reshape(-1, x)
  198. return D
  199. if __name__ == '__main__':
  200. from aukit.audio_player import play_audio
  201. path = r"C:/Users/jared/Downloads/hi.mp3"
  202. y, sr = librosa.load(path)
  203. # y = change_vague(3, y, sr)
  204. # y = change_pitch(-6, y, sr)
  205. # y = change_speed(0.5, y, sr)
  206. # y = change_sample(0.8, y, sr)
  207. # y = change_reback(3, y, sr)
  208. # y = change_pitchspeed(2, y, sr)
  209. # y = change_attention(50, y, sr)
  210. # y = change_male(5, y, sr)
  211. # y = change_vague(6, y, sr)
  212. """童声"""
  213. y = change_pitch(6, y, sr)
  214. y = change_male(20, y, sr)
  215. play_audio(y, sr=sr)