"BOKU"のITな日常

62歳・文系システムエンジニアの”BOKU”は日々勉強を楽しんでます

windows10+Python3.7で「pyaudio」をインストールして軽く使ってみる

pyaudioで、ちょっと音を出して遊ぼうと思っただけなのに、Windows10+Python3.7だと、インストールにちょっと苦労しました・・という話題です。

f:id:arakan_no_boku:20200707230113p:plain

 

インストールでつまづきました

 

久々にギターの練習を再開したら、pythonでも音を出して遊びたくなりました。

pythonで音を扱うといえば「pyaudio」です。

早速「pip install pyaudio」でインストールしようとしました。

ところが・・。

ERROR: Failed building wheel for pyaudio

おやおや・・です。

どうやら、VisualStudioのBuildToolでコンパイルエラーがでています。

エラーの原因は。

fatal error C1083: include ファイルを開けません。'portaudio.h':No such file or directory 

なるほど・・ですね。

portaudio.hというのは、pythonパッケージにはなくて、完全に独立したCライブラリのようです。

portaudio.com

Linuxなら、pipのオプションでなんとかなるらしいです。

Windowsでも、Python3.6以下ならいけるという情報もあります。

でも、それだけのために、Pythonのバージョンを落とすのも、Linuxを使うのもめんどくさいので、別の方法を試すことにしました。

 

ビルド済のWindowsバイナリを使う

 

ありがたいことに、こちらでPyAudioWindowsバイナリを提供いただいています。

https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio

あくまで「Unofficial Windows Binaries」ですけど、自分が個人で使う分には全く問題ありません。

ここから、windowsの64ビット版+Python3.7なので。

PyAudio‑0.2.11‑cp37‑cp37m‑win_amd64.whl

をダウンロードします。

そしてダウンロードしたフォルダをカレントフォルダにして以下を実行します。

pip install PyAudio-0.2.11-cp37-cp37m-win_amd64.whl

すると、あっさりインストールできます。

Processing c:\users\tadas\downloads\pyaudio-0.2.11-cp37-cp37m-win_amd64.whl
Installing collected packages: PyAudio
Successfully installed PyAudio-0.2.11

 ありがたいですねえ。

 

試すために、まず12音階の周波数を求めておこう

 

ちゃんと使えるかどうかの確認を兼ねて、軽く音階の音を出してみます。

PyAudioで音階を表現するには、周波数を求める必要があります。

A(ラ)の周波数が440Hzとして、これに2の十二乗根を掛け合わせていけば、半音ずつずらした音階の周波数が計算できます。

ループを回して、ちょうどA(ラ)にあたるところで、2の0乗・・つまり1になるようにすればいいわけです。

プログラムにすると、こんな感じですかね。

a_hz = 440
names = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
res = []
for n in range(0, 13):
    hz = a_hz * 2 ** ((n - 9) / 12)
    name = names[n % 12]
    print(name, ";", hz)

これを実行すると。 

C ; 261.6255653005986
C# ; 277.1826309768721
D ; 293.6647679174076
D# ; 311.1269837220809
E ; 329.6275569128699
F ; 349.2282314330039
F# ; 369.9944227116344
G ; 391.99543598174927
G# ; 415.3046975799451
A ; 440.0
A# ; 466.1637615180899
B ; 493.8833012561241
C ; 523.2511306011972

 こんな感じになります。

いけてるっぽいので、次にいきます。

 

PyAudioでドレミを鳴らしてみる

 

音をだしてみます。

ドレミファソラシド・・にしてみます。

まずは、クラス化して、使いやすくしてみました。

Audioクラスです。

import pyaudio as pa
import numpy as np


class Audio:

    def __init__(self, bpm=30):
        self.audio = pa.PyAudio()
        self.a_hz = 440
        self.smpl_rate = 44100
        self.bpm = bpm
        self.code_names = (
            "C",
            "C#",
            "D",
            "D#",
            "E",
            "F",
            "F#",
            "G",
            "G#",
            "A",
            "A#",
            "B")
        self.stream = self.audio.open(
            format=pa.paFloat32,
            channels=1,
            rate=self.smpl_rate,
            frames_per_buffer=1024,
            output=True)

    def __tone(self, hz, note, gain=1.0):
        slen = int(note * self.smpl_rate)
        t = float(hz) * np.pi * 2 / self.smpl_rate
        return np.sin(np.arange(slen) * t) * gain

    # 音符
    def make_note(self):
        self.note1 = 60 / (self.bpm * 4)
        notes = []
        notes.append(self.note1)
        notes.append(self.note1 / 2)
        notes.append(self.note1 / 4)
        notes.append(self.note1 / 8)
        return notes

    # 音階
    def make_scale(self):
        res = {}
        octave = -1
        for n in range(0, 13):
            hz = self.a_hz * 2 ** ((n - 9) / 12)
            if (n % 12) == 0:
                octave += 1
            name = self.code_names[n % 12] + str(octave)
            res[name] = hz
        return res

    def play(self, hz, note, gain=1.0):
        self.stream.write(self.__tone(hz, note, gain).astype(np.float32).tostring())

補足しておきます。 

クラスを初期化するときのパラメータ「bmp」は、音の長さです。

Beat Per Minuteなので、1分間あたりのビート数です。

デフォルトは30で、かなりゆっくりにしてます。

数字を大きくすると速くなります。

サンプリングレート( self.smpl_rate)は44100にしてます。

これは、1秒間で44100個のデータを再生デバイスに送る・・という意味で、CDのサンプリングレートにあたります。

とりあえず。

  • 音階(スケール)の辞書を作成(make_scale)
  • 音符のリストを生成(make?note)

して、それを使って「play」する・・という感じです。

音階は、C、Dなどに、オクターブの0、1をつける形で「C0」「C1」のように名前をつけて辞書化します。

音符は

  • 0: 全音
  • 1:二分音符
  • 2:四分音符
  • 3:八分音符

 の4種類を用意します。

 

Audioクラスを使ってみます

 

使い方のサンプルです。

a = Audio()
scales = a.make_scale()
notes = a.make_note()
a.play(scales["C0"], notes[0])
a.play(scales["D0"], notes[0])
a.play(scales["E0"], notes[0])
a.play(scales["F0"], notes[0])
a.play(scales["G0"], notes[0])
a.play(scales["A0"], notes[0])
a.play(scales["B0"], notes[0])
a.play(scales["C1"], notes[0])

ちゃんとインストールできていれば、これで全音符で「ド・レ・ミ・ファ・ソ・ラ・シ・ド」となるはずです。

とりあえず、鳴ればOK。

今回はこんなところです。

ではでは。