LoginSignup
2
1

More than 5 years have passed since last update.

楽曲からのボーカル抽出とスケーリング処理 (python3)

Posted at

実装:スケーリング処理 題材:ボーカル抽出

紛らわしいタイトルでしたら申し訳ありません。

Deep U-Netで自動歌声分離
https://qiita.com/xiao_ming/items/88826e576b87141c4909

@xiao_ming さんのこちらの記事で紹介されているボーカル抽出を使いたかったのですが、公開されているサンプルコードではFFTのフレームにして1024~2048フレーム分(時間軸にしてだいたい33秒~66秒)ぐらいしか処理されなかったので楽曲全体で処理できるようにスケーリング処理をしたという内容になります。中身はただのスケーリング処理なのですが、もしかしたら自分と同じように1曲分ボーカル抽出をやりたいというような人がいるかもと思ったので記事にしてみようと思いました。あとQiitaへの投稿も多くないのでそれの勉強も兼ねてということで。
変数の付け方とかがアホっぽいのはご勘弁を。

該当コード

公開されているdoexperiment.pyを使うことでボーカル抽出のデモができるようになっています。(同じディレクトリにutil.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フレーム分しかできないので、これをスケーリング処理にして全時間分適用させるようにしたものが以下のコードです。

doexperiment2.py

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以下になると処理をやめてしまいますので、最後の数秒は処理ができていないことになります。なんてこった。

今後の展望

色々雑な点はありますがまずは指定フォルダ内の全ファイルにこれが適応できるようにクラス作ったりフォルダ内のファイル名一覧取得とかをやっていきたいと思います。

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1