要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