ウダー譜作成ソフトUdaFFT ピークだけ表示するバージョン
先日作成したウダー譜作成ソフトUdaFFTの、ピーク部分にだけ音符を表示するバージョンを作成したので公開します。
サンプル動画(712KB)
思ったほど見やすくならなかったのが残念です。特に旋律の短い音が連続するところでは音符があちこちに飛び散ってしまってどれが先に落ちてくるのかわかりづらいです。
ソースコード
# -*- coding: cp932 -*-
#
# UDA-FFT peak only version
#
from time import clock
startTime = clock()
import os
import wave
import Image
import ImageDraw
from math import sqrt, pi, log, sin, cos
from numarray import FFT
PROJECT_DIR = r"c:\Home\Projects\UdaFFT"
INPUT_WAVE = "hana-8bitM.wav" # 8-bit モノラル
OUTPUT_DIR = "bmps"
wav = wave.open(os.path.join(PROJECT_DIR, INPUT_WAVE))
(nChannels, sampWidth, frameRate, nFrames, compType, compName) = wav.getparams()
RADIUS = 256
SIZE = RADIUS * 2
print frameRate
FramePerSecond = 20
framePerStep = frameRate / FramePerSecond # 0.1 sec
numStep = nFrames / framePerStep
RENDER_LENGTH = numStep # 通常numStep、デバッグ時は減らして軽くする
FREQ_CENTER_A = 440.0 # 真ん中のラ
data = wav.readframes(RENDER_LENGTH * framePerStep)
print clock() - startTime
print "RENDER_LENGTH:", RENDER_LENGTH
peakList = []
for i in range(RENDER_LENGTH):
start = framePerStep * i
f = data[start : start + framePerStep]
s = [abs(v) for v in FFT.fft(f)]
peakValue = max(s[220 / FramePerSecond : 880 / FramePerSecond])
peakPos = s.index(peakValue)
freq = FramePerSecond * peakPos
l = log(freq / FREQ_CENTER_A) / log(2) + 5
angle = l - int(l)
th = 2 * pi * angle
peakList.append((th, peakValue))
if i % 100 == 0: print i, "analysed"
wav.close()
print clock() - startTime
peakList += [(0, 0)] * FramePerSecond # 末尾に1秒分の余白
r = 10
SCALE = 750
LBOUND = 100
INNER_RADIUS = 40
PIXEL_PER_STEP = (RADIUS - INNER_RADIUS) / FramePerSecond
for start in range(RENDER_LENGTH):
image = Image.new("L", (SIZE, SIZE))
d = ImageDraw.Draw(image)
d.ellipse([(RADIUS - INNER_RADIUS, RADIUS - INNER_RADIUS),
(RADIUS + INNER_RADIUS, RADIUS + INNER_RADIUS)],
LBOUND)
for i in range(FramePerSecond):
rad = INNER_RADIUS + r + i * PIXEL_PER_STEP
(th, value) = peakList[start + i]
x = int(RADIUS - rad * cos(th))
y = int(RADIUS - rad * sin(th))
light = value / SCALE
if light > LBOUND:
d.ellipse([(x - r, y - r),
(x + r, y + r)],
light)
image.save(os.path.join(PROJECT_DIR, OUTPUT_DIR, "%04d.bmp" % start), "BMP")
if start % 100 == 0: print start, "outputed"
print "OK."
print clock() - startTime