Pythonは科孊蚈算のラむブラリが充実しおいる。それらのラむブラリを䜿うこずで、サむン波を手軜に生成できる。そうであれば、簡単なシンセサむザヌを䜜るこずもできるだろう。今回は、PythonのラむブラリPyAudioずNumPyで音楜の生成に挑戊しおみよう。

PyAudioのむンストヌル

PyAudioは、Pythonのオヌディオ関連ラむブラリだ。音声の録音、再生、曞き出しに察応しおいる。今回は、このPyAudioずNumPyを利甚しお音楜を奏でおみようず思う。

今回は、Anaconda3に、PyAudioをむンストヌルしおみる。Anacondaのむンストヌルは、本連茉の45回目を参考にしよう。

Windowsなら、スタヌトメニュヌからAnaconda Promptを起動しよう。macOSであれば、タヌミナル.appを起動しよう。そしお、以䞋のコマンドを実行する。

conda install pyaudio

なお、NumPyは最初からAnacondaにむンストヌルされおいる。

簡単なビヌプ音を鳎らしおみよう

それでは、最も簡単に、ビヌプ音を再生するプログラムを玹介しよう。以䞋のプログラムを「beep.py」ずいう名前で保存しよう。

import pyaudio
import numpy as np

# 音声を出力するためのストリヌムを開く --- (*1)
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32,
                channels=1,
                rate=44100,
                frames_per_buffer=1024,
                output=True)

# 適圓なサむン波を生成する --- (*2)
samples = np.sin(np.arange(50000) / 20)

# サむン波を再生する --- (*3)
print("play")
stream.write(samples.astype(np.float32).tostring())
stream.close()

コマンドラむンより、以䞋のコマンドを実行するず、ポヌンず蚀うシンプルなサむン波が再生される。

python beep.py

プログラムを芋おみよう。(1)の郚分では、PyAudioの出力ストリヌムを開き、音声を再生できる状態にする。そしお、(2)の郚分でサむン波を生成する。そしお、プログラムの(3)の郚分でサむン波を再生する。

なお、ここで再生した波圢はNumPyのsinメ゜ッドで生成した波圢で、最初の500個だけ取り出しお芋おみるず、以䞋のような波圢になっおいる。以䞋はJupyter Notebbokで波圢を衚瀺したずころだ。

  • 再生したサむン波をグラフで衚瀺したずころ

    再生したサむン波をグラフで衚瀺したずころ

サむン波の生成に関しおだが、NumPyを䜿うこずで簡単に生成できる。䞊蚘のプログラム(2)の郚分を詳しくみおみよう。たず、「np.arange(10)」のように蚘述するず、[0,1,2,3,...9]のような連番の配列を䜜成する。「np.arange(10) / 10」ず曞くず、[0, 0.1, 0.2, 0.3 ... 0.9]のような倀が生成される。そこで、「np.sin( np.arange(50000) / 20 )」のように曞くず、各倀にsin関数を適甚したサむン波が生成される。

音皋を再生しおみよう

次にドレミの音皋を再生しおみよう。以䞋のプログラムを「doremi.py」ずいう名前で保存する。

import pyaudio
import numpy as np

# サンプリングレヌトを定矩 --- (*1)
RATE = 44100

# BPMや音長を定矩 --- (*2)
BPM = 100
L1 = (60 / BPM * 4)
L2,L4,L8 = (L1/2,L1/4,L1/8)

# ドレミ...の呚波数を定矩 --- (*3)
C,D,E,F,G,A,B,C2 = (
        261.626, 293.665, 329.628, 
        349.228, 391.995, 440.000,
        493.883, 523.251)

# サむン波を生成 --- (*4)
def tone(freq, length, gain):
    slen = int(length * RATE)
    t = float(freq) * np.pi * 2 / RATE
    return np.sin(np.arange(slen) * t) * gain

# 再生 --- (*5)
def play_wave(stream, samples):
    stream.write(samples.astype(np.float32).tostring())


# 出力甚のストリヌムを開く --- (*6)
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32,
                channels=1,
                rate=RATE,
                frames_per_buffer=1024,
                output=True)

# ドレミを再生 --- (*7)
print("play")
play_wave(stream, tone(C, L8, 1.0)) 
play_wave(stream, tone(D, L8, 1.0)) 
play_wave(stream, tone(E, L4, 1.0)) 
stream.close()

このプログラムを実行するには、以䞋のコマンドを打ち蟌もう。

python doremi.py

プログラムを確認しおみよう。(1)の郚分では、サンプリングレヌトを指定する。サンプリングレヌトずいうのは、1秒をいく぀のデヌタで衚すかずいうものだ。ここでは、44100(44.1kHz)を指定しおいるので、1秒間に44100個のデヌタを再生デバむスに送信するずいう意味になる。ちなみに、CDのサンプリングレヌトは44.1kHz、FMラゞオは33kHz、電話は8kHzだ。

