HOWTO · Python

Python オーディオ合成

このチュートリアルでは、Python でオーディオ合成を学習し、Python でオーディオ合成を生成するためのさまざまなコード例を示します。

このページの内容

今日は、オーディオ合成と、Python を使用してサウンドを生成する方法について学びます。

Python オーディオ合成

サウンド合成またはオーディオ合成は、人間の声や楽器を模倣するサウンドを (ハードウェアまたはソフトウェアを使用して) 電子的に生成します。

合成は主に音楽用であり、シンセサイザーとして知られる電子デバイス/楽器を使用して音楽を録音および実行します。

さて、重要なのは、Python を使用して、これらの種類の単純な音、たとえば正弦波を生成できるかということです。 そのためのモジュールはありますか、または独自のモジュールを作成するにはどうすればよいですか?

以下のさまざまな方法を学びましょう。

Python での加算合成に IPython.display を使用する

  • まず、必要なモジュールとライブラリをインポートします。 IPython をインポートしてサウンド プレーヤーを表示し、numpy を配列を操作するために、matplotlib をインポートしてグラフを作成します (基本的な波形を生成しながら実行します)、そして数学関数を使用するために math をインポートします。
    import IPython.display as ipd
    import numpy
    import math
    import matplotlib.pyplot as plt
    
  • サンプルレートを設定します。 ここでは、sample_rate22050 に設定します。
    sample_rate = 22050
    
  • 正弦波を作ります。
    def makesine(frequency, duration):
        t = numpy.linspace(0, duration, math.ceil(sample_rate * duration))
        x = numpy.sin(2 * numpy.pi * frequency * t)
        return x
    

    このステップでは、パラメータとして frequencyduration を取る関数 makesine() を定義します。 numpy.linspace() メソッドで duration を、numpy.sin() メソッドで frequency を使用して、純粋な正弦波形を再利用します。

    numpy.linspace() は数値シーケンスを作成することに注意してください。または、等間隔の数値/サンプルを返すと言えます。 間隔 (開始、停止)。 numpy.arange() に似ていますが、step の代わりにサンプル番号 (num) をパラメーターとして取ります。

    詳しくは こちら をご覧ください。

    一方、numpy.sin() は、指定されたすべての x (要素の配列) について三角関数のサインを計算します。

  • makesine() を実行します。
    output = numpy.array(())
    y = makesine(261.63, 0.5)  # C for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    y = makesine(293.66, 0.5)  # D for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    y = makesine(329.63, 0.5)  # E for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    ipd.Audio(output, rate=sample_rate)
    

    次に、makesine() を複数回実行して、指定された frequencyduration で新しい波形を形成します。 その後、numpy.concatenate() を使用してすべてをまとめます。

    以下の完全な作業ソース コードと、それぞれの出力を見つけることができます。

  • これが完全なソースコードです。
    import IPython.display as ipd
    import matplotlib.pyplot as plt
    import numpy
    import math
    
    sample_rate = 22050
    
    
    def makesine(frequency, duration):
        t = numpy.linspace(0, duration, math.ceil(sample_rate * duration))
        x = numpy.sin(2 * numpy.pi * frequency * t)
        return x
    
    
    output = numpy.array(())
    y = makesine(261.63, 0.5)  # C for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    y = makesine(293.66, 0.5)  # D for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    y = makesine(329.63, 0.5)  # E for 0.5 seconds
    
    output = numpy.concatenate((output, y))
    ipd.Audio(output, rate=sample_rate)
    

    出力:

    python 音声合成 - ipython display.wav

Python で加算合成を使用してさまざまな基本的な波形を作成する

基本的な正弦波が完成しました。 frequency * i を使用して、整数倍の周波数を持つさまざまな基本的な波形を試してみましょう。 ここで、i1 からのカウンターで、毎回 1 ずつ増加します。

これらの正弦波を定義済みの振幅 (amplist) に柔らかくする必要があります。これは、output に積み上げられます。 これを実現するには、次のように addsyn() という名前の関数を作成する必要があります。

def addsyn(frequency, duration, amplist):
    i = 1
    t = numpy.linspace(0, duration, math.ceil(sample_rate * duration))
    output = numpy.zeros(t.size)

    for amp in amplist:
        x = numpy.multiply(makesine(frequency * i, duration), amp)
        output = output + x
        i += 1

    if numpy.max(output) > abs(numpy.min(output)):
        output = output / numpy.max(output)
    else:
        output = output / -numpy.min(output)
    return output

addsyn() の中で、新しい output を初期化します。 for ループ内で、最大振幅 (amp) の正弦波を作成します。 ここで、frequency は整数倍です。

次に、それを出力に合計し、output 変数に保存します。 次に、最大振幅が 1 を超えないことを確認し、output を返します。

ここで、次のコードを実行して高調波正弦波を 1つだけ作成し、0.005 秒だけを示すチャートを作成して、この波形形状を確認できます。

t = numpy.linspace(0, 1, sample_rate)
sinewave = addsyn(440, 1, [1])
plt.plot(t, sinewave)
plt.xlim(0, 0.005)
ipd.Audio(sinewave, rate=sample_rate)

完全なソース コードは次のようになります。

コード例:

import IPython.display as ipd
import matplotlib.pyplot as plt
import numpy
import math

sample_rate = 22050


