'20/06/13更新:音が多少ずれてたのを修正しました。
ライブラリpyaudioのインストールは下記のようにcondaで出来ます。
conda install pyaudio
音は波(三角関数sin)です。音階は周波数の違いで表現できます。そのため、楽譜に沿って、ドレミファソラシドの音符を順番に指定すれば、曲を演奏できます。4分音符や8分音符といった音の長さも指定します。ゲイン(音の強さ)は曲風が変わります。
下図は「ねこふんじゃった」の音(波)をプロットしたグラフです。正弦波でない波は、2つの正弦波を足した和音です。
■本プログラム
#!/usr/bin/python3 # -*- coding: utf-8 -*- import sys import pyaudio import numpy as np import wave import struct import glob import re #import matplotlib #matplotlib.use('Agg') import matplotlib.pyplot as plt import datetime now = datetime.datetime.now() now = now.strftime("%y%m%d") # サイン波を生成する関数 def tone(freq, length, gain): # 引数:(周波数, 長さ, 振幅) slen = int(length * RATE) # 基本周波数 if not isinstance(freq, list): # freqの型がリストでない場合 t = float(freq) * np.pi * 2 / RATE sin_curve = np.sin(np.arange(slen) * t) * gain else: # freqがリストの場合の処理。和音 amp = float(gain) / len(freq) sin_curve = 0 for f in freq: t = float(f) * np.pi * 2 / RATE sin_curve += np.sin(np.arange(slen) * t) * amp plt.figure(num=1, figsize=(10,6)) plt.plot(sin_curve[0:500], label=freq) plt.legend(bbox_to_anchor = (1.05, 1.0)) plt.tick_params(labelsize=16) plt.tight_layout() plt.grid() plt.savefig(now + '_sin_curve.png') #plt.close() return sin_curve # 音声を再生する関数 def play_wave(stream, sin_curve): stream.write(sin_curve.astype(np.float32).tostring()) # 楽曲をリストで作成 def create_music(): sample_list = [] # 音階, 音符, 強さ sample_list.append([Dsharp4, L8, GAIN]) #ね sample_list.append([Csharp4, L8, GAIN]) #こ sample_list.append([Fsharp3, L2, GAIN]) #ふん sample_list.append([[Asharp3, Fsharp4], L4, GAIN]) #じゃ # 和音 sample_list.append([[Asharp3, Fsharp4], L4, GAIN]) #った sample_list.append([Dsharp4, L8, GAIN]) #ね sample_list.append([Csharp4, L8, GAIN]) #こ sample_list.append([Fsharp3, L2, GAIN]) #ふん sample_list.append([[Asharp3, Fsharp4], L4, GAIN]) #じゃ sample_list.append([[Asharp3, Fsharp4], L4, GAIN]) #った sample_list.append([Dsharp4, L8, GAIN]) #ね sample_list.append([Csharp4, L8, GAIN]) #こ sample_list.append([Fsharp3, L2, GAIN]) #ふんー sample_list.append([[Asharp3, Fsharp4], L4, GAIN]) #じゃー sample_list.append([Dsharp3, L2, GAIN]) #ふんー sample_list.append([[Asharp3, Fsharp4], L4, GAIN]) #じゃー sample_list.append([Csharp3, L2, GAIN]) #ふん sample_list.append([[B3, F4], L4, GAIN]) #じゃ sample_list.append([[B3, F4], L4, GAIN]) #った return sample_list # カレントディレクトリに存在してるwavファイルを読み込んで再生する関数 def read_wav(sample_list): p=pyaudio.PyAudio() stream = p.open(format = pyaudio.paInt16, channels = 1, rate = RATE, frames_per_buffer = 1024, input = True, output = True) # inputとoutputを同時True wav_list = glob.glob('./*wav') wav_list = sorted(wav_list, key=lambda x:int((re.search(r"[0-9]+", x)).group(0))) for wavfile in wav_list: print(wavfile) wr = wave.open(wavfile, "rb") input = wr.readframes(wr.getnframes()) output = stream.write(input) stream.close() # メイン関数 def main(): ### 出力用のストリームを開く p = pyaudio.PyAudio() stream = p.open(format=pyaudio.paFloat32, channels=2, rate=RATE, frames_per_buffer=1024, output=True) ### 音楽の再生とwavファイル出力 sample_list = create_music() binary_data_list = [] for i, sample in enumerate(sample_list): print(i, sample) # sin波の生成 sin_curve = tone(*sample) # 音波をcsvファイルに出力 np.savetxt(now + '_' + str(i) + '_sin_curve.csv', # 書き出すファイル名 sin_curve, # 書き出すnumpyアレイ形式のデータ delimiter=',', # カンマ区切り fmt='%.1f') # fは小数 # 音を再生 play_wave(stream, sin_curve) # wavファイルへ保存するために、バイナリデータへ変換する # sinカーブを-32768から32767の整数値へ変換(16bit pcm) sin_curve = [int(x * 32767.0) for x in sin_curve] # バイナリ化 binary_data = struct.pack("h" * len(sin_curve), *sin_curve) binary_data_list.append(binary_data) # バイナリデータをリストで追加 # リスト内の要素をバイト型へ変換 binary_data_list = list(map(bytes, binary_data_list)) # 全要素を結合 binary_data = b''.join(binary_data_list) #sin波をwavファイルで出力 w = wave.Wave_write(now + "_sine.wav") p = (1, 2, 44100, len(binary_data), 'NONE', 'not compressed') w.setparams(p) w.writeframes(binary_data) w.close() stream.close() ### カレントディレクトリに存在してるwavファイルを読み込んで再生する read_wav(sample_list) if __name__ == '__main__': # サンプリングレート RATE = 44100 # ゲイン GAIN = 1 # BPM(Beats Per Minute) BPM = 100 # 1分間あたりに刻む拍数を100回 # 音長 L1 = (60 / BPM * 4) # 音の長さを秒単位で、全分音符 L2, L4, L8 = (L1/2, L1/4, L1/8) # 2分音符(L2)、4分音符(L4)、8分音符(L8)を計算する # 周波数 # ド レ ミ ファ ソ ラ シ # C, D, E, F, G, A, B C3, Csharp3, D3, Dsharp3, E3, F3, Fsharp3, G3, Gsharp3, A3, Asharp3, B3 \ = (130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220.000, 233.082, 246.942) C4, Csharp4, D4, Dsharp4, E4, F4, Fsharp4, G4, Gsharp4, A4, Asharp4, B4 \ = (261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440.0, 466.164, 493.883) C5, Csharp5, D5, Dsharp5, E5, F5, Fsharp5, G5, Gsharp5, A5, Asharp5, B5 \ = (523.251, 554.365, 587.330, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880.000, 932.328, 987.767) main() print('finished')
●参考リンク
https://people.csail.mit.edu/hubert/pyaudio/docs/
以上
<広告>
リンク