実装:スケーリング処理 題材:ボーカル抽出
紛らわしいタイトルでしたら申し訳ありません。
Deep U-Netで自動歌声分離
https://qiita.com/xiao_ming/items/88826e576b87141c4909
@xiao_ming さんのこちらの記事で紹介されているボーカル抽出を使いたかったのですが、公開されているサンプルコードではFFTのフレームにして1024~2048フレーム分(時間軸にしてだいたい33秒~66秒)ぐらいしか処理されなかったので楽曲全体で処理できるようにスケーリング処理をしたという内容になります。中身はただのスケーリング処理なのですが、もしかしたら自分と同じように1曲分ボーカル抽出をやりたいというような人がいるかもと思ったので記事にしてみようと思いました。あとQiitaへの投稿も多くないのでそれの勉強も兼ねてということで。
変数の付け方とかがアホっぽいのはご勘弁を。
該当コード
公開されているdoexperiment.pyを使うことでボーカル抽出のデモができるようになっています。(同じディレクトリにutil.pyもある前提)
import uitl.py
# init
fname = "test.wav"
mag, phase = util.LoadAudio(fname)
start = 0#2048
end = start+1024
print(mag.shape)
print(mag[:,start:end].shape)
# adapt mask
mask = util.ComputeMask(mag[:,start:end], unet_model="unet.model", hard=False)
# save
util.SaveAudio(
"./wav/"+"vocal-%s" % fname, mag[:, start:end]*mask, phase[:, start:end])
util.SaveAudio(
"./wav/inst-%s" % fname, mag[:, start:end]*(1-mask), phase[:, start:end])
util.SaveAudio(
"./wav/orig-%s" % fname, mag[:, start:end], phase[:, start:end])
そしてこのままでは曲の一部しかボーカル抽出できない+maskの適用は32~1024フレーム分しかできないので、これをスケーリング処理にして全時間分適用させるようにしたものが以下のコードです。
import util
import numpy as np
fname = "test.wav"
mag, phase = util.LoadAudio(fname)
# init
start = 0
end = start+1024
initnum = 10
if len(mag[:,start:end][0]) != 1024:
end = start+512
initnum = 9
if len(mag[:,start:end][0]) != 512:
print("too short. input more long File")
# first processing
mask = util.ComputeMask(mag[:,start:end], unet_model="unet.model", hard=False)
savemag = mag[:,start:end]*mask
savemag1 = mag[:,start:end]*(1-mask)
start = end
end = start+2**initnum
print("length abst data", mag[:,start:end].shape)
# loop processing
diff = 0
endpoint=True
while(endpoint):
num = initnum
while len(mag[:,start:end][0]) != 2**num: #need modity
num-=1
end = start+2**num
if num==5:
endpoint = False
diff = len(mag[:,start:end][0])
break
if (endpoint):
mask = util.ComputeMask(mag[:,start:end], unet_model="unet.model", hard=False)
savemag = np.concatenate((savemag,mag[:,start:end]*mask),axis = 1)
savemag1 = np.concatenate((savemag1,mag[:,start:end]*(1-mask)), axis = 1)
print("concatenate list")
# print(savemag-mag[:,start:end])
else:
print(np.shape(savemag))
# print(savemag)
print()
break
start = end
end = start+2**num
end -= 2**num
util.SaveAudio(
"./wav/vocal-all%s" % fname, savemag, phase[:, :end])
util.SaveAudio(
"./wav/inst-all%s" % fname, savemag1, phase[:, :end])
originalはどうせ適応前のデータあるならいらないかなと思って保存のコードを省きました。
改変コードについて
大雑把に説明すると、mask適応をしたフレームのmagをnumpyのconcatenateでスタックしていきます。
最後にutil.SaveAudioを使って全範囲のmag, phaseを合わせて音声ファイルとして保存します。
細かい所で色々微調整していますが基本的にはフレームが2^(initnum)より小さかったら2^(initnum-1)より大きいか調べる
というような処理をして最後にphaseの長さと揃えるために帳尻合わせをしています。
全時間分と散々書いていますが厳密には後ろの残りフレームが64以下になると処理をやめてしまいますので、最後の数秒は処理ができていないことになります。なんてこった。
今後の展望
色々雑な点はありますがまずは指定フォルダ内の全ファイルにこれが適応できるようにクラス作ったりフォルダ内のファイル名一覧取得とかをやっていきたいと思います。