123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- #!usr/bin/env python
- # -*- coding: utf-8 -*-
- # author: kuangdd
- # date: 2019/12/22
- """
- ### audio_changer
- 变声器,变高低音,变语速,变萝莉音,回声。
- """
- from pathlib import Path
- import logging
- logging.basicConfig(level=logging.INFO)
- logger = logging.getLogger(Path(__name__).stem)
- import numpy as np
- import librosa
- from .audio_io import _sr
- def change_pitch(wav, sr=_sr, rate=0.):
- """
- 调音高。
- :param rate:-20~20,float,0:原声
- :param wav:
- :param sr:
- :return:
- """
- return librosa.effects.pitch_shift(wav, sr=sr, n_steps=rate)
- def change_speed(wav, sr=_sr, rate=0.):
- """
- 调语速。
- :param rate:0~5,float,0:原声
- :param wav:
- :param sr:
- :return:
- """
- return librosa.effects.time_stretch(wav, rate)
- def change_sample(wav, sr=_sr, rate=1):
- """
- 调采样率,语速和音高同时改变。
- :param rate:0~5,float,1:原声
- :param wav:
- :param sr:
- :return:
- """
- return librosa.resample(wav, orig_sr=sr, target_sr=int(sr * rate))
- def change_reback(wav, sr=_sr, rate=1):
- """
- 回声。
- :param rate:1~10,int,1:原声
- :param wav:
- :param sr:
- :return:
- """
- frequencies, D = librosa.ifgram(wav, sr=sr)
- D = pool(D, size=(1, rate))
- D = repeat(D, rate)
- return librosa.istft(D)
- def change_pitchspeed(wav, sr=_sr, rate=1):
- """
- 音高和语速同时变化。
- :param rate:0~10,float,1:原声
- :param wav:
- :param sr:
- :return:
- """
- frequencies, D = librosa.ifgram(wav, sr=sr)
- n = int(D.shape[0] * rate)
- if n <= D.shape[0]:
- D = drop(D, D.shape[0] - n, mode="r")
- else:
- D = rewardshape(D, (n, D.shape[1]))
- return librosa.istft(D)
- def change_attention(wav, sr=_sr, rate=0):
- """
- 突出高音或低音段。
- :param rate:-100~100,int,0:原声
- :param wav:
- :param sr:
- :return:
- """
- frequencies, D = librosa.ifgram(wav, sr=sr)
- D = roll(D, rate)
- return librosa.istft(D)
- def change_male(wav, sr=_sr, rate=0):
- """
- 变男声。
- :param rate:0~1025,int,0,1,1025:原声
- :param wav:
- :param sr:
- :return:
- """
- frequencies, D = librosa.ifgram(wav, sr=sr)
- D = pool_step(D, rate)
- return librosa.istft(D)
- def change_stretch(wav, sr=_sr, rate=1):
- """
- 成倍拉伸延长。
- :param rate:1~10,int,1:原声
- :param wav:
- :param sr:
- :return:
- """
- frequencies, D = librosa.ifgram(wav, sr=sr)
- D = spread(D, rate)
- return librosa.istft(D)
- def change_vague(wav, sr=_sr, rate=1):
- """
- 模糊。
- :param rate:1~10,int,1:原声
- :param wav:
- :param sr:
- :return:
- """
- frequencies, D = librosa.ifgram(wav, sr=sr)
- D = pool(D, (1, rate))
- D = spread(D, (1, rate))
- return librosa.istft(D)
- class CheckStep(object):
- def __init__(self, step):
- self.step = step
- self.index = 0
- def __call__(self, *args):
- self.index += 1
- return self.index % self.step != 0
- def spread(D, size=(3, 3)):
- """传播,重复每个数据点。"""
- if isinstance(size, tuple):
- if size[0] > 1:
- D = np.repeat(D, size[0], axis=0)
- if size[1] > 1:
- D = np.repeat(D, size[1], axis=1)
- if size[0] * size[1] > 1:
- D = D / (size[0] * size[1])
- elif isinstance(size, int):
- D = np.repeat(D, size, axis=1)
- return D
- def drop(D, n, mode="l"):
- """丢弃,mode:left,right,side,center"""
- if n == 0:
- return D
- if mode == "l":
- return D[n:]
- elif mode == "r":
- return D[:-n]
- elif mode == "s":
- return D[n // 2:-(n // 2)]
- elif mode == "c":
- if n < len(D):
- return np.vstack((D[:n // 2], D[-(n // 2):]))
- else:
- return ()
- else:
- raise AssertionError
- def repeat(D, n, axis=0):
- """重复"""
- return np.repeat(D, n, axis=axis)
- def roll(D, n):
- """循环移动"""
- return np.roll(D, n, axis=0)
- def rewardshape(D, shape):
- """填充"""
- x = shape[0] - D.shape[0]
- y = shape[1] - D.shape[1]
- if x > 0:
- bottomlist = np.zeros([x, D.shape[1]])
- D = np.r_[D, bottomlist]
- if y > 0:
- rightlist = np.zeros([D.shape[0], y])
- D = np.c_[D, rightlist]
- return D
- def pool_step(D, step):
- """步长池化"""
- _shape = D.shape
- if step < 2:
- return D
- cs = CheckStep(step)
- return rewardshape(np.array(list(filter(cs, D))), _shape)
- def pool(D, size=(3, 3), shapeed=False):
- """池化"""
- _shape = D.shape
- if isinstance(size, tuple):
- if size[1] > 1:
- D = _pool(D, size[1])
- if size[0] > 1:
- D = _pool(D.T, size[0]).T
- elif isinstance(size, int):
- D = _pool(D.T, size).T
- if shapeed:
- D = rewardshape(D, _shape)
- return D
- def _pool(D, poolsize):
- """池化方法"""
- x = D.shape[1] // poolsize
- restsize = D.shape[1] % poolsize
- if restsize > 0:
- x += 1
- rightlist = np.zeros([D.shape[0], poolsize - restsize])
- D = np.c_[D, rightlist]
- D = D.reshape((-1, poolsize))
- D = D.sum(axis=1).reshape(-1, x)
- return D
- if __name__ == '__main__':
- from aukit.audio_player import play_audio
- path = r"C:/Users/jared/Downloads/hi.mp3"
- y, sr = librosa.load(path)
- # y = change_vague(3, y, sr)
- # y = change_pitch(-6, y, sr)
- # y = change_speed(0.5, y, sr)
- # y = change_sample(0.8, y, sr)
- # y = change_reback(3, y, sr)
- # y = change_pitchspeed(2, y, sr)
- # y = change_attention(50, y, sr)
- # y = change_male(5, y, sr)
- # y = change_vague(6, y, sr)
- """童声"""
- y = change_pitch(6, y, sr)
- y = change_male(20, y, sr)
- play_audio(y, sr=sr)
|