def addsyn(frequency, duration, amplist):
    i = 1
    t = numpy.linspace(0, duration, math.ceil(sample_rate * duration))
    output = numpy.zeros(t.size)

    for amp in amplist:
        x = numpy.multiply(makesine(frequency * i, duration), amp)
        output = output + x
        i += 1

    if numpy.max(output) > abs(numpy.min(output)):
        output = output / numpy.max(output)
    else:
        output = output / -numpy.min(output)
    return output


t = numpy.linspace(0, 1, sample_rate)
sinewave = addsyn(440, 1, [1])
plt.plot(t, sinewave)
plt.xlim(0, 0.005)
ipd.Audio(sinewave, rate=sample_rate)

出力:

python オーディオ合成 - 基本的な正弦波のharmonic.wav

python オーディオ合成 - 基本的な正弦波ハーモニック グラフ

これで、addsyn() 関数のさまざまな値をいじって、さまざまな出力を得ることができます。 以下の方形波を作成する別の例を参照してください。

コード例:

import IPython.display as ipd
import matplotlib.pyplot as plt
import numpy
import math

sample_rate = 22050


def addsyn(frequency, duration, amplist):
    i = 1
    t = numpy.linspace(0, duration, math.ceil(sample_rate * duration))
    output = numpy.zeros(t.size)

    for amp in amplist:
        x = numpy.multiply(makesine(frequency * i, duration), amp)
        output = output + x
        i += 1

    if numpy.max(output) > abs(numpy.min(output)):
        output = output / numpy.max(output)
    else:
        output = output / -numpy.min(output)
    return output


t = numpy.linspace(0, 1, sample_rate)
square_wave = addsyn(440, 1, [1, 0, 0.349, 0, 0.214, 0, 0.156, 0, 0.121, 0])
plt.plot(t, square_wave)
plt.xlim(0, 0.005)
ipd.Audio(square_wave, rate=sample_rate)

出力:

python オーディオ合成 - 基本的な正弦波の square.wav

python オーディオ合成 - 基本的な正弦波の正方形グラフ

pyaudio を使用して Python で音声合成を生成する

ここでは、Python でオーディオを録音する Python モジュール pyaudio を使用します。

  • まず、必要なライブラリをインポートします。数学関数を実行するための math と、波を生成するための pyaudio です。
    import math  # import needed modules
    import pyaudio  # sudo apt-get install python-pyaudio
    
  • pyaudio を初期化します。
    PyAudio = pyaudio.PyAudio
    
  • 変数を初期化します。
    bit_rate = 16000
    frequency = 500
    length = 1
    
    bit_rate = max(bit_rate, frequency + 100)
    number_of_frames = int(bit_rate * length)
    rest_frames = number_of_frames % bit_rate
    wave_data = ""
    

    ここでは、1 秒あたりのフレーム数を示す bit_rate16000 で初期化しました。 frequency500 Hz に設定され、1 秒あたりの波数 (261.63=C4-note) を表し、length1 で初期化されます。

    その後、max() 関数を使用して bit_ratefrequency+100 から最大値を見つけ、その最大値を bit_rate に割り当てます。 次に、bit_ratelength を乗算し、int() 関数を使用して int 型に変換し、number_of_frames に割り当てます。

    次に、モジュロ演算子 (%) を使用して number_of_framesbit_rate で割り、余りを rest_frames に割り当てます。 最後に、空の文字列で wave_data を初期化します。

  • 波を生成します。
    for x in range(number_of_frames):
        wave_data = wave_data + chr(
            int(math.sin(x / ((bit_rate / frequency) / math.pi)) * 127 + 128)
        )
    
    for x in range(rest_frames):
        wave_data = wave_data + chr(128)
    

    ここでは、波を生成するために number_of_frames まで反復する 2つの for ループを使用しました。

  • レコードオーディオ。
    p = PyAudio()
    stream = p.open(
        format=p.get_format_from_width(1), channels=1, rate=bit_rate, output=True
    )
    stream.write(wave_data)
    stream.stop_stream()
    stream.close()
    p.terminate()
    

    ここでは、PyAudio のインスタンスを作成し、p に参照を保存し、その参照を使用して open() メソッドを使用してストリームを開き、オーディオを録音します。 次に、wave_data を書き、ストリームを停止し、閉じました。 最後に、PyAudio インスタンス (p) も終了します。

    open()write()stop_stream()、および close() こちら について詳しく読むことができます。

  • これが完全なソースコードです。
    import math
    import pyaudio
    
    PyAudio = pyaudio.PyAudio
    
    bit_rate = 16000
    frequency = 500
    length = 1
    
    bit_rate = max(bit_rate, frequency + 100)
    number_of_frames = int(bit_rate * length)
    rest_frames = number_of_frames % bit_rate
    wave_data = ""
    
    for x in range(number_of_frames):
        wave_data = wave_data + chr(
            int(math.sin(x / ((bit_rate / frequency) / math.pi)) * 127 + 128)
        )
    
    for x in range(rest_frames):
        wave_data = wave_data + chr(128)
    
    p = PyAudio()
    stream = p.open(
        format=p.get_format_from_width(1), channels=1, rate=bit_rate, output=True
    )
    
    stream.write(wave_data)
    stream.stop_stream()
    stream.close()
    p.terminate()
    

    上記のコードを実行すると、波が聞こえます。 このウェーブを .wav ファイルに保存していないことに注意してください。

    .wav ファイルへの保存については、こちら をお読みください。