0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

はじめに

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

MIDI出力・入力(Mido)

SMFファイル(作成と再生)

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

複数波の合成

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

MP3変換と再生(Colab再生対応)

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?