
Pythonで音を奏でよう③〜ランダム関数を使って作曲してみた〜
こんにちは。学びの探求者です。
前回は、Pythonでキラキラ星を転調してみました。
今回は、Pythonの関数を使って作曲してみようと思います。
基本の音階(スケール)
今回は、ハ長調をベースに作っていきます。
まず、こちらが基本の音階(スケール)です。

このスケールを元に、メロディを作っていきます。
作曲してみよう
1.完全なランダムで音を並べた場合
まず、適当に音を並べるだけの方法を試してみました。
コード
import random
# 🎼 Cメジャースケール(ハ長調)のMIDIノート番号
c_major_scale = [60, 62, 64, 65, 67, 69, 71, 72] # C, D, E, F, G, A, B, C
# 🎼 MIDIノート番号 → 音名マッピング(Cメジャースケール)
note_names = {60: "C", 62: "D", 64: "E", 65: "F", 67: "G", 69: "A", 71: "B", 72: "C"}
# 🎼 完全ランダムなメロディ生成(8小節 x 4拍)
random_melody = [
[random.choice(c_major_scale) for _ in range(4)]
for _ in range(8)
]
# 🎵 出力: ランダムなメロディ(音名表記)
for i, measure in enumerate(random_melody):
measure_text = " | ".join(f"{note_names[note]}{(note - 60) // 12 + 4}" for note in measure)
print(f"{i+1}小節目: {measure_text} |")
結果
1小節目: B4 | B4 | B4 | D4 |
2小節目: D4 | F4 | D4 | G4 |
3小節目: D4 | D4 | D4 | D4 |
4小節目: B4 | G4 | B4 | F4 |
5小節目: F4 | A4 | D4 | A4 |
6小節目: C4 | E4 | A4 | D4 |
7小節目: C5 | B4 | B4 | B4 |
8小節目: C4 | A4 | C4 | D4 |
出来上がった音楽がこちらです。

