Pythonを使用した音声変換プログラムの作成
17642 ワード
Photo by Jake Kaminski on Unsplash
おんりょうちょうせい
おんりょうちょうせい
人の声の中で最も重要な要素であるトーンをどのように調整するかを理解してみましょう.
リサンプリングによるピッチ調整
最も簡単な方法は、音源ファイルをダウンサンプリングすると音の色調が低下し、逆にアップサンプリングすると音の色調が向上します.import librosa
import samplerate
import IPython.display as ipd
data, sr = librosa.load('example.wav', sr=None)
out_data1 = samplerate.resample(data, 0.5, 'sinc_best')
out_data2 = samplerate.resample(data, 1.5, 'sinc_best')
print('Higher pitch:')
ipd.display(ipd.Audio(out_data1, rate=sr))
print('Lower pitch:')
ipd.display(ipd.Audio(out_data2, rate=sr))
しかし、この方法を使うと、話すスピードにも影響があり、不自然に聞こえます.したがって、同じ速度でトーンを変更したい場合は、「マッチング同期ゼロオーバーと追加」アルゴリズムを使用する必要があります.
PSOLAアルゴリズムによるピッチ調整
まず、フレーム(Frame)単位で音声ファイルを分割し、同じ語速とトーンのみを変更します.この関数をframeize
に設定してみます.def frameize(x: np.array, N: int, H_a: int, hfilt: np.array) -> list:
"""Truncate audio sample into frames.
Params
------
x: audio array
N: segment size
H_a: analysis hop size
hfilt: windowing filter
Returns
-------
frames: segments of audio sample
"""
frames = []
idx = 0
while True:
try: frames += [hfilt*x[H_a*idx:H_a*idx+N]]
except: break
idx += 1
return frames
ここで、H_a
は音源部分間の間隔であり、N
は各部分の長さである.
これで、フレーム間隔を調整するだけで、サウンドファイルの時間を変更し、フレーム内のフィーチャーを保持できます.これをtime-stratingといい、distort_time
関数にしてみます.def distort_time(x: np.array, N: int, H_a: int,
hfilt: np.array, alpha: float) -> np.array:
"""Distort time of audio sample by given ratio.
Params
------
x: audio data
N: segment size
H_a: analysis hop size
hfilt: windowing filter
alpha: time-scaling factor
Returns
-------
out_x: time-scaled data
"""
# put into frames
frames = frameize(x, N, H_a, hfilt)
H_s = int(np.round(H_a*alpha))
interval = 200 # search area for best match
out_x = np.zeros(len(frames)*H_s+N)
# time-distorting
for i, frame in enumerate(frames):
# end parts
if i == len(frames) - 1:
hfilt_norm = find_hfilt_norm(hfilt, H_s)
# start, middle parts
else:
hfilt_norm = find_hfilt_norm(hfilt, H_s)
out_x[i*H_s:i*H_s+N] += frame/hfilt_norm
return out_x
ここで、find_hfilt_norm
関数は、分割時に適用されたフィルタを再消去する役割を果たす.
その後、再サンプリングが1/(フレーム間隔パーセント)の場合、時間は元の水平に戻り、間隔は変化します.このメソッドは、関数synthesize_pitch
に表示されます.def synthesize_pitch(x: np.array, sr: int, N: int, H_a: int,
hfilt: np.array, alpha: float) -> np.array:
"""Synthesize sound sample into new one with different pitch using PSOLA algorithm.
Params
------
x: audio data
sr: sampling rate
N: segment size
H_a: analysis hop size
hfilt: windowing filter
alpha: pitch factor
Returns
-------
syn_x: synthesized data
"""
syn_data = distort_time(x, N, H_a, hfilt, alpha)
# resampling
syn_data = samplerate.resample(syn_data, 1/alpha, 'sinc_best')
syn_data = syn_data/np.max(abs(syn_data))
return syn_data
この場合、周囲にフレーム間の溝がある必要があり、時間が長くなると切断された音が聞こえなくなり、フレーム間隔を変更すると溝に間欠が発生するため、この問題を解決するために、溝間隔をさらに調整して、中断の程度を最小限に抑えることができる.
ピッチ調整機能付きFrequencesStretching
ピッチをある程度高くすると、音はヘリウム音になります.この問題を緩和するために、β=α1/3\beta=\alpha^{1/3}β=α1/3の割合で増加すると、よりナチュラルな色合いになります.こちらです.α\alphaα pitch因子値です.β\betaβ はstretching factor値です.この式は数回の実験によって確立され,この論文で見ることができる.N = 1024 # segment size for sampling rate 44100 Hz
H_a = int(N*0.5) # analysis hop size between 0.5 ~ 1
hfilt = np.hanning(N) # filter type
# input
data, sr = librosa.load('example.wav', sr=None)
ipd.display(ipd.Audio(data, rate=sr, normalize=False))
alpha = 1.6 # pitch
# pitch increase
data = synthesize_pitch(data, sr, N, H_a, hfilt, alpha=alpha)
# frequency stretching
S1 = librosa.stft(data, n_fft=512, hop_length=64)
S2 = warp_spectrum(S1, alpha**(1/3))
data = librosa.istft(S2, hop_length=64, win_length=512)
ipd.display(ipd.Audio(data, rate=sr, normalize=True))
完全なコードは羽根で記述されている.
最後に、より自然に音を変えるためには、トーンだけでなく、他の特性も調整しなければならない.その部分は次の授業で紹介しましょう.
Reference
この問題について(Pythonを使用した音声変換プログラムの作成), 我々は、より多くの情報をここで見つけました
https://velog.io/@paulleelife/파이썬으로-음성변환-프로그램-만들기
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
import librosa
import samplerate
import IPython.display as ipd
data, sr = librosa.load('example.wav', sr=None)
out_data1 = samplerate.resample(data, 0.5, 'sinc_best')
out_data2 = samplerate.resample(data, 1.5, 'sinc_best')
print('Higher pitch:')
ipd.display(ipd.Audio(out_data1, rate=sr))
print('Lower pitch:')
ipd.display(ipd.Audio(out_data2, rate=sr))
def frameize(x: np.array, N: int, H_a: int, hfilt: np.array) -> list:
"""Truncate audio sample into frames.
Params
------
x: audio array
N: segment size
H_a: analysis hop size
hfilt: windowing filter
Returns
-------
frames: segments of audio sample
"""
frames = []
idx = 0
while True:
try: frames += [hfilt*x[H_a*idx:H_a*idx+N]]
except: break
idx += 1
return frames
def distort_time(x: np.array, N: int, H_a: int,
hfilt: np.array, alpha: float) -> np.array:
"""Distort time of audio sample by given ratio.
Params
------
x: audio data
N: segment size
H_a: analysis hop size
hfilt: windowing filter
alpha: time-scaling factor
Returns
-------
out_x: time-scaled data
"""
# put into frames
frames = frameize(x, N, H_a, hfilt)
H_s = int(np.round(H_a*alpha))
interval = 200 # search area for best match
out_x = np.zeros(len(frames)*H_s+N)
# time-distorting
for i, frame in enumerate(frames):
# end parts
if i == len(frames) - 1:
hfilt_norm = find_hfilt_norm(hfilt, H_s)
# start, middle parts
else:
hfilt_norm = find_hfilt_norm(hfilt, H_s)
out_x[i*H_s:i*H_s+N] += frame/hfilt_norm
return out_x
def synthesize_pitch(x: np.array, sr: int, N: int, H_a: int,
hfilt: np.array, alpha: float) -> np.array:
"""Synthesize sound sample into new one with different pitch using PSOLA algorithm.
Params
------
x: audio data
sr: sampling rate
N: segment size
H_a: analysis hop size
hfilt: windowing filter
alpha: pitch factor
Returns
-------
syn_x: synthesized data
"""
syn_data = distort_time(x, N, H_a, hfilt, alpha)
# resampling
syn_data = samplerate.resample(syn_data, 1/alpha, 'sinc_best')
syn_data = syn_data/np.max(abs(syn_data))
return syn_data
N = 1024 # segment size for sampling rate 44100 Hz
H_a = int(N*0.5) # analysis hop size between 0.5 ~ 1
hfilt = np.hanning(N) # filter type
# input
data, sr = librosa.load('example.wav', sr=None)
ipd.display(ipd.Audio(data, rate=sr, normalize=False))
alpha = 1.6 # pitch
# pitch increase
data = synthesize_pitch(data, sr, N, H_a, hfilt, alpha=alpha)
# frequency stretching
S1 = librosa.stft(data, n_fft=512, hop_length=64)
S2 = warp_spectrum(S1, alpha**(1/3))
data = librosa.istft(S2, hop_length=64, win_length=512)
ipd.display(ipd.Audio(data, rate=sr, normalize=True))
Reference
この問題について(Pythonを使用した音声変換プログラムの作成), 我々は、より多くの情報をここで見つけました https://velog.io/@paulleelife/파이썬으로-음성변환-프로그램-만들기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol