1. はじめに
今年から新しい趣味としてDTMを始めようと思い、それと同時にLT登壇やアウトプットも継続していきたいと考えていました。
その結果、
「音楽 × 技術」
をテーマに、今年1年は音楽に絡めたLTをしていこうと決めました。
本記事は、
「音楽 × ネタ」
をテーマにしたプロダクトを作った記録です。
説明
本番に入る前にまずは簡単に音と色についての説明をします
2. 音の聞こえるしくみについて
私たちは普段、当たり前のように音を聞いていますが、
音の正体は
空気の振動
です。
例えば、
- ギターの弦を弾く
- スピーカーが振動する
- 手を叩く
こうした動きによって、周囲の空気が押されたり引かれたりします。
すると空気中には
圧縮(密)
↓
膨張(疎)
↓
圧縮(密)
↓
膨張(疎)
という変化が波として伝わっていきます。
これを
音波(sound wave)
と呼びます。
この波が耳に届くと、
鼓膜が振動する
↓
内耳で電気信号に変換される
↓
脳が「音」として認識する
という流れで、私たちは音を感じています。
つまり、
音は「空気を伝わる波」
です。
3. 色の見えるしくみについて
では、色はどうでしょうか。
色も実は
波
です。
正確には、
光の波長
を私たちは色として認識しています。
太陽光や照明の光は、さまざまな波長を持っています。
その中で、
- 波長が長い → 赤っぽい
- 波長が短い → 青っぽい
という違いがあります。
この光が目に入ると、
網膜が光を受け取る
↓
視神経を通じて脳へ送る
↓
脳が「色」として認識する
という流れで、私たちは色を見ています。
つまり、
色は「光の波」
です。
要するに
音は波で、色は波だから色と音はほぼ同じものだということです。もちろん物理的には全く異なるものですが、ネタLTということでお許しをw
色の表現方法の違いについて
色をプログラムで扱う方法にはいくつかありますが、
代表的なのが
- RGB
- HSV
の2つです。
まずはこの違いを簡単に整理します。
RGBとは
RGBは
- Red(赤)
- Green(緑)
- Blue(青)
の3つの値で色を表現する方法です。
例えば、
(255, 0, 0)
なら赤、
(0, 255, 0)
なら緑、
(255, 255, 255)
なら白になります。
普段Webや画像処理で色を扱うときは、
ほとんどこのRGB形式が使われています。
とても直感的ですが、
「色の変化」
を扱うには少し不便です。
例えば
赤 → オレンジ → 黄色
のような連続的な変化を
RGBの数値だけで捉えるのは意外と難しいです。
HSVとは
一方、HSVは
- Hue(色相)
- Saturation(彩度)
- Value(明度)
で色を表現します。
それぞれの意味は
- Hue:色そのもの(赤・青・緑など)
- Saturation:鮮やかさ
- Value:明るさ
です。
特に重要なのが
Hue(色相)
です。
これは
0° → 赤
120° → 緑
240° → 青
360° → 赤
というように、
色を円として扱う
表現になっています。
これが今回かなり重要になります。
色の表現方法の違いについて
色をプログラムで扱う方法にはいくつかありますが、
代表的なのが
- RGB
- HSV
の2つです。
まずはこの違いを簡単に整理します。
RGBとは
RGBは
- Red(赤)
- Green(緑)
- Blue(青)
の3つの値で色を表現する方法です。
例えば、
(255, 0, 0)
なら赤、
(0, 255, 0)
なら緑、
(255, 255, 255)
なら白になります。
普段Webや画像処理で色を扱うときは、
ほとんどこのRGB形式が使われています。
とても直感的ですが、
「色の変化」
を扱うには少し不便です。
例えば
赤 → オレンジ → 黄色
のような連続的な変化を
RGBの数値だけで捉えるのは意外と難しいです。
HSVとは
一方、HSVは
- Hue(色相)
- Saturation(彩度)
- Value(明度)
で色を表現します。
それぞれの意味は
- Hue:色そのもの(赤・青・緑など)
- Saturation:鮮やかさ
- Value:明るさ
です。
特に重要なのが
Hue(色相)
です。
これは
0° → 赤
120° → 緑
240° → 青
360° → 赤
というように、
色を円として扱う
表現になっています。
これが今回かなり重要になります。
なぜRGBじゃなくてHSVなのか
色をプログラムで扱うとき、普通はRGBを使います。
- Red
- Green
- Blue
の3つですね。
でも、今回はあえてHSVを使いました。
理由はシンプルで、
音に変換しやすいから
です。
音楽には
- ド
- レ
- ミ
- ファ
- ソ
- ラ
- シ
があり、
さらに
オクターブ
という“循環構造”があります。
例えば
ラ → ラ(1オクターブ上)
は別の高さですが、
同じ音名として感じられます。
これが
Hue(色相)の円環構造
とかなり似ています。
つまり、
色相環
↔
音階・オクターブ
という対応が作りやすいわけです。
RGBにはこの循環性がないため、
音への変換には向いていないと判断しました。
だから今回は
HSV、特にHueを使う
という方針にしました。
コード
実際に使ったコードの中心部分はこちらです。
import numpy as np
import sounddevice as sd
from PIL import Image, ImageTk
import tkinter as tk
import math
def hue_to_freq(h, base=440.0): # A4基準
return base * (2 ** (h / 360.0))
def value_to_amp(v):
return v ** 2 # 人間の聴感に合わせて非線形
def saturation_to_timbre(s):
return {
"wave_mix": s, # 0: sine, 1: saw
"fm_index": s * 5
}
def hsv_to_sound(h, s, v):
freq = hue_to_freq(h)
amp = value_to_amp(v)
timbre = saturation_to_timbre(s)
return {
"freq": freq,
"amp": amp,
**timbre
}
def rgb_to_hsv(R, G, B):
r, g, b = R/255.0, G/255.0, B/255.0
mx = max(r, g, b)
mn = min(r, g, b)
delta = mx - mn
# Value
V = mx
# Saturation
S = 0 if mx == 0 else delta / mx
# Hue
if delta == 0:
H = 0
elif mx == r:
H = (60 * ((g - b) / delta)) % 360
elif mx == g:
H = 60 * ((b - r) / delta + 2)
else:
H = 60 * ((r - g) / delta + 4)
return H, S, V
def play_sound(freq, amp, duration=0.5, fs=44100):
t = np.linspace(0, duration, int(fs * duration), False)
wave = np.sin(2 * np.pi * freq * t)
wave *= amp
sd.play(wave, fs)
# --- 画像読み込み ---
img = Image.open("HSV.jpg").convert("RGB")
pixels = np.array(img)
# --- GUI ---
root = tk.Tk()
canvas = tk.Canvas(root, width=img.width, height=img.height)
canvas.pack()
tk_img = ImageTk.PhotoImage(file="HSV.jpg")
canvas.create_image(0, 0, anchor=tk.NW, image=tk_img)
# --- クリック処理 ---
def on_click(event):
x, y = event.x, event.y
R, G, B = pixels[y, x]
H, S, V = rgb_to_hsv(R, G, B)
freq = hue_to_freq(H)
amp = value_to_amp(V)
print(f"RGB=({R},{G},{B}) → H={H:.1f}, V={V:.2f} → {freq:.1f}Hz")
play_sound(freq, amp)
canvas.bind("<Button-1>", on_click)
root.mainloop()
このコードでは、
画像をクリックした場所の色を取得し、
その色を音に変換して再生する
という処理を行っています。
流れとしては
画像をクリック
↓
その場所のRGB値を取得
↓
RGB → HSV に変換
↓
Hue(色相)を周波数に変換
Value(明度)を音量に変換
↓
サイン波を生成
↓
音として再生
という仕組みで音を鳴らしています。
何がうれしいか
今回の仕組みを作ったことで、
色と音を直接連動させる
ことができるようになりました。
例えば
- ペイントで色を塗る
- 動画のワンシーンを切り取る
- 写真をクリックする
だけで、その色に応じた音が鳴ります。
これによって
映像から音楽を作る
という発想が現実的になります。
特に面白いと思ったのは
タイムラプス動画
です。
作業風景やお絵描きの過程を
タイムラプスとして保存し、
その色の変化から自動で音を生成できれば、
映像そのものがBGMを持つ
ような表現ができるかもしれません。
いずれにしても、
「色を聴く」
という新しい視点を持てたことで、
表現の可能性はかなり広がったと思います。
反省
今回は
1オクターブ分
にしか対応できていません。
Hueを360°で1周させているため、
440Hz → 880Hz
までしか扱えていません。
もっと自然な音楽にするには
- 複数オクターブへの対応
- 五度圏へのスナップ
- コード自動生成
などが必要だと思っています。
まだまだ荒削りですが、
「ネタ」からちゃんとした作品になりそう
という感触はありました。
ここからさらに発展させていきたいです。