【その2】pythonでメロディーを作りたい

f:id:nuakam:20170929172616j:plain

準備編 【準備編】pythonでメロディーを作りたい - エンジニア戦記←前回
第2回 ここ
第3回 【その3】Pythonでメロディーを奏でたい - エンジニア戦記
第4回 【その4】Pythonでメロディーを奏でたい-モジュール化とwavファイル出力 - エンジニア戦記

目標

音を鳴らす

環境

  • python3
  • windows10
  • anaconda

概要

前回、環境を作成した。
とりあえず音をぶぃ~っと鳴らしたい。

音のプログラムはだいたい正弦波を作成し音声データとして流すのがセオリー。
言語に依らずやることは殆ど変わらない。


言語を絞って検索するなり、参考書を開いてみると大まかなプログラムは一緒。

ソース

import wave
import struct
import numpy as np
import pyaudio

from pylab import *


def createSinWave (A, f0, fs, length):
    """振幅A,基本周波数f0, サンプリング周波数fs,再生時間length秒の正弦波を作成して返す"""
    
    data = []
    for n in arange(length * fs):
        s = A * np.sin(2 * np.pi * f0 * n / fs) # 正弦波の計算
        
        # 振幅の範囲を-1~1に設定
        if s > 1.0: s = 1.0
        if s < -1.0: s = -1.0
        data.append(s)

    data = [int(x * 32767.0) for x in data]# [-32768, 32767]の整数値に変換

    data = struct.pack("h" * len(data), *data) # バイナリデータに変換


    return data

#再生用関数
def play(data, fs, bit):
    
    p = pyaudio.PyAudio()
    stream = p.open(format=pyaudio.paInt16,
            channels=1,
            rate=int(fs),
            output=True)

    chunk = 1024
    sp = 0
    buffer = data[sp:sp+chunk]
    while buffer != b'':
        stream.write(buffer)
        sp = sp + chunk
        buffer = data[sp:sp+chunk]

    stream.close()
    p.terminate()


if __name__ == "__main__" :
    freqList = [262, 294, 330, 349, 392, 440, 494, 523]# ドレミファの周波数[Hz]
    for f in freqList:
        data = createSinWave(1.0, f, 8000.0, 2.0)
        play(data, 8000, 16)

こちらのソースは参考ページのgithubのコード。
createSinWaveの中身は今のところ呪文だと思って大丈夫。



覚えておきたいところは

data = struct.pack("h" * len(data), *data)

でバイナリデータに変換しなきゃならないところ。
後々音声データをファイル化するときに、バイナリデータを使うことになる。



最後の行の

play(data, 8000, 16)

をforから外してdataを262や523といった周波数を決め打ちに変えると、その音がなる。