« ウダー譜作成ソフトUdaFFT |Main| 拡張子のないファイルをtext/htmlにする »

« ウダー譜作成ソフトUdaFFT | UdaFFT | UdaFFTがうまく行かない理由を考察 »

ウダー譜作成ソフト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

トラックバック(Trackback)

Trackback URL: http://www.nishiohirokazu.org/mt/mt-tb.cgi/13

ご意見・ご感想をお送りください(フィードバック)

(フィードバックはメールで送信され、基本的に表示されませんが、内容によっては公開させていただくこともございます。ご了承ください。Your comment doesn't appear the page immediately. If the comment has value to other people, it will be put on the page or subsequent entries. Thank you.)

上の情報は、いずれも未記入でかまいません。 All of above questions are optional.