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?

色と音を音に変換する

0
Posted at

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

までしか扱えていません。

もっと自然な音楽にするには

  • 複数オクターブへの対応
  • 五度圏へのスナップ
  • コード自動生成

などが必要だと思っています。

まだまだ荒削りですが、

「ネタ」からちゃんとした作品になりそう

という感触はありました。
ここからさらに発展させていきたいです。

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?