本日は、全内容を東京画廊の山本豊津代表に銀座東京画廊で公開説明した以外に6年間にわたり機密事項として封印してきた『音楽の楽譜を絵画に変換する物理的法則』を、封印を解いてついに公開しました。
公開理由は以下の通りです。
- 物理などの新理論や発見は特許を取れない。
- 6年間で、10枚以上のこの法則を利用した大画面のパステル画を制作しストックできたこと。
- ただ発見しましたでは、皆様に多くの場合結局信用してもらえなかったこと。
以上の理由により、今回、そのエビデンスを法則の全内容とともに公開いたしました!
この法則が真実かどうかは?以下のプログラムと、色んな音楽家、ミュージシャンの発言から確かめてください!
聴覚の芸術である「音楽」を、視覚の芸術である「絵画」へと変換することはできないのか?
その問いに対する芸術史上初の『できる』という解答がこの法則です。
今回私は、この理論を確認するためのPython言語プログラム作って実行し、見事に理論通りの結果が描画され、この法則の正しさが実証されました。
それでは、その法則の全貌を公開します!
楽譜を絵画にする4つの法則
① 音階は「光のスペクトル(虹色)」に一致する
ドレミファソラシドの7音階は、光の波長(色)と完全に連動しています。
ド(C / ハ)= 赤
レ(D / ニ)= オレンジ
ミ(E / ホ)= 黄色
ファ(F / ヘ)= 黄緑
ソ(G / ト)= 緑
ラ(A / イ)= 青
シ(B / ロ)= 紫
色は上に行くにしたがって高周波になるので、1オクターブごとに明るくなっていくと考えていいでしょう!
◆私はこの理論を完成させるまでは知らなかったのですが、実はここまでは1919年にメアリオンという人がほぼ同じものを提唱しています。が、そこからの理論構築が進まなかったのです。
② 音楽の主調音は色彩の主調色になる。画面を覆う主調色
ここからは、メアリオンや過去の研究者が未発見な理論となります。

