PyAudioとPyWorldで音声を逐次分析合成しつづけるPythonスクリプト

PyAudio & PyWorld。Numpyも。
合成するまでには、ある程度の遅延は発生するけども、まぁ許容範囲でしょう。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

# Copyright (c) 2020 Akira TAMAMORI
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import numpy as np
import pyaudio
import pyworld as pw


sample_rate = 16000
frame_length = 1024 * 8


def audio_trans(input):

    signal = np.frombuffer(input, dtype='int16')
    signal = signal.astype(np.float64)
    f0, t = pw.harvest(signal, sample_rate)  # 基本周波数の抽出
    sp = pw.cheaptrick(signal, f0, t, sample_rate)  # スペクトル包絡の抽出
    ap = pw.d4c(signal, f0, t, sample_rate)  # 非周期性指標の抽出

    synth = pw.synthesize(modified_f0, modified_sp, ap, sample_rate)

    return synth.astype(np.int16).tobytes()


if __name__ == "__main__":

    audio = pyaudio.PyAudio()

    stream = audio.open(format=pyaudio.paInt16,
                        channels=1,
                        rate=sample_rate,
                        frames_per_buffer=frame_length,
                        input=True,
                        output=True)
    try:
        while stream.is_active():
            input = stream.read(frame_length, exception_on_overflow=False)
            input = audio_trans(input)
            stream.write(input)

    except KeyboardInterrupt:
        stream.stop_stream()
        stream.close()
        audio.terminate()
        print("Stop Streaming")

声の高さと声色を調整してボイスチェンジャー的に遊んでみたい方は以下のコード。
gist.github.com