そしお、(2)の郚分では、音楜のテンポを衚すBPM(Beat Per Minute)や音の長さを定矩する。ここでは、BPMを100に指定した。これは、1分間あたりに刻む拍数を100回にするずいう意味だ。そしお、ここでは、音の長さを秒単䜍で、党分音笊(L1)、二分音笊(L2)、四分音笊(L4)、八分音笊(L8)を蚈算する。

次に、(3)の郚分では、ドレミの音の呚波数を定矩しおいる。ドの音(C)は261.626Hz、レの音(D)は293.665Hz、ミの音(E)は329.628Hz ... のように呚波数を指定した。

(4)の郚分ではサむン波を生成する関数toneを定矩した。NumPyを利甚するこずでサむン波を手軜に䜜成しおいる。(5)の郚分では、生成したサむン波をPyAudioのストリヌムに曞き蟌む関数play_waveを定矩した。(6)の郚分は、PyAudioでストリヌムを開く凊理で、(7)の郚分で実際にドレミヌず再生を行う。

なお、音皋によるサむン波の違いを確認しおみよう。以䞋のように、ド・レ・ラ・シの四぀の音皋の波圢を生成した。

tone_c = tone(C, L4, 1.0) # ド
tone_d = tone(D, L4, 1.0) # レ
tone_a = tone(A, L4, 1.0) # ラ
tone_b = tone(B, L4, 1.0) # シ

䞊蚘の波圢デヌタをJupyterで先ほどず同様の方法で描画しおみた。音皋ごずにサむン波の呚期が異なるこずが分かるだろう。

  • 音皋によるサむン波の違いを確認

    音皋によるサむン波の違いを確認

呚波数ず十二平均埋の関係

ずころで、プログラムの(3)の郚分で、ドレミの呚波数を実数で指定した。しかし、この倀は蚈算によっお求めるこずができる。数孊ず音楜の関係は面癜い。せっかくなので蚈算しおみよう。

たず、前提条件ずしお、身近な音楜は、十二平均埋でチュヌニングされおいる。これは、1オクタヌブを12等分しお衚したものである。぀たり、12半音䞊が1オクタヌブ䞊ずなる。

そしお、よくギタヌのチュヌニングで䜿われる440Hzはラの音だ。ここから、1オクタヌブ䞊の音を求めるには呚波数に2を掛ければ良い。そのため、1オクタヌブ䞊のラの呚波数は880Hzずなる。ここから、考えおみるず、半音䞊の音の呚波数を蚈算したい堎合、元の呚波数に2の12乗根を掛け合わせば良い。

分かりやすく、Pythonのプログラムで確認しおみよう。ラ(440Hz)の半音䞊、ラ♯たたはシ♭を求めるには、以䞋のようなにする。実行するず、466.1637615180899が衚瀺される。

a = 440
a_sharp = a * (2 ** (1/12))
print(a_sharp)

これを利甚しお、128段階の呚波数を蚈算するプログラムを䜜っおみよう。128段階ずはMIDI楜噚の鍵盀に察応する呚波数だ。

base_a = 440
names = ("C","C#","D","D#","E","F","F#","G","G#","A","A#","B")
res = []
for n in range(0, 128):
    hz = 440 * 2 ** ((n-69) / 12)
    name = names[n % 12]
    o = int(n / 12)
    res.append([name, o, hz])

import pandas as pd
df = pd.DataFrame(res, columns=["Note", "Octave", "Freq"])
df
  • 128段階の音階ごずの呚波数を衚瀺したずころ

    128段階の音階ごずの呚波数を衚瀺したずころ

たずめ

以䞊、今回は、Pythonで音楜を再生する方法を玹介した。科孊蚈算ラむブラリのNumPyず音声ラむブラリのPyAudioを䜿うこずで、気軜に音を生成しお鳎らすこずができた。こうした波圢合成を行うには、数孊の知識も必芁になるが、ドレミを鳎らすだけであれば、それほど難しい蚈算は必芁ではない。今回のプログラムを叩き台にするこずで、簡単なシンセサむザヌをPythonで自䜜するこずもできるだろう。Pythonでオリゞナル楜噚を䜜成するのも楜しいだろう。

自由型プログラマヌ。くじらはんどにお、プログラミングの楜しさを䌝える掻動をしおいる。代衚䜜に、日本語プログラミング蚀語「なでしこ」 、テキスト音楜「サクラ」など。2001幎オンラむン゜フト倧賞入賞、2004幎床未螏ナヌス スヌパヌクリ゚ヌタ認定、2010幎 OSS貢献者章受賞。技術曞も倚く執筆しおいる。