音で学ぶPython：MIDI・SMF・波形生成・WAV/MP3再生の完全チュートリアル

##  はじめに
本記事ではGoogle Colab上で実行可能で、以下の機能を順番に学ぶことができます：

MIDI出力・入力（Mido）

SMFファイル（作成と再生）

サイン波・矩形波・のこぎり波の生成

複数波の合成

WAVファイルとして保存・再生

MP3変換と再生（Colab再生対応）

##  Pythonコード


```python
# --- 🔧 必要ライブラリのインストール（Google Colab用） ---
!pip install mido pydub numpy scipy
!apt-get install -y ffmpeg timidity

# --- 📚 ライブラリの読み込み ---
import numpy as np
import mido
from mido import MidiFile, MidiTrack, Message
from scipy.io.wavfile import write
from scipy.signal import square, sawtooth
from pydub import AudioSegment
from IPython.display import Audio, display

# --- MidoによるMIDI出力と入力 ---
def basic_mido_output(note=60, velocity=64, duration=0.5):
    print(f"MIDI Note On: {note}, velocity={velocity}")
    print(f"MIDI Note Off: {note}, after {duration} sec")

def advanced_mido_output(notes):
    for note in notes:
        print(f"[ON] Note: {note}")
        print(f"[OFF] Note: {note}")

def read_midi_input(filename):
    mid = MidiFile(filename)
    for i, track in enumerate(mid.tracks):
        print(f"Track {i}: {track.name}")
        for msg in track:
            print(msg)

# --- SMFの作成と再生 ---
def create_smf(filename="output.mid"):
    mid = MidiFile()
    track = MidiTrack()
    mid.tracks.append(track)
    notes = [60, 62, 64, 65, 67, 69, 71, 72]
    for note in notes:
        track.append(Message('note_on', note=note, velocity=64, time=200))
        track.append(Message('note_off', note=note, velocity=64, time=200))
    mid.save(filename)
    print(f"MIDIファイルを保存しました: {filename}")

def play_smf(filename="output.mid"):
    print(f"{filename} を再生します（Colab: timidity使用）")
    !timidity {filename} -Ow -o temp.wav
    display(Audio("temp.wav"))

# --- 波形の生成と合成 ---
def generate_waveform(wave_type="sine", freq=440, duration=1.0, samplerate=44100):
    t = np.linspace(0, duration, int(samplerate * duration), endpoint=False)
    if wave_type == "sine":
        return 0.5 * np.sin(2 * np.pi * freq * t)
    elif wave_type == "square":
        return 0.5 * square(2 * np.pi * freq * t)
    elif wave_type == "sawtooth":
        return 0.5 * sawtooth(2 * np.pi * freq * t)
    else:
        raise ValueError("Unsupported waveform type.")

def synthesize_waveform(freqs=[440, 660], duration=2.0):
    t = np.linspace(0, duration, int(44100 * duration), endpoint=False)
    wave = sum(np.sin(2 * np.pi * f * t) for f in freqs)
    return 0.5 * wave / len(freqs)

# --- WAVファイル保存と再生 ---
def save_to_wav(filename, waveform, samplerate=44100):
    scaled = np.int16(waveform / np.max(np.abs(waveform)) * 32767)
    write(filename, samplerate, scaled)
    print(f"WAVファイルを保存: {filename}")

def play_wav_colab(filename):
    print(f"{filename} を再生します")
    display(Audio(filename))

# --- MP3変換と再生 ---
def convert_wav_to_mp3(wav_file, mp3_file):
    sound = AudioSegment.from_wav(wav_file)
    sound.export(mp3_file, format="mp3")
    print(f"MP3に変換完了: {mp3_file}")
    return mp3_file

# --- デモ実行 ---
print("MidoによるMIDI出力")
basic_mido_output()
advanced_mido_output([60, 64, 67])

print("SMFファイルの作成と再生")
create_smf("demo_output.mid")
play_smf("demo_output.mid")
read_midi_input("demo_output.mid")

print("波形の生成と合成")
sine_wave = generate_waveform("sine", 440, 2)
combined_wave = synthesize_waveform([440, 660])

print("WAVファイルとして保存・再生")
save_to_wav("sine.wav", sine_wave)
play_wav_colab("sine.wav")

print("MP3変換と再生")
convert_wav_to_mp3("sine.wav", "sine.mp3")
play_wav_colab("sine.mp3")


```
結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046871/e6ba500f-1d9b-468c-b6c2-c3abea755cb7.png)