Python で音を出す。5オクターブの「ド」の合成。

オクターブの異なるドレミの音を合成するとどうなるかやってみました。まずは「ド」から。130.813Hzから2093.005Hzまでの5つのサインカーブの「ド」を順番に出し、最後にそれらを合成した「ド」を出しています。wav形式のファイルは、別途mp3形式に変換しています。
【音が出ますので、音量にご留意ください。】

# sound-try-02.py    2023.06.30  by Kero
# "sounddevice" モジュールを使って音を出します。
# 数オクターブの「ド」を同時に出します。

import numpy as np
import sounddevice as sd
import matplotlib.pyplot as plt
import scipy # 音のファイルを作るため。
from scipy.io.wavfile import write
import time
pi = np.pi

# 波形をグラフ化しています。(蛇足)
fig = plt.figure(figsize=(8,4)) # グラフを左右2枚。
ax1 = fig.add_subplot(121) # 左のグラフは音の出だしの波形。
ax2 = fig.add_subplot(122) # 右のグラフは音の終端の波形。

# CDのサンプリングレート(44100Hz)に合わせます。1秒間音が出ます。
sh = np.linspace(0, 1, 44101) # 時間軸です。
sndall = [0]*44101 # 振幅を入れる配列を用意します。

do = [0]*5 # 5オクターブの「ド」の音を用意します。
do[0] = 130.813 # 各周波数です。
do[1] = 261.626
do[2] = 523.251
do[3] = 1046.502
do[4] = 2093.005
dodo = np.array([]) # 生成したドの音を順に入れる器です。

a = 1. # 音量パラメータです。ノイズ除去に使います。
ax1.set_xlim(0, 4/440) # 波形グラフはラ(440Hz)の音が4つ入るくらいに設定。
ax2.set_xlim(1-4/440, 1) # 音の終端のグラフ用です。
for doi in do:
    print(doi)
    snd = np.sin(2*pi*sh*doi) # 「ド」の音を生成。
    for a in range(0, 750): # 音の終端にノイズが入るので、音量を小さくして消去。
        snd[-a-1] = snd[-a-1] * a / 750

    sd.play(snd, 44100) # 各オクターブの「ド」の音を出力。
    time.sleep(2) # ある音と次の音の間隔を2秒に設定。
    dodo = np.append(dodo, snd)
    sndall = sndall + snd # 各「ド」の音を重ね合わせ。

print("all")
sd.play(sndall, 44100) # すべてのオクターブの「ド」の音を同時出力。
time.sleep(2)
dodo = np.append(dodo, sndall)

ax1.plot(sh, sndall) # 音の波形グラフ。0秒〜。
ax2.plot(sh, sndall) # 音の波形グラフ。〜1秒。

dodo = np.array(dodo)
# scipyはwav形式しか扱えないようです。
scipy.io.wavfile.write(filename='sound-try-02.wav', rate=44100, data=dodo)

plt.show()