音楽プログラミングの超入門(仮)

Python / 音楽情報処理 初心者が、初心者にも分かるような記事を書きたい。

『AM』(Arctic Monkeys) のジャケットの解析

『AM』

昨年、Arctic Monkeys の5thアルバム『AM』がリリースされましたが、無茶苦茶格好いいですね。全体的に落ち着いた雰囲気の曲が多く、渋めのアルバムとなっています。

例えば、アルバム1曲目はこんな感じの曲です。

Do I Wanna Know?


PVも格好いいですね。

そして、このアルバムのジャケットがこちら。

imshow

波形があったらフーリエ変換したくならないですか?

というわけで、この波形をフーリエ変換してみます。
(それだけの記事です・・・)

より具体的には、

  1. 上のジャケットの画像を取り込んで、波形に落とし込む
  2. フーリエ変換する
  3. バンドパスフィルタとかかけてみる

みたいなことをしました。

結果

コードは最後らへんに貼っています。

取り出した波形

ジャケットっぽく表示させたので、ほとんどジャケットのまんまですね笑。
imshow

フーリエ変換してみた

簡単のため、横幅(1024ピクセル)を1秒としています。
(なんてフーリエ変換しやすい幅なんだろうか・・)

imshow

見た感じのとおり、20Hz くらいの波のパワーが大きいですね。もっと低い周波数成分もちょっとある感じ。100Hz より上の成分はほぼありませんでした。

バンドパスしてみる

真面目に実装してないですが、簡単にバンドパスしてみて、波形がどう変わるか見てみましょう。

0 ~ 20 Hz

imshow

20 ~ 30 Hz

imshow

組み合わせることで格好良く・・・

imshow
(^^;)

コード

# -*- coding: utf-8 -*-
"""
Analysis of "AM" (Arctic Monkeys) jacket
"""
import Image
from scipy import arange, array, asarray, fft, ifft, transpose, median, where
from scipy.signal import firwin, lfilter
from matplotlib import pylab as pl

### Get wave from AM jacket
def image2wave():
    image = Image.open("../pic_data/am.jpg")
    image = transpose(asarray(image), (1, 0, 2))
    r, c = image.shape[:2]
    print "size : ", r, "x", c
    ret = []
    for row in image:
        ret.append(abs(median(where(row.sum(1) > 760)[0]) - r))
    return array(ret), (r, c)

### ジャケットっぽく表示
def plot_jacket(wave, shape):
    fig = pl.figure(figsize = (9, 9))
    fig.patch.set_alpha(0.)
    ax = fig.add_subplot(111, axisbg='black')
    ax.set_aspect("equal")
    ax.plot(wave, "w", lw = 6)
    ax.set_xlim([0, shape[0]])
    ax.set_ylim([- shape[1] / 2, shape[1] / 2])
    pl.tight_layout()
    pl.show()

### 重ねて表示
def plot_waves(wave1, wave2, wave3, shape):
    fig = pl.figure(figsize = (9, 9))
    fig.patch.set_alpha(0.)
    ax = fig.add_subplot(111, axisbg='black')
    ax.set_aspect("equal")
    ax.plot(wave1, "w", lw = 6)
    ax.plot(wave2, "#4169e1", lw = 4)
    ax.plot(wave3, "#dc143c", lw = 4)
    ax.set_xlim([0, shape[0]])
    ax.set_ylim([- shape[1] / 2, shape[1] / 2])
    pl.tight_layout()
    pl.show()

### 横幅を1秒とする
def fft_am(wave, L, plot_index = 100):
    spectrum = fft(wave)
    fig = pl.figure()
    fig.patch.set_alpha(0.)
    fig.add_subplot(111)
    pl.plot(abs(spectrum)[: plot_index])
    pl.xlabel("Frequency [Hz]", fontsize = 15)
    pl.ylabel("Amplitude", fontsize = 15)
    pl.tight_layout()
    pl.show()

### ウルトラ適当なバンドパス
def bandpass(wave, low, up, fs = 1024):
    up = min(up, fs / 2 - 1)
    low = max(low, 1)
    spec = fft(wave)
    spec[1 : low + 1] = 0
    spec[- low :] = 0
    spec[up + 1 : - up] = 0
    ret = ifft(spec).real
    return ret

if __name__ == "__main__":
    wave, shape = image2wave()
    ### 位置合わせ
    wave = wave - shape[0] / 2

    plot_jacket(wave, shape)
    fft_am(wave, shape[1])

    wave2 = bandpass(wave, 20, 30)
    wave3 = bandpass(wave, 0, 20)
    # plot_jacket(bp_wave, shape)
    plot_waves(wave, wave2, wave3, shape)