調性音楽とは、最初の音がドで始まって、ドで終わるならハ長調。
ミで始まるならニ長調となります。
ドとミの間の音から始まるのはニ短調となります。
ドレミといった長音は『明るい音』として聴こえますし、長音の間にあるピアノでいえば黒鍵にあたる単音は暗い音に聴こえます。
この主調音は、だから、曲全体の調子、雰囲気を決めますね。明るい感じの曲か、暗い感じの曲か?
つまり、曲全体を支配している。
絵画では、この各音に当たる色彩が画面全体を支配する色となります。
だから、ハ長調を絵画に翻訳すると下の梅原龍三郎の『櫻島 赤』のように赤が画面の支配色となる。
一方逆に、『桜島 青』は、そうロ長調になります。
こう考えないと、音楽がなぜ、ハ長調やイ短調などの曲調によって、全体の雰囲気が決まるのかの説明もつかないですよね。
私のこの理論は、絵画の主調色の役割もばっちり説明していますよね?
非調性音楽は、シェーンベルグの12音階セリー音楽から始まっています。そうすると、短調は、以下の和音描画のプログラムを実施してもらえれば分かりますが、
赤と朱色、青と紫の『中間のくすんだ色』となります。
つまり純粋な色ではない。濁った中間色になると考えていい。
こうすると、悲しい、たそがれた絵になりますね。
ワシリー・カンディンスキー夫妻とシェーンベルグ夫妻が部屋で語らい中に、妻のニーナが「ピカソの作品(夢(赤い椅子に眠る女) 写真などは、12音階音楽を絵画で実現したものだ!」という逸話は至言で、この作品には画面を支配する基調色がないからです。
④ 音の高さと絵画との関係
メロディは、キャンバス上の「時間(X軸)」と「高さ(Y軸)」として配置されます。
◆時間(音の長さ):
1拍(四分音符)を1つの「正方形(□)」とします。例えば3拍伸ばす音なら、正方形を横に3つ並べて表示します。次の音符の正方形へは、線で結んでつながりを表現します。
◆高さ(音程):
縦のY軸は建物の階層のようになります。1階がド、2階がレ、3階がミ…と上がり、7音階で1つのトーテムポールのような高さになります。
◆音には色=音色と高さがあります。
音の高さは、ご存じのように高くなるにしたがって周波数が高くなります。
例えばトランペットで考えると、カンディンスキーが『芸術における精神的なるもの』などの著書で指摘したように、トランペットの音は、視た感じそのものの黄色や黄金のような金属音に聴こえますね?
これに音の高さがある。
とするなら、絵画に翻訳する場合は、画面の下ほど暗く、つまり色としても低周波、上に行くほど白く高周波になっていく。
なんと、これって自然と同じですね?天と地の関係になっている。
この音色と高さの絵画への置き換え法則を見抜けないと、色は青に向かっていくほど高周波になるが、高さも明るい方が高周波になる。では絵画に翻訳するのにどう当てはめればいいの?と分からなくなりここで挫折してしまいますね?
リズムはどう考えるといい?
大衆音楽を作る場合、かつて私が大学時代、NHKFMで作曲実演した時に、最初にメトロノームのよう音でリズムを作り、次の和音=コードをキーボードの音で乗せ、最後にリズムとコード進行からメロディを被せて一丁上がりとしていましたが、これはレッドツェッペリンなども、この方法を使用していたようで、もっともオーソドックスな作曲法ですよね?
大衆音楽はこれに、本人か作詞家が詩を載せて一丁あがりとなりますね。
この基底=ベースとなるリズムは、楽器としてはベースやドラムなどが担当します。
下にローリング・ストーンズ『サティスファクション』のチャーリー・ワッツ、ドラム演奏を絵画にしたものを載せました。
メロディが、曲の主題、イメージなので、そのメロディが次々と右に描出されていくときの音の長短がリズムとなりますね!
ここが今までの絵画と主調音楽・大衆音楽の違いで、マチスやピカソの平面的な絵には、このリズムがないわけです。
わずかに、線の歪曲によってリズムを表現しているので、ロックミュージックの様な躍動感・生命力が感じられないですよね?
和音はどう描画できる?
代表的な和音=コード、ドレミ レファラなどは音とスペクトラムの1対1対応から簡単に以下のように描画できますね?
この和音、コードを巧みに使って絵画制作したのが、国民画家と言われた梅原龍三郎です。
この詳細は次の投稿で詳しく説明します。
この和音描画プログラムは下に掲載しました。
色彩の和音が実際に使用されている絵画の例
この法則にしたがえば、Cメジャーコードのド・ミ・ソは「赤、黄、緑」となります。
Dm(ディー・マイナーコード)のレ・ファ・ラは「朱色、黄緑、青」となりますね?
この作品を観てみてください。梅原龍三郎の富士山で、発表されたときは新聞に「場外満塁ホームランのような大傑作!」と賞賛されたほど世間にインパクトを与えた作品です。
富士のふもと、小さな連山の部分は「赤と緑、そしてその上の雲に黄色」となり、また連山の下の平地も黄色ですね?
ほら、これってCメジャーコードでしょう?
●注意してほしいのは、雲が朱色で、さらに『黄色』があることです。この黄色がこの画面をひときわ引き立てていますね。
これが、よりCメジャーコードの調和を引き立てていますよね?
さらに連山と平地の朱色。雲も朱色に雲の下が黄緑で、その下の連山が青。
ほら、見事Dmコードですね。
梅原は色とスペクトラムの関係は薄々気づいていたけど、はっきりと意識はしていなかったのでは?
でも少なくとも『三色の和音』の理論、三色の定石となる組み合わせの高い「感動」をもたらす調和・効果は法則としてはっきり認識していたでしょう。
この定石が見破れなかったから、他の画家が梅原のような感動を呼ぶ作品を描こうと思っても、どうやっても跳ね返されてしまったわけです。
私もその一人でした。
この法則によるプログラム。
この法則を以下のようにプログラムにしました。
まず、坂本龍一の『ラストエンペラー』を描画したら・・・・私の想定通り、紫禁城、桂林の風景、イメージが描画されました。
これは何を意味するのか?作曲家はただ音だけを脳裏に浮かべて作曲するのではない。 ある具体的な風景や情景、を思い浮かべて曲を作るのです。
だからこそ、松本隆などの作詞家は曲から連想されるそのイメージにピッタリ一致する詩を被せることができるのです。
もう一度いいます。
『歌謡曲などの調性音楽は抽象芸術ではない!』
『音楽は全て抽象画のような抽象芸術というのは誤りである!』
あるクラシック楽団の楽団員の人は私のこの意見に「自分もだが楽団員などクラシック演奏家は皆薄々はっきりとそのようだと理解していた!」と言いました。
あなたもそう思いませんか?
つまり、大衆音楽などの調性音楽は『具象画』なのです!
今まで、抽象画家は『全ての音楽は抽象芸術だ!』と思い込んでそれを前提に『感覚と印象』で点・線・面、色・絵肌を置いていきました。
つまり、世の抽象画家のほとんどは『抽象印象派』『抽象感覚派』と呼べるでしょう。
点、線、面と色を何となく、キャンバスに置いていく。
しかし、そこにはカンディンスキーの口癖だった『必然性』がない。
必然性の代わりに『なんとなく』なのです。
だから当然、抽象画家の多くは、作詞の詩のような具体物の説明性がどうしようもなく失われていて、欠けていることに凄く苦しんだはずです。
具体的な物や風景、花、木々、人物やそれらの際立つ個性を『全然、説明し表現できない』わけですね?
これは、非常に苦しい経験です。だって、言いたいこと。伝えたいことを鑑賞者に十分に伝えられないわけだから。
しかし、調性音楽、つまり普段耳にするポップミュージックや歌謡曲、バッハなどのクラシック音楽が『ハ長調』『イ短調』といった主調音から始まる音楽であり、それが具象画であると分かった時、このどうしようもない表現の不自由の原因と対策が見えてきます。
こうなると、そうです。多くの抽象画家の『音楽は抽象である』という思い込みや『絵画と音楽はまったく共通の周波数などの法則が、物理的に医学・生理学的に違うから絶対統合できない』というステレオタイプの思い込みが間違いとなり、自分の作品の基盤となる表現理論・手法が極めて貧しく、おおざっぱで乏しくぼやけていることがはっきりします。
これは美術史上の常識をちゃぶ台返しでひっくり返す、コペルニクス的な革新=発見ではないでしょうか?
そこで、今回は、この理論の証明となるこの理論通りに描画するPythonプログラムを作りました。
それがこちらです。
今、イノベーションとは「それまで異質でまったく別のものと考えられてきたものに、共通する法則を見抜いて結合したもの」という定石通り、美術史上、音楽史上初めて絵画と音楽は結合し互いに翻訳可能となったのです。
サンプルプログラム
こちらのプログラムをIDLEの画面にコピペして実行してください。
実行結果はこのページのヘッダーと同じになります。
①IDLEのインストールはこちらです。
②IDLEの起動
◆Windowsの場合、画面最下段の検索窓に『IDLE』と打ってEnterキーを押してください。

◆Macの場合は先のIDLEのインストールページをご覧ください。
②プログラムの実行方法
- Pythonに標準で付いている開発環境「IDLE」を起動します。
- 画面上のメニューから「File」→「New File」をクリックし、新しい真っ白なウィンドウを開きます。
- 開いたウィンドウに、上記のプログラム(コード)をすべてコピーして貼り付けます。
- メニューから「Run」→「Run Module」(またはキーボードの F5キー)を押します。
- 「Source Must Be saved・・・・ Ok キャンセル」とメッセージボックスが出るのでOkをクリックして、次の画面のファイル名に適当な名前を自由に入れて『保存(S)』ボタンをクリック
しばらく待つと新しいウィンドウが開き、理論に基づいた「ドレミの歌」の視覚化グラフが描画されます!ぜひお手元で、音楽が絵画に変わる瞬間を体験してみてください。
◆坂本龍一:ラストエンペラー メインテーマの楽譜を絵画に翻訳
楽曲はこちらです!
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib import colors
# ---------------------------------------------------------
# 1. 音楽データの定義(坂本龍一:ラストエンペラー メインテーマ)
# ---------------------------------------------------------
melody = [
# 【Aメロ】
(5, 1, 3), (6, 1, 1), (0, 2, 2), (1, 2, 2), (2, 2, 4),
(0, 2, 2), (5, 1, 2), (4, 1, 2), (5, 1, 4),
# 【Bメロ】
(5, 1, 2), (0, 2, 2), (1, 2, 2), (2, 2, 2), (4, 2, 2),
(2, 2, 4), (1, 2, 2), (0, 2, 2), (5, 1, 6),
]
# ---------------------------------------------------------
# 2. 法則に基づく色の定義
# ---------------------------------------------------------
base_colors = {
0: '#FF0000', 1: '#FFA500', 2: '#FFFF00', 3: '#9ACD32',
4: '#008000', 5: '#0000FF', 6: '#800080'
}
bg_colors = {
0: '#FF76C2', 1: '#FFA376', 2: '#FFE276', 3: '#C2FF76',
4: '#76FFC2', 5: '#76C2FF', 6: '#C276FF' # 「ラ」主調の青系背景
}
def get_color(pitch_class, octave):
"""オクターブが上がると色を明るくする関数"""
base_rgb = colors.to_rgb(base_colors[pitch_class])
if octave <= 1:
return base_rgb
else:
factor = 1.0 - (0.5 ** (octave - 1))
return [c + (1.0 - c) * factor for c in base_rgb]
# ---------------------------------------------------------
# 3. 描画キャンバスと背景色の設定
# ---------------------------------------------------------
fig, ax = plt.subplots(figsize=(16, 8))
# 最初の音(ラ)に基づき、青系の背景に設定
first_pitch = melody[0][0]
ax.set_facecolor(bg_colors[first_pitch])
current_x = 0
square_corners = [] # 全ての正方形の左下と右下の座標を記録するリスト
# ---------------------------------------------------------
# 4. 白大理石の基壇(漢白玉の台座)
# ---------------------------------------------------------
ax.add_patch(patches.Rectangle((0, 0), 100, 0.4, facecolor='#E0E0E0', edgecolor='#CCCCCC', zorder=1))
ax.add_patch(patches.Rectangle((0, 0.4), 100, 0.3, facecolor='#ECECEC', edgecolor='#DDDDDD', zorder=1))
ax.add_patch(patches.Rectangle((0, 0.7), 100, 0.3, facecolor='#F5F5F5', edgecolor='#EEEEEE', zorder=1))
# ---------------------------------------------------------
# 5. 音符(正方形)の配置
# ---------------------------------------------------------
for note in melody:
pitch_class, octave, duration = note
y = pitch_class + 1 + (octave - 1) * 7
note_color = get_color(pitch_class, octave)
# 指定された長さ分、正方形を並べる
for i in range(duration):
sq_x = current_x + i + 0.05
sq_y = y - 0.45
# この正方形の左下(bl)と右下(br)の座標を記録
bl = (sq_x, sq_y)
br = (sq_x + 0.9, sq_y)
square_corners.append({'bl': bl, 'br': br})
rect = patches.Rectangle((sq_x, sq_y), 0.9, 0.9,
facecolor=note_color, edgecolor='black', linewidth=1.2, zorder=4)
ax.add_patch(rect)
current_x += duration
# ---------------------------------------------------------
# 6. 前の□の右下から、次の□の左下へ線を繋ぐ
# ---------------------------------------------------------
for i in range(len(square_corners) - 1):
prev_br_x, prev_br_y = square_corners[i]['br'] # 前の□の右下
next_bl_x, next_bl_y = square_corners[i+1]['bl'] # 次の□の左下
# 薄い黒色(グレー)でシンプルに結ぶ
ax.plot([prev_br_x, next_bl_x], [prev_br_y, next_bl_y], color='#555555', linewidth=1.5, zorder=3)
# ---------------------------------------------------------
# 7. 見た目の調整と出力
# ---------------------------------------------------------
ax.set_xlim(0, current_x)
ax.set_ylim(0, 15)
ax.set_yticks(range(1, 15))
yticklabels = ['1F: C(ド)', '2F: D(レ)', '3F: E(ミ)', '4F: F(ファ)', '5F: G(ソ)', '6F: A(ラ)', '7F: B(シ)',
'8F: C(ド高)', '9F: D(レ高)', '10F: E(ミ高)', '11F: F(ファ高)', '12F: G(ソ高)', '13F: A(ラ高)', '14F: B(シ高)']
ax.set_yticklabels(yticklabels)
ax.set_xlabel("Time (Beats)")
ax.set_title("The Last Emperor - Music Art")
plt.grid(True, which='both', axis='y', linestyle='--', alpha=0.5, color='white', zorder=1)
plt.tight_layout()
plt.show()
大瀧詠一 カナリヤ諸島にて 主メロディ部
◆楽曲はこちらです!
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib import colors
# ---------------------------------------------------------
# 1. 音楽データの定義(大瀧詠一:カナリア諸島にて)
# ---------------------------------------------------------
melody = [
# 【イントロ】(南国の風を感じるストリングス風の波打つメロディ)
(2, 1, 2), (1, 1, 2), (0, 1, 2), (1, 1, 2), (2, 1, 4),
(4, 1, 2), (3, 1, 2), (2, 1, 2), (3, 1, 2), (4, 1, 4),
(5, 1, 2), (4, 1, 2), (3, 1, 2), (2, 1, 2), (1, 1, 4),
(0, 1, 4),
# 【Aメロ】♪薄く切ったオレンジを アイスティーに浮かべて
(2, 1, 1), (2, 1, 1), (2, 1, 2), # う・す・く
(2, 1, 1), (3, 1, 1), (4, 1, 2), # きっ・た
(5, 1, 1), (4, 1, 1), (3, 1, 1), (2, 1, 1), (1, 1, 4), # お・れ・ん・じ・を
(1, 1, 1), (1, 1, 1), (1, 1, 2), # あ・い・す
(1, 1, 1), (2, 1, 1), (3, 1, 2), # てぃ・に
(4, 1, 1), (3, 1, 1), (2, 1, 1), (1, 1, 1), (0, 1, 4), # う・か・べ・て
# 【Aメロ続き】♪海辺のバルコニーで 空の色を眺める
(2, 1, 1), (2, 1, 1), (2, 1, 2), # う・み・べ
(2, 1, 1), (3, 1, 1), (4, 1, 2), # の・
(5, 1, 1), (4, 1, 1), (3, 1, 1), (2, 1, 1), (1, 1, 4), # ば・る・こ・に・で
(1, 1, 1), (1, 1, 1), (1, 1, 2), # そ・ら・の
(1, 1, 1), (2, 1, 1), (3, 1, 2), # い・ろ・
(4, 1, 1), (3, 1, 1), (2, 1, 1), (1, 1, 1), (0, 1, 8), # な・が・め・るーー
]
# ---------------------------------------------------------
# 2. 法則に基づく色の定義
# ---------------------------------------------------------
base_colors = {
0: '#FF0000', 1: '#FFA500', 2: '#FFFF00', 3: '#9ACD32',
4: '#008000', 5: '#0000FF', 6: '#800080'
}
bg_colors = {
0: '#FF76C2', 1: '#FFA376', 2: '#FFE276', 3: '#C2FF76',
4: '#76FFC2', 5: '#76C2FF', 6: '#C276FF'
}
def get_color(pitch_class, octave):
"""オクターブが上がると色を明るくする関数"""
base_rgb = colors.to_rgb(base_colors[pitch_class])
if octave <= 1:
return base_rgb
else:
factor = 1.0 - (0.5 ** (octave - 1))
return [c + (1.0 - c) * factor for c in base_rgb]
# ---------------------------------------------------------
# 3. 描画キャンバスと背景色の設定
# ---------------------------------------------------------
fig, ax = plt.subplots(figsize=(20, 8)) # 曲が少し長いため横幅を広げました
# 最初の音(ミ)に基づき、背景色が自動で「カナリアイエロー(#FFE276)」に設定されます
first_pitch = melody[0][0]
ax.set_facecolor(bg_colors[first_pitch])
current_x = 0
square_corners = [] # 全ての正方形の左下と右下の座標を記録するリスト
# ---------------------------------------------------------
# 4. 白いテラスの基壇(海辺のリゾートをイメージした白い台座)
# ---------------------------------------------------------
ax.add_patch(patches.Rectangle((0, 0), 150, 0.4, facecolor='#E0E0E0', edgecolor='#CCCCCC', zorder=1))
ax.add_patch(patches.Rectangle((0, 0.4), 150, 0.3, facecolor='#ECECEC', edgecolor='#DDDDDD', zorder=1))
ax.add_patch(patches.Rectangle((0, 0.7), 150, 0.3, facecolor='#F5F5F5', edgecolor='#EEEEEE', zorder=1))
# ---------------------------------------------------------
# 5. 音符(正方形)の配置
# ---------------------------------------------------------
for note in melody:
pitch_class, octave, duration = note
y = pitch_class + 1 + (octave - 1) * 7
note_color = get_color(pitch_class, octave)
for i in range(duration):
sq_x = current_x + i + 0.05
sq_y = y - 0.45
# この正方形の左下(bl)と右下(br)の座標を記録
bl = (sq_x, sq_y)
br = (sq_x + 0.9, sq_y)
square_corners.append({'bl': bl, 'br': br})
rect = patches.Rectangle((sq_x, sq_y), 0.9, 0.9,
facecolor=note_color, edgecolor='black', linewidth=1.2, zorder=4)
ax.add_patch(rect)
current_x += duration
# ---------------------------------------------------------
# 6. 前の□の右下から、次の□の左下へ線を繋ぐ
# ---------------------------------------------------------
for i in range(len(square_corners) - 1):
prev_br_x, prev_br_y = square_corners[i]['br'] # 前の□の右下
next_bl_x, next_bl_y = square_corners[i+1]['bl'] # 次の□の左下
# 薄い黒色(グレー)でシンプルに結ぶ
ax.plot([prev_br_x, next_bl_x], [prev_br_y, next_bl_y], color='#555555', linewidth=1.5, zorder=3)
# ---------------------------------------------------------
# 7. 見た目の調整と出力
# ---------------------------------------------------------
ax.set_xlim(0, current_x)
ax.set_ylim(0, 10) # メロディの最高音に合わせて余白を調整
ax.set_yticks(range(1, 10))
yticklabels = ['1F: C(ド)', '2F: D(レ)', '3F: E(ミ)', '4F: F(ファ)', '5F: G(ソ)', '6F: A(ラ)', '7F: B(シ)',
'8F: C(ド高)', '9F: D(レ高)']
ax.set_yticklabels(yticklabels)
ax.set_xlabel("Time (Beats)")
ax.set_title("Eiichi Ohtaki - A Canary Island (Music Art)")
plt.grid(True, which='both', axis='y', linestyle='--', alpha=0.5, color='white', zorder=1)
plt.tight_layout()
plt.show()
カナリヤ諸島にて 冒頭 イントロ部分

今度は弦楽奏イントロ部分のみを描画させました。楽曲はこちらです。
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib import colors
# ---------------------------------------------------------
# 1. 音楽データの定義(大瀧詠一:カナリア諸島にて - イントロのみ)
# 「ダタダ~~ン、ダ~~ン🎵」のフレーズをブロックの長短で忠実に再現
# ---------------------------------------------------------
melody = [
# 1回目:ダタダ~~ン(高)、ダ~~ン🎵 (ソ・ラ・ド高ーー、ラーー)
(4, 1, 1), (5, 1, 1), (0, 2, 6), (5, 1, 4),
# 2回目:ダタダ~~ン(高)、ダ~~ン🎵 (ソ・ラ・レ高ーー、ラーー)
(4, 1, 1), (5, 1, 1), (1, 2, 6), (5, 1, 4),
# 3回目:ダタダ~~ン(最高音)、ダ~~ン🎵 (ソ・ラ・ミ高ーー、レ高・ド高ー)
(4, 1, 1), (5, 1, 1), (2, 2, 6), (1, 2, 2), (0, 2, 4),
]
# ---------------------------------------------------------
# 2. 法則に基づく色の定義(元のスペクトルに復元)
# ---------------------------------------------------------
base_colors = {
0: '#FF0000', # ド (C): 赤
1: '#FFA500', # レ (D): オレンジ
2: '#FFFF00', # ミ (E): 黄色
3: '#9ACD32', # ファ (F): 黄緑
4: '#008000', # ソ (G): 緑
5: '#0000FF', # ラ (A): 青
6: '#800080' # シ (B): 紫
}
bg_colors = {
0: '#FF76C2', # ド (C): 薄い赤
1: '#FFA376', # レ (D): 薄いオレンジ
2: '#FFE276', # ミ (E): 薄い黄色
3: '#C2FF76', # ファ (F): 薄い黄緑
4: '#76FFC2', # ソ (G): 薄い緑(今回の主調色:リゾートグリーン)
5: '#76C2FF', # ラ (A): 薄い青
6: '#C276FF' # シ (B): 薄い紫
}
def get_color(pitch_class, octave):
"""オクターブが上がると色を明るくする関数"""
base_rgb = colors.to_rgb(base_colors[pitch_class])
if octave <= 1:
return base_rgb
else:
factor = 1.0 - (0.5 ** (octave - 1))
return [c + (1.0 - c) * factor for c in base_rgb]
# ---------------------------------------------------------
# 3. 描画キャンバスと背景色の設定
# ---------------------------------------------------------
fig, ax = plt.subplots(figsize=(15, 7))
# 最初の音(ソ)に基づき、背景色が自動で「薄い緑(#76FFC2)」に設定されます
first_pitch = melody[0][0]
ax.set_facecolor(bg_colors[first_pitch])
current_x = 0
square_corners = []
# ---------------------------------------------------------
# 4. 白いテラスの基壇
# ---------------------------------------------------------
ax.add_patch(patches.Rectangle((0, 0), 100, 0.4, facecolor='#E0E0E0', edgecolor='#CCCCCC', zorder=1))
ax.add_patch(patches.Rectangle((0, 0.4), 100, 0.3, facecolor='#ECECEC', edgecolor='#DDDDDD', zorder=1))
ax.add_patch(patches.Rectangle((0, 0.7), 100, 0.3, facecolor='#F5F5F5', edgecolor='#EEEEEE', zorder=1))
# ---------------------------------------------------------
# 5. 音符(正方形)の配置
# ---------------------------------------------------------
for note in melody:
pitch_class, octave, duration = note
y = pitch_class + 1 + (octave - 1) * 7
note_color = get_color(pitch_class, octave)
for i in range(duration):
sq_x = current_x + i + 0.05
sq_y = y - 0.45
bl = (sq_x, sq_y)
br = (sq_x + 0.9, sq_y)
square_corners.append({'bl': bl, 'br': br})
rect = patches.Rectangle((sq_x, sq_y), 0.9, 0.9,
facecolor=note_color, edgecolor='black', linewidth=1.2, zorder=4)
ax.add_patch(rect)
current_x += duration
# ---------------------------------------------------------
# 6. 前の□の右下から、次の□の左下へ線を繋ぐ
# ---------------------------------------------------------
for i in range(len(square_corners) - 1):
prev_br_x, prev_br_y = square_corners[i]['br']
next_bl_x, next_bl_y = square_corners[i+1]['bl']
# 薄い黒色(グレー)でシンプルに結ぶ
ax.plot([prev_br_x, next_bl_x], [prev_br_y, next_bl_y], color='#555555', linewidth=1.5, zorder=3)
# ---------------------------------------------------------
# 7. 見た目の調整と出力
# ---------------------------------------------------------
ax.set_xlim(0, current_x)
ax.set_ylim(0, 11)
ax.set_yticks(range(1, 12))
yticklabels = ['1F: C(ド)', '2F: D(レ)', '3F: E(ミ)', '4F: F(ファ)', '5F: G(ソ)', '6F: A(ラ)', '7F: B(シ)',
'8F: C(ド高)', '9F: D(レ高)', '10F: E(ミ高)', '11F: F(ファ高)']
ax.set_yticklabels(yticklabels)
ax.set_xlabel("Time (Beats)")
ax.set_title("Eiichi Ohtaki - A Canary Island (Intro Sequence)")
plt.grid(True, which='both', axis='y', linestyle='--', alpha=0.5, color='white', zorder=1)
plt.tight_layout()
plt.show()
クラシック音楽の主要なコード・和音の描画
◆まず「Cメジャー」という世界=音階
Cメジャーの音階は、皆さんご存じの
**ド・レ・ミ・ファ・ソ・ラ・シ・ド**
です。
この7つの音を使って、3つの音を重ねると基本的な三和音ができます。
たとえば、
**ド・ミ・ソ**
を同時に鳴らすと「C」という和音になります。
このCは、Cメジャーという音楽の「中心」です。
音楽がどこかへ旅をしても、最後にCへ戻ってくると、 「帰ってきた」という感じがします。
これが**主和音(Ⅰ)**です。
これがクラシック音楽の代表的な和音です。
| 和声記号 | 和音 | 構成音 | 基本的な役割 |
|---|---|---|---|
| Ⅰ | C | ド・ミ・ソ | 安定・中心 |
| Ⅱ | Dm | レ・ファ・ラ | 次へ進む準備 |
| Ⅳ | F | ファ・ラ・ド | 中心から離れる |
| Ⅴ | G | ソ・シ・レ | Cへ戻りたくなる |
| Ⅴ7 | G7 | ソ・シ・レ・ファ | 強い緊張 |
| Ⅶ° | Bdim | シ・レ・ファ | 非常に不安定 |
それではクラシック音楽の代表的な和音・コードを描画するプログラムです。
実行結果はこちらです。

import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib import colors
# ---------------------------------------------------------
# 1. クラシック音楽(Cメジャー調)の代表的な機能和音の定義
# 形式: (和声記号と機能, コード名, 構成音)
# ---------------------------------------------------------
classic_chords = [
("Ⅰ\n(Tonic)", "C", [(0, 1), (2, 1), (4, 1)]), # 主和音:安定
("Ⅳ\n(Subdominant)", "F", [(3, 1), (5, 1), (0, 2)]), # 下属和音:少し動く
("Ⅴ\n(Dominant)", "G", [(4, 1), (6, 1), (1, 2)]), # 属和音:緊張
("Ⅴ7\n(Dominant 7th)", "G7", [(4, 1), (6, 1), (1, 2), (3, 2)]), # 属七の和音:強い緊張
("Ⅱ\n(Supertonic)", "Dm", [(1, 1), (3, 1), (5, 1)]), # Ⅱ度の和音(Ⅳの代理)
("Ⅶ°\n(Diminished)", "Bdim", [(6, 1), (1, 2), (3, 2)]), # 減三和音:不安定
]
# カデンツ(和音の進行)のデモンストレーション用(Ⅴ7 -> Ⅰ)
cadence = [
("Ⅴ7 (Tension)", "G7", [(4, 1), (6, 1), (1, 2), (3, 2)]),
("Ⅰ (Resolution)", "C", [(0, 1), (2, 1), (4, 1)])
]
# ---------------------------------------------------------
# 2. 法則に基づく色の定義
# ---------------------------------------------------------
base_colors = {
0: '#FF0000', # C (ド): 赤
1: '#FFA500', # D (レ): オレンジ
2: '#FFFF00', # E (ミ): 黄
3: '#9ACD32', # F (ファ): 黄緑
4: '#008000', # G (ソ): 緑
5: '#0000FF', # A (ラ): 青
6: '#800080', # B (シ): 紫
}
def get_color(pitch_class, octave):
"""オクターブが上がると色を明るくする関数"""
base_hex = base_colors.get(pitch_class, '#888888')
base_rgb = colors.to_rgb(base_hex)
if octave <= 1:
return base_rgb
else:
factor = 1.0 - (0.5 ** (octave - 1))
return [c + (1.0 - c) * factor for c in base_rgb]
# ---------------------------------------------------------
# 3. 描画キャンバスの設定
# ---------------------------------------------------------
fig, ax = plt.subplots(figsize=(20, 8))
ax.set_facecolor('#76C2FF') # 基本の青系背景
current_x = 0
# 白いテラスの基壇
ax.add_patch(patches.Rectangle((0, 0), 120, 0.4, facecolor='#E0E0E0', edgecolor='#CCCCCC', zorder=1))
ax.add_patch(patches.Rectangle((0, 0.4), 120, 0.3, facecolor='#ECECEC', edgecolor='#DDDDDD', zorder=1))
ax.add_patch(patches.Rectangle((0, 0.7), 120, 0.3, facecolor='#F5F5F5', edgecolor='#EEEEEE', zorder=1))
# ---------------------------------------------------------
# 4. 代表的な6つの和音を描画
# ---------------------------------------------------------
# タイトルテキスト
ax.text(0.5, 13.5, "[ Classical Functional Harmony: The 6 Core Chords ]", fontsize=14, fontweight='bold', color='white', zorder=5)
for function_name, chord_name, notes in classic_chords:
sq_x = current_x + 0.5
for pitch_class, octave in notes:
y = pitch_class + 1 + (octave - 1) * 7
sq_y = y - 0.45
note_color = get_color(pitch_class, octave)
rect = patches.Rectangle((sq_x, sq_y), 1.2, 0.9,
facecolor=note_color, edgecolor='black', linewidth=1.2, zorder=4)
ax.add_patch(rect)
# コード名(上)と機能名(下)
ax.text(sq_x + 0.6, -1.0, function_name, ha='center', va='top', fontsize=10, fontweight='bold', color='#333333', zorder=5)
ax.text(sq_x + 0.6, 0.2, chord_name, ha='center', va='center', fontsize=12, fontweight='bold', color='#550000', zorder=5)
current_x += 2.5
# ---------------------------------------------------------
# 5. カデンツ(Ⅴ7 -> Ⅰ の解決)を描画
# ---------------------------------------------------------
current_x += 1.0 # 少し間を開ける
ax.plot([current_x, current_x], [0, 15], color='white', linestyle='--', linewidth=2, zorder=2) # 区切り線
current_x += 1.0
ax.text(current_x, 13.5, "[ The Ultimate Resolution: Dominant 7th to Tonic ]", fontsize=14, fontweight='bold', color='white', zorder=5)
for function_name, chord_name, notes in cadence:
sq_x = current_x + 0.5
for pitch_class, octave in notes:
y = pitch_class + 1 + (octave - 1) * 7
sq_y = y - 0.45
note_color = get_color(pitch_class, octave)
rect = patches.Rectangle((sq_x, sq_y), 1.5, 0.9,
facecolor=note_color, edgecolor='black', linewidth=1.5, zorder=4)
ax.add_patch(rect)
ax.text(sq_x + 0.75, -1.0, function_name, ha='center', va='top', fontsize=11, fontweight='bold', color='#333333', zorder=5)
ax.text(sq_x + 0.75, 0.2, chord_name, ha='center', va='center', fontsize=14, fontweight='bold', color='#550000', zorder=5)
current_x += 3.0
# ---------------------------------------------------------
# 6. 見た目の調整と出力
# ---------------------------------------------------------
ax.set_xlim(0, current_x)
ax.set_ylim(-2.5, 15) # 下部のテキスト用にy軸を少し下へ広げる
ax.set_yticks(range(1, 15))
yticklabels = ['1F: C(ド)', '2F: D(レ)', '3F: E(ミ)', '4F: F(ファ)', '5F: G(ソ)', '6F: A(ラ)', '7F: B(シ)',
'8F: C(ド高)', '9F: D(レ高)', '10F: E(ミ高)', '11F: F(ファ高)', '12F: G(ソ高)', '13F: A(ラ高)', '14F: B(シ高)']
ax.set_yticklabels(yticklabels)
ax.set_xlabel("Time / Structure")
ax.set_title("Visualizing Functional Harmony: The Inevitability of Structure")
plt.grid(True, which='both', axis='y', linestyle='--', alpha=0.5, color='white', zorder=1)
plt.tight_layout()
plt.show()
代表的な和音のプログラムだが、短調の和音も描出
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib import colors
# ---------------------------------------------------------
# 1. 和音ペアの定義を拡張(幅を1拍=1個のブロックにコンパクト化)
# 形式: (長調の名前, 長調の構成音, 短調の名前, 短調の構成音)
# ---------------------------------------------------------
chord_pairs = [
("C", [(0, 1), (2, 1), (4, 1)], "C#m", [(0.5, 1), (2, 1), (5, 1)]),
("Db", [(0.5, 1), (2.5, 1), (4.5, 1)], "Dm", [(1, 1), (3, 1), (5, 1)]),
("D", [(1, 1), (3, 1), (5, 1)], "D#m", [(1.5, 1), (3, 1), (5.5, 1)]),
("Eb", [(1.5, 1), (3.5, 1), (5.5, 1)], "Em", [(2, 1), (4, 1), (6, 1)]),
("E", [(2, 1), (4, 1), (6, 1)], "Fm", [(3, 1), (5, 1), (0, 2)]),
("F", [(3, 1), (5, 1), (0, 2)], "F#m", [(3.5, 1), (5.5, 1), (0.5, 2)]),
("F#", [(3.5, 1), (5.5, 1), (0.5, 2)], "Gm", [(4, 1), (6, 1), (1, 2)]),
("G", [(4, 1), (6, 1), (1, 2)], "G#m", [(4.5, 1), (6.5, 1), (1.5, 2)]),
("Ab", [(4.5, 1), (6.5, 1), (1.5, 2)], "Am", [(5, 1), (0, 2), (2, 2)]),
("A", [(5, 1), (0, 2), (2, 2)], "A#m", [(5.5, 1), (0.5, 2), (2.5, 2)]),
]
# ---------------------------------------------------------
# 2. 法則に基づく色の定義(短調は赤〜オレンジの中間でくすんだ暗い色)
# ---------------------------------------------------------
base_colors = {
0: '#FF0000', # C (ド): 赤
0.5: '#C45500', # C# / Db: 赤とオレンジの中間でくすんだ暗い色
1: '#FFA500', # D (レ): オレンジ
1.5: '#B87A00', # D# / Eb: オレンジ寄りのくすんだ暗い色
2: '#FFFF00', # E (ミ): 黄
2.5: '#D1D100', # E# / F: 黄のくすみ
3: '#9ACD32', # F (ファ): 黄緑
3.5: '#7A9A28', # F# / Gb: くすんだ黄緑
4: '#008000', # G (ソ): 緑
4.5: '#006633', # G# / Ab: くすんだ緑
5: '#0000FF', # A (ラ): 青
5.5: '#0000B3', # A# / Bb: くすんだ青
6: '#800080', # B (シ): 紫
6.5: '#5E005E' # B# / C: くすんだ紫
}
bg_colors = {
0: '#FF76C2', 1: '#FFA376', 2: '#FFE276', 3: '#C2FF76',
4: '#76FFC2', 5: '#76C2FF', 6: '#C276FF'
}
def get_color(pitch_class, octave):
"""オクターブが上がると色を明るくする関数"""
base_hex = base_colors.get(pitch_class, '#888888')
base_rgb = colors.to_rgb(base_hex)
if octave <= 1:
return base_rgb
else:
factor = 1.0 - (0.5 ** (octave - 1))
return [c + (1.0 - c) * factor for c in base_rgb]
# ---------------------------------------------------------
# 3. 描画キャンバスの設定(和音が増えたため横幅を拡大)
# ---------------------------------------------------------
fig, ax = plt.subplots(figsize=(22, 8))
ax.set_facecolor('#76C2FF') # 基本の青系背景
current_x = 0
# 白いテラスの基壇
ax.add_patch(patches.Rectangle((0, 0), 120, 0.4, facecolor='#E0E0E0', edgecolor='#CCCCCC', zorder=1))
ax.add_patch(patches.Rectangle((0, 0.4), 120, 0.3, facecolor='#ECECEC', edgecolor='#DDDDDD', zorder=1))
ax.add_patch(patches.Rectangle((0, 0.7), 120, 0.3, facecolor='#F5F5F5', edgecolor='#EEEEEE', zorder=1))
# ---------------------------------------------------------
# 4. 1個(1拍分)の長調と短調のペアを連続配置
# ---------------------------------------------------------
for major_name, major_notes, minor_name, minor_notes in chord_pairs:
# --- 【長調(1個のみ)】 ---
sq_x = current_x + 0.05
for pitch_class, octave in major_notes:
y = pitch_class + 1 + (octave - 1) * 7
sq_y = y - 0.45
note_color = get_color(pitch_class, octave)
rect = patches.Rectangle((sq_x, sq_y), 0.9, 0.9,
facecolor=note_color, edgecolor='black', linewidth=1.2, zorder=4)
ax.add_patch(rect)
# 長調のコード名
ax.text(current_x + 0.5, 0.2, major_name, ha='center', va='center',
fontsize=10, fontweight='bold', color='#333333', zorder=5)
current_x += 1.2 # 次の短調までのスペース
# --- 【半音ずれた短調(1個のみ)】 ---
sq_x = current_x + 0.05
for pitch_class, octave in minor_notes:
y = pitch_class + 1 + (octave - 1) * 7
sq_y = y - 0.45
note_color = get_color(pitch_class, octave)
rect = patches.Rectangle((sq_x, sq_y), 0.9, 0.9,
facecolor=note_color, edgecolor='black', linewidth=1.2, zorder=4)
ax.add_patch(rect)
# 短調のコード名
ax.text(current_x + 0.5, 0.2, minor_name, ha='center', va='center',
fontsize=10, fontweight='bold', color='#550000', zorder=5)
current_x += 2.0 # 次のペアのセットまでの大きめのスペース
# ---------------------------------------------------------
# 5. 見た目の調整と出力
# ---------------------------------------------------------
ax.set_xlim(0, current_x)
ax.set_ylim(0, 15)
ax.set_yticks(range(1, 15))
yticklabels = ['1F: C(ド)', '2F: D(レ)', '3F: E(ミ)', '4F: F(ファ)', '5F: G(ソ)', '6F: A(ラ)', '7F: B(シ)',
'8F: C(ド高)', '9F: D(レ高)', '10F: E(ミ高)', '11F: F(ファ高)', '12F: G(ソ高)', '13F: A(ラ高)', '14F: B(シ高)']
ax.set_yticklabels(yticklabels)
ax.set_xlabel("Chord Variations (Major vs Shifted Minor)")
ax.set_title("Expanded Spectral Translation: 10 Major & Minor Chord Pairs")
plt.grid(True, which='both', axis='y', linestyle='--', alpha=0.5, color='white', zorder=1)
plt.tight_layout()
plt.show()
ローリング・ストーンズ サティスファクション
★楽曲はこちらです!
どうですか?まず、全体が非常に、性行為を暗示させる『エロティック』な主調色になっており、さらに、「I can’t get no Satisfaction」とううメロディラインが、女性がベットに横たわっていることを想起させる図になっていますすね?
基底、ベースとなるドラム音は、性行為のリズミカルな一定の繰り返しである『ピストン運動』を表現していますね。
それで、タイトルが「I can’t get no Satisfaction」=「俺は全然満足できない。」で、「no,no,noお前じゃ全然満足できない。」
ということで「モテすぎてお前ぐらいじゃ全然満足できない。明後日出直してこい!」という詩の内容を見事に一致してますね?
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib import colors
# ---------------------------------------------------------
# 1. 音楽データの定義(The Rolling Stones: Satisfaction Vocal)
# 形式: (開始X, ピッチ, オクターブ, 持続ブロック数, 歌詞テキスト)
# ---------------------------------------------------------
vocal_line = [
(0, 6, 1, 3, "I"), # I (B)
(4, 6, 1, 2, "can't"), # can't (B)
(7, 6, 1, 2, "get"), # get (B)
(10, 6, 1, 4, "no"), # no (B)
(16, 6, 1, 2, "sa"), # sa (B)
(19, 0.5, 2, 2, "tis"), # tis (C#)
(22, 1, 2, 4, "fac"), # fac (D)
(27, 6, 1, 6, "tion") # tion (B)
]
# ベースとドラムは伴奏・重力の基盤として継続
bass_line = []
for i in range(0, 38, 2):
bass_line.append((i, 2, 0, 1))
drums = []
for i in range(0, 38, 4):
drums.append((i, 98, 0, 2))
drums.append((i+2, 99, 0, 2))
# ---------------------------------------------------------
# 2. 法則に基づく色の定義
# ---------------------------------------------------------
base_colors = {
0.5: '#C45500', # C# (ド#)
1: '#FFA500', # D (レ)
2: '#FFFF00', # E (ミ)
6: '#800080', # B (シ)
98: '#333333',
99: '#FFFFFF'
}
def get_color(pitch_class, octave):
base_hex = base_colors.get(pitch_class, '#000000')
base_rgb = colors.to_rgb(base_hex)
if pitch_class >= 98: return base_rgb
if octave <= 0: return [c * 0.4 for c in base_rgb]
elif octave == 1: return base_rgb
else:
factor = 1.0 - (0.5 ** (octave - 1))
return [c + (1.0 - c) * factor for c in base_rgb]
# ---------------------------------------------------------
# 3. 描画キャンバスの設定(正方形 + 指定の背景色)
# ---------------------------------------------------------
bg_color = '#da70d6' # 主調色(オーキッド)
text_color = '#1A1A1A'
fig, ax = plt.subplots(figsize=(12, 12))
fig.patch.set_facecolor(bg_color)
ax.set_facecolor(bg_color)
# 大地(ベース・ドラム層)
ax.add_patch(patches.Rectangle((0, -1), 40, 1.5, facecolor='#111111', edgecolor='none', zorder=1))
# ---------------------------------------------------------
# 4. ブロックを描画する関数(ボーカル用拡張)
# ---------------------------------------------------------
def draw_track(track_data, is_drum=False, is_vocal=False):
for note in track_data:
if is_vocal:
start_x, pitch_class, octave, duration, lyric = note
else:
start_x, pitch_class, octave, duration = note
if pitch_class == 98: y = -0.5
elif pitch_class == 99: y = 0.5
else: y = pitch_class + 1 + (octave - 1) * 7
note_color = get_color(pitch_class, octave)
# ブロック群の描画
for i in range(duration):
sq_x = start_x + i + 0.1
sq_y = y - 0.45
if is_drum:
rect = patches.Circle((sq_x + 0.45, sq_y + 0.45), 0.4,
facecolor=note_color, edgecolor='black', linewidth=1.5, zorder=3)
else:
rect = patches.Rectangle((sq_x, sq_y), 0.8, 0.8,
facecolor=note_color, edgecolor='black', linewidth=1.5, zorder=4)
ax.add_patch(rect)
# ボーカルの場合はブロック群の中央に歌詞テキストを配置
if is_vocal:
center_x = start_x + (duration / 2)
center_y = y - 0.05
ax.text(center_x, center_y, lyric, ha='center', va='center',
fontsize=14, fontweight='bold', color='white', zorder=5)
draw_track(drums, is_drum=True)
draw_track(bass_line, is_drum=False)
draw_track(vocal_line, is_vocal=True)
# ---------------------------------------------------------
# 5. 見た目の調整と出力
# ---------------------------------------------------------
ax.set_xlim(-1, 36)
ax.set_ylim(-1, 10)
ax.set_yticks([-0.5, 0.5, 1, 2, 3, 6, 7, 8, 8.5])
yticklabels = ['Kick', 'Snare', '1F: C(ド)', '2F: D(レ)', '3F: E(ミ)', '7F: B(シ)',
'8F: C(ド高)', '9F: D(レ高)', '9.5F: C#(ド#高)']
ax.set_yticklabels(yticklabels, color=text_color, fontweight='bold')
ax.tick_params(axis='x', colors=text_color)
ax.tick_params(axis='y', colors=text_color)
ax.set_xlabel("Time (Grid)", color=text_color, fontweight='bold')
ax.set_title("The Rolling Stones - Satisfaction (Vocal & Typography)", color=text_color, fontweight='bold', fontsize=16)
plt.grid(True, which='both', axis='x', linestyle=':', alpha=0.3, color=text_color, zorder=1)
plt.tight_layout()
plt.show()
サティスファクション 間奏のドラム部分
今度は、間奏の、ドラマー、チャーリー・ワッツのドラム演奏を描出したものです。
画面下の白と黒の○がドラムの打撃音です。
◆楽曲はこちらです。
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib import colors
# ---------------------------------------------------------
# 1. 音楽データの定義("no, no, no" -> ドラムフィル -> "Hey, Hey")
# ---------------------------------------------------------
vocal_line = [
# 前半 (感情の拒絶)
(2, 6, 1, 2, "oh,"),
(6, 6, 1, 2, "no,"),
(10, 6, 1, 2, "no,"),
(14, 6, 1, 2, "no!"),
# 後半 (反逆の再開: He HEI HEI ThatS)
(24, 6, 1, 2, "Hey"),
(26, 6, 1, 2, "Hey"),
(28, 6, 1, 2, "Hey,"),
(30, 6, 1, 2, "That's"),
(32, 6, 1, 2, "what I"),
(34, 6, 1, 2, "say")
]
drums = []
# 前半のビート (KickとSnareの反復)
for i in range(0, 16, 4):
drums.append((i, 98, 0, 1)) # Kick
drums.append((i+2, 99, 0, 1)) # Snare
# ブレイク部分の正確なドラムフィル(ツン タン ツツツツ ツン タン)
drums.append((16, 98, 0, 1)) # ツン (Kick)
drums.append((18, 99, 0, 1)) # タン (Snare)
# ツツツツ (Snareの16分音符4連打。持続時間を0.5として定義)
drums.append((20, 99, 0, 0.5))
drums.append((20.5, 99, 0, 0.5))
drums.append((21, 99, 0, 0.5))
drums.append((21.5, 99, 0, 0.5))
drums.append((22, 98, 0, 1)) # ツン (Kick)
drums.append((24, 99, 0, 1)) # タン (Snare / Heyと同時にクラッシュ)
# 後半のビート再開
for i in range(26, 38, 4):
drums.append((i, 98, 0, 1)) # Kick
drums.append((i+2, 99, 0, 1)) # Snare
# ---------------------------------------------------------
# 2. 法則に基づく色の定義
# ---------------------------------------------------------
base_colors = {
6: '#800080', # B (シ): ボーカルの主調色
98: '#333333', # Kick (黒に近いグレー)
99: '#FFFFFF' # Snare (白)
}
def get_color(pitch_class, octave):
base_hex = base_colors.get(pitch_class, '#000000')
base_rgb = colors.to_rgb(base_hex)
if pitch_class >= 98: return base_rgb
if octave <= 0: return [c * 0.4 for c in base_rgb]
else: return base_rgb
# ---------------------------------------------------------
# 3. 描画キャンバスの設定(正方形 + 指定の背景色)
# ---------------------------------------------------------
bg_color = '#da70d6' # 主調色(オーキッド)
text_color = '#1A1A1A'
fig, ax = plt.subplots(figsize=(12, 12))
fig.patch.set_facecolor(bg_color)
ax.set_facecolor(bg_color)
# 大地(黒い基盤)
ax.add_patch(patches.Rectangle((0, -1), 40, 1.5, facecolor='#111111', edgecolor='none', zorder=1))
# ---------------------------------------------------------
# 4. ブロックと完全正円を描画する関数
# ---------------------------------------------------------
def draw_track(track_data, is_drum=False, is_vocal=False):
for note in track_data:
if is_vocal:
start_x, pitch_class, octave, duration, lyric = note
else:
start_x, pitch_class, octave, duration = note
if pitch_class == 98: y = -0.5
elif pitch_class == 99: y = 0.5
else: y = pitch_class + 1 + (octave - 1) * 7
note_color = get_color(pitch_class, octave)
if is_drum:
# 円をキャンバスの比率に関わらず「絶対的な正円」にするためScatterマーカーを使用
# ツツツツ(duration 0.5)の連打は面積(s)を小さくする
marker_size = 600 if duration >= 1 else 150
cx = start_x + (0.5 if duration >= 1 else 0.25)
cy = y
ax.scatter(cx, cy, s=marker_size, c=[note_color], edgecolors='black', linewidths=1.5, zorder=3)
elif is_vocal:
# 歌詞ブロックを繋がった1つのソリッドな長方形として描画
rect_width = duration - 0.1
sq_x = start_x + 0.05
sq_y = y - 0.4
rect = patches.Rectangle((sq_x, sq_y), rect_width, 0.8,
facecolor=note_color, edgecolor='black', linewidth=1.5, zorder=4)
ax.add_patch(rect)
# テキストの中央配置
center_x = start_x + (duration / 2)
center_y = y
ax.text(center_x, center_y, lyric, ha='center', va='center',
fontsize=16, fontweight='bold', color='white', zorder=5)
draw_track(drums, is_drum=True)
draw_track(vocal_line, is_vocal=True)
# ---------------------------------------------------------
# 5. 見た目の調整と出力
# ---------------------------------------------------------
ax.set_xlim(-1, 37)
ax.set_ylim(-1, 10)
ax.set_yticks([-0.5, 0.5, 1, 2, 3, 6, 7, 8, 8.5])
yticklabels = ['Kick', 'Snare', '1F: C', '2F: D', '3F: E', '7F: B (Vocal)',
'8F: C#', '9F: D', '9.5F: E']
ax.set_yticklabels(yticklabels, color=text_color, fontweight='bold')
ax.tick_params(axis='x', colors=text_color)
ax.tick_params(axis='y', colors=text_color)
ax.set_xlabel("Time (Grid)", color=text_color, fontweight='bold')
ax.set_title("The Rolling Stones - Drum Fill & Vocal Resurgence", color=text_color, fontweight='bold', fontsize=16)
plt.grid(True, which='both', axis='x', linestyle=':', alpha=0.3, color=text_color, zorder=1)
plt.tight_layout()
plt.show()










