やってみよう!

プログラミングとかでぃーぷらーにんぐとかVRとか気になったものをやってみる予定

リアルタイム音声変換メモ1

前回に引き続きリアルタイムに音声を変換するボコーダーをやってみます。

blog.ascreit.com

かなりハマっていて、できる気配がないのでメモを残しながら試行錯誤してみようと思います。

前回、マイク入力をそのままスピーカーに流すことはできたのですが、pyworldでsynthesize()をかけるとサイズが増えてしまってエラーになっていました。

「じゃあサイズ減らせばいいんじゃね?」ということで、単純に入り切らない後ろの部分だけを切ってみたコードがこちら

import queue
import sys
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
import sounddevice as sd
import pyworld as pw

def audio_callback(indata, outdata, frames, time, status):
    """サンプリングごとに呼ばれるコールバック関数"""
    if status:
        print(status, file=sys.stderr)

    try:
        # print(time)
        data = indata[:,0]
        # print(data.dtype,data.size,frames)
        data = data.astype(np.float64)
        _f0, t = pw.dio(data, samplerate)                   # 基本周波数の抽出
        f0 = pw.stonemask(data, _f0, t, samplerate)         # 基本周波数の修正
        sp = pw.cheaptrick(data, f0, t, samplerate)         # スペクトル包絡の抽出
        ap = pw.d4c(data, f0, t, samplerate)                # 非周期性指標の抽出
        data = pw.synthesize(f0*2, sp, ap, samplerate)    # 1オクターブ高い声に変換
        # スペクトル包絡を1.2倍
        # female_like_sp = np.zeros_like(sp)
        # for f in range(female_like_sp.shape[1]):
        #     female_like_sp[:, f] = sp[:, int(f/1.2)]
        # data = pw.synthesize(f0*2, female_like_sp, ap, samplerate)

        data = data.astype(np.float32)      # float64から32へ戻す
        data = data[:frames]

        # frames = data.size                  # 何故かsynthesize()で要素数が増えるので無理やり修正
        # data = data.reshape(data.size,1)    # 何故かsynthesize()で要素数が増えるので無理やり修正

        outdata[:,0] = data

    except Exception as e:
        print(e)

    global q
    q.put(outdata[:])


def update_plot(frame):
    """matplotlibのアニメーション更新毎に呼ばれるグラフ更新関数"""

    global plotdata
    while True:
        try:
            data = q.get_nowait()
        except queue.Empty:
            break

        shift = len(data)
        plotdata = np.roll(plotdata, -shift, axis=0)
        plotdata[-shift:, :] = data

        lines[0].set_ydata(plotdata[:, 0])

    return lines


if __name__ == '__main__':
    samplerate = 44100.0   # サンプリング周波数
    window = 0.2        # グラフ表示サンプル数決定係数
    interval = 3        # グラフ更新頻度(ミリ秒)
    channels = 1        # チャンネル数(1固定)

    q = queue.Queue()

    length = int(window * samplerate)   # グラフに表示するサンプル数
    plotdata = np.zeros((length, 1))

    fig, ax = plt.subplots()
    lines = ax.plot(plotdata)          # グラフのリアルタイム更新の最初はプロットから
    ax.axis((0, len(plotdata), -1, 1))

    stream = sd.Stream(channels=channels, samplerate=samplerate, callback=audio_callback,
        device=('USB PnP Audio Device: Audio','HDA NVidia: HDMI 1'))
    ani = FuncAnimation(fig, update_plot, interval=interval, blit=True)
    with stream:
        plt.show()

f:id:ascreit:20180804133622p:plain

どんな声が出てるのか録音して聞いてもらいたかったけど録音の仕方が分かりませんでした...

音は出ているのですが、バリバリ鳴る感じです。あと、高い声になってない。

無理やりカットしてるからそうなるよね...といった感じです。

ん〜だめかぁ...