このように、ランダムな音の並びでは音楽らしさはまったく感じられません🥺
まるでランダムに押した鍵盤を鳴らしたようなカオスな音になってしまいました。
2.規則を取り入れたランダム作曲
そこで、音楽的な規則を取り入れて、もっと自然なメロディを作ります。
メロディ(右手)のルール
スケール内の音(C, D, E, F, G, A, B, C)のみを選択
次の音は現在の音から近い範囲(±5度以内)に制限
リズム(8分音符 or 4分音符)を考慮しながら構成
休符を適度に入れてリズムを作る(15%の確率)
伴奏(左手)のルール
メロディに完全にランダムな伴奏をつけると不協和音になりやすい
そのため 定番のコード進行(C → G → Am → F)を採用
4拍ごとに安定したコードを入れることで、メロディを支える
コード
import random
# 🎵 **Cメジャースケール(C4 〜 B4)**
midi_notes = [60, 62, 64, 65, 67, 69, 71] # C4, D4, E4, F4, G4, A4, B4
# 🎼 **4/4拍子, 8小節**
num_measures = 8
melody = []
for _ in range(num_measures):
measure = []
beat = 0
while beat < 4: # 1小節は4拍
note_length = random.choice([0.5, 1.0]) # 8分 or 4分音符
# 🎯 **次の音をスケール内で選択し、前の音と近いものにする**
if measure and isinstance(measure[-1][0], int): # 直前が休符でない場合
last_note = measure[-1][0]
valid_notes = [n for n in midi_notes if abs(n - last_note) <= 5]
next_note = random.choice(valid_notes) if valid_notes else random.choice(midi_notes)
else:
next_note = random.choice(midi_notes)
# 🎵 **休符をランダムに入れる(15%の確率)**
if random.random() < 0.15 and beat + note_length <= 4:
measure.append(("Rest", note_length))
else:
measure.append((next_note, note_length))
beat += note_length
# 🎯 **小節の拍数が4拍より多い場合、最後の音を調整**
total_beats = sum(n[1] for n in measure)
if total_beats > 4:
excess = total_beats - 4
measure[-1] = (measure[-1][0], measure[-1][1] - excess) # 超えた分を削減
# 🎯 **小節の拍数が4拍より少ない場合、最後の音を引き伸ばす**
total_beats = sum(n[1] for n in measure) # 再計算
if total_beats < 4:
measure[-1] = (measure[-1][0], measure[-1][1] + (4 - total_beats))
melody.append(measure)
# 🎵 **伴奏(左手):固定のコード進行**
chord_progression = [
("C", [48, 52, 55]), # Cメジャー (C3, E3, G3)
("G", [43, 47, 50]), # Gメジャー (G2, B2, D3)
("Am", [45, 48, 52]), # Aマイナー (A2, C3, E3)
("F", [41, 45, 48]), # Fメジャー (F2, A2, C3)
("C", [48, 52, 55]), # Cメジャー
("G", [43, 47, 50]), # Gメジャー
("Am", [45, 48, 52]), # Aマイナー
("F", [41, 45, 48]) # Fメジャー
]
# 🎵 **MIDI番号を音名に変換**
def midi_to_note_name(midi_note):
note_names = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
return f"{note_names[midi_note % 12]}{(midi_note // 12) - 1}"
# 🎼 **結果を表示**
for i, (measure, (chord_name, chord_notes)) in enumerate(zip(melody, chord_progression)):
melody_text = " | ".join(
f"Rest ({note[1]}拍)" if note[0] == "Rest" else f"{midi_to_note_name(note[0])} ({note[1]}拍)"
for note in measure
)
chord_text = f"🎵 {chord_name} ({', '.join([midi_to_note_name(n) for n in chord_notes])})"
print(f"{i+1}小節目: {melody_text} {chord_text}")
結果
1小節目: E4 (0.5拍) | C4 (0.5拍) | E4 (0.5拍) | G4 (1.0拍) | D4 (1.0拍) | E4 (0.5拍) 🎵 C (C3, E3, G3)
2小節目: D4 (1.0拍) | F4 (0.5拍) | C4 (0.5拍) | D4 (1.0拍) | G4 (1.0拍) 🎵 G (G2, B2, D3)
3小節目: C4 (0.5拍) | D4 (0.5拍) | D4 (1.0拍) | C4 (1.0拍) | C4 (1.0拍) 🎵 Am (A2, C3, E3)
4小節目: F4 (1.0拍) | D4 (0.5拍) | C4 (1.0拍) | Rest (0.5拍) | B4 (0.5拍) | Rest (0.5拍) 🎵 F (F2, A2, C3)
5小節目: C4 (0.5拍) | F4 (0.5拍) | A4 (0.5拍) | F4 (0.5拍) | D4 (1.0拍) | Rest (1.0拍) 🎵 C (C3, E3, G3)
6小節目: G4 (0.5拍) | B4 (0.5拍) | G4 (0.5拍) | G4 (0.5拍) | G4 (1.0拍) | B4 (1.0拍) 🎵 G (G2, B2, D3)
7小節目: G4 (0.5拍) | F4 (0.5拍) | G4 (1.0拍) | A4 (0.5拍) | E4 (1.0拍) | A4 (0.5拍) 🎵 Am (A2, C3, E3)
8小節目: Rest (0.5拍) | E4 (1.0拍) | F4 (0.5拍) | E4 (1.0拍) | A4 (1.0拍) 🎵 F (F2, A2, C3)
出来上がった音楽がこちらです。

完全ランダムよりは、音楽らしいメロディになったと思いませんか?😁
まとめ
いかがでしたか?
今回、 ただランダムに音を並べるだけでは音楽らしくならないことがわかりました。
しかし、 前の音との関係・休符・コード進行などの規則を加えると、しっかりと「ハ長調の音楽」に聴こえるようになりました。
このように、 音楽の規則も数学的にプログラミングすることが可能 であり、実際に AIの作曲技術にも活用 されています。
次回は、 数学の確率モデル「マルコフ連鎖」 を使い、さらに 自然なメロディを生成する方法 に挑戦してみたいと思います。
「AIがどのようにメロディを学習して作るのか?」を体験してみたいです!
お楽しみに。
最後まで読んでくださりありがとうございます。
また少しでも読んでみたいな、ぜひ「いいね」や「フォロー」で応援してくれると嬉しいです!💡✨
いいなと思ったら応援しよう!
