メイン | 2006年04月 »

2006年03月31日

DownloadableYouTube

This is a bookmarklet to make all link from YouTube search result downloadable.

How to use

Bookmark this link. (Right-click the link and add to bookmark.) And then click the bookmark on a search result of YouTube. So all links change not to a browse page but to a download cgi. You can save the movie with right-clicking them and choose "save as..".

How to see the downloaded files

The format of those movies is *.FLV (Flash Movie), so you need a flv player. If you don't have it, get "Free Riva FLV Player 1.2" from Riva VX: Downloads.

How it works

An URL like "http://www.youtube.com/watch?v=********" is a page to browse movie. The bookmarklet replace all url like above to like "http://youtube.com/get_video.php?video_id=********". It is a cgi to get movie.

I made this on a Firefox, and I didn't check its behavior on IE.

Pythonで「お気に入れっと」

概要

これはインターネットエクスプローラーの「お気に入り」に入れておくことで、エクスプローラで開いているフォルダをコマンドプロンプトで開くのが楽になるPythonスクリプトです。

スクリーンショット

wshpython1.png

wshpython2.png

ソースコード

import win32com.client
import os

shell = win32com.client.Dispatch("Shell.Application") 
ie = shell.Windows().Item()
folder = ie.Document.Folder
path = str(folder.Items().Item().Path)

os.system("cmd /k cd " + path)

解説

あらかじめ、このスクリプトを適当な場所に*.pysという拡張子で保存し、IEのお気に入りフォルダにそのスクリプトへのショートカットを入れておきます。ショートカットの名前は「コマンドプロンプトで開く」にしたものとします。任意のフォルダでお気に入りから「コマンドプロンプトで開く」を選ぶと、そのフォルダがカレントディレクトリになったコマンドプロンプトが立ち上がります。

これは後輩に 吉岡 照雄ViewFolder.VBSを見せてもらって、ブックマークレットのようなものがローカルのエクスプローラーのお気に入りで動いていることに驚き、Pythonでこの機能を利用して面白いことが出来ないかと試してみた物です。最初はWSH(Windows Script Host)の機能だと思っていったので、拡張子pysをWSHの実行ファイルであるc:\windows\system32\cscript.exeに関連づけています。しかし、「現在開いているフォルダ」の情報を取得するのは別にWSHとは関係ないようで、単純に*.pyを起動しても同じ結果が得られます。なお、実行にはPythonとwin32allのインストールが必要です。

開いているフォルダの取得がなぜこの方法で出来るかなどについては、ViewFolder.vbsに添付の解説資料が詳しいです。

2006年03月30日

Pythonで特定条件のファイルを検索

後輩の質問に答えたついでにエントリーとして公開します。 「指定したフォルダ以下で最後の3文字が".py"であるようなファイルを探す」という程度のスクリプトなら数行で書けます。

import os
for (root, dirs, files) in os.walk(r"c:\home\Projects"):
	for f in files:
		if f[-3:] == ".py":
			print f, root

これを利用して、「特定のフォルダ以下にある全部のresult.txtを、"そのフォルダの名前.txt"という名前でresultFilesというフォルダにコピー」というスクリプトを作ると以下のようになります。

import os, shutil
for (root, dirs, files) in os.walk(r"."):
    print root
    for f in files:
	if f == "result.txt":
            folderName = os.path.split(root)[-1]
            shutil.copy(
                os.path.join(root, f),
                os.path.join("resultFiles", "%s.txt" % folderName))

print "ok."			

2006年03月28日

拡張子のないファイルをtext/htmlにする

先日スナップショットを取ったCOREBlogの記事をXREAにアップロードしてみたところ、拡張子のないファイルのデフォルトのMIMEタイプがtext/plainになっているようでHTMLがそのまま表示されてしまいました。.htaccessに以下のように書いて解決しました。

<FilesMatch "^[^.]+$">
	ForceType text/html
</FilesMatch>

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

2006年03月26日

ウダー譜作成ソフトUdaFFT

Waveファイルからウダー譜を作成するPythonスクリプトを公開します。

ウダーとは?

宇田道信さんが開発した螺旋上を指で押さえて演奏する新しい楽器です。1周で1オクターブで、半音より小さい間隔の音も出すことが出来ます。

ウダー譜とは?

宇田さんが考案した、新しい音楽の表記方法です。ウダー同様に1周で1オクターブになっています。軽く探してみましたがまだネット上にスクリーンショットなどはないようです。

ウダー譜作成ソフトUdaFFTとは?

宇田さん本人によるMIDIをウダー譜で表示するプログラムを拝見した筆者が勝手に作ったWAVをウダー譜で表示するプログラムです。

コンセプト

従来の五線譜は直感的ではありません。同じ位置にある音符が、行頭で宣言されているシャープやフラットといった記号の違いで違う音になります。また、同じ和音であっても根音の違いによって五線譜の上での表記は異なったものになります。ウダー譜では同じ和音は同じ形で表されます。また、まだ普及版ウダーが販売されていないので実践は出来ませんが「ウダー譜に表示されているとおりに押さえれば出したい音が出る」という点が五線譜にはないメリットになるでしょう。既存の音楽ファイルをウダー譜に変換するプログラムがあれば、見たとおりに弾くだけで聞いたとおりの音が出るはずです。

まぁ、理由付けはさておき、筆者はウダー譜に美を感じており、ウダー譜でカノンを表示すると美しいのではないか、ウダーでカノンを弾くと楽しいのではないか、と考えています。

UdaFFT Ver0.1

現時点では残念ながら簡単に使っていただけるような形になっていません。まずSoundEngine Freeなどを使って8bitモノラルのWAVファイルを用意します。それをUdaFFT Ver0.1にかけると0.1秒あたり1枚のBMPファイルが出力されます。それをAVIMakerを使って無圧縮AVI形式の動画にし、携帯動画変換君を使ってH.264形式の動画に変換しています。最新のQuickTimeで見ることが出来るはずです。実行にはPython Japan User's Groupと、numarrayPython Imaging Library (PIL)のインストールが必要です。

原理

まずWavファイルの波形のデータから周波数ごとの強さのデータを作るためにフーリエ解析を用います。フーリエ解析は自分で実装してもいいですが、すでにいろいろな言語で高速フーリエ解析(FFT)の実装があるのでそれを参考にするのもいいでしょう。Mathtools.net : Java/FFT。UdaFFT Ver0.1ではnumarrayというライブラリのFFTモジュールを利用しています。38-39行目で、音の波形データから0.1秒分を切り出し、それをフーリエ解析した結果の絶対値を計算して周波数ごとの音の強さを求めています。「0.1秒」という長さは適当に決めました。

13行目:
from numarray import FFT
38-39行目:
    f = data[start : start + framePerStep]
    s = [abs(v) for v in FFT.fft(f)]

元のWavファイルのサンプリングレートが44KHzであれば0.1秒分で約4400個のサンプルがFFTに渡されることになります。FFTの結果sは、s[1]が「0.1秒で1周するような周期の強さ」、s[2]が「0.1秒で2周するような周期の強さ」になっています。つまり周波数に直すとそれぞれ1秒で10周するので10Hz、1秒で20周するので20Hz…となります。UdaFFT Ver0.1では41行目で周波数を求めた後、42行目でその周波数が200未満の場合と3200以上の場合を思い切って捨てています。目的の音以外のノイズを表示しないように、という意図です。この下限上限は適当に決めました。

41-42行目:
        freq = frameRate * j / framePerStep
        if freq < 200 or freq > 3200: continue

さて、周波数ごとの音の強さが求まったところで、次はこれをオクターブごとにまとめましょう。1オクターブ上がると周波数は2倍になります。2オクターブなら4倍です。周波数の比から、それが何オクターブ分に当たるかを計算するには対数を使います。UdaFFT Ver0.1では43行目で対数を使って周波数freqが真ん中のラから見て何オクターブ離れたところにあるかを計算しています。式の最後の「+5」は特に重要な意味はなく、負の数を切り捨てた場合の挙動を調べるのが面倒だったので全部正の数になるように足したものです。

43行目:
        l = log(freq / FREQ_CENTER_A) / log(2) + 5

UdaFFT Ver0.1はこの後、この値を1オクターブ64個の音階に丸めていますが、これは改善の余地があると思います。

最後に音階から画面上の位置への変換について説明します。先ほど対数で求めた値lの整数部分はオクターブの情報なので、「l - int(l)」とやって小数部分を取り出します。この値が0~1で0度~360度に対応するので、360を掛ける…と言いたいところですが、度ではなくてラジアンを使う言語の方が多いのでここは2π(6.283)を掛けます。この「ラジアン表記された角度」から画面上の位置x, yを求めるには、三角関数を使います。今回は0ラジアンのラが時計で9時の位置に来て時計回りに値が増えるようにします。そうするとラどドの間が3半音なのでドが12時の位置に来ます。0ラジアンのラが9時の位置に来るということは、左上隅が原点のスクリーン座標系では円の中心から見てX軸方向にマイナスでY軸方向に0ということです。sin(0)は0でcos(0)は1なので、X座標の値は「中心のX座標 - 半径 × cos(ラジアン)」となります。次に、0.1ラジアンの場合を考えると、時計回りなのでXが少し増えてYが少し減ります。sin(x)は0のそばではxが増えるとsin(x)も増えます。つまりY座標の値もマイナスがついて「中心のY座標 - 半径 × sin(ラジアン)」となるわけです。

サンプル動画

ドレミ(219KB)、 肉声(1.17MB)

iTunesか最新のQuickTimeをインストールしている必要があるかと思います。

既知の問題点と今後の方針

  • 人間の声は想像以上に倍音成分が多いようです。根音から見て7時の位置に二つめの音符が出てしまいます。
    • 和音と倍音の区別は難しいように思います。和音の表示をあきらめれば「一番強い音のところにだけ音符を表示する」という解決策も考えられます。
  • どのくらいの音の大きさを白(255)にするかを手動で設定しなければならない。
    • 「直前のステップで一番強かった音の強さ × 0.8」を上限にすれば柔軟に対応できるかも?
  • オクターブの情報を捨てている。
    • 宇田さんのソフトでは丸の大きさでオクターブの違いを表現している。
  • ウダー譜を得るまでの操作がかなり面倒。
    • Javaで実装して宇田さんのソフトに組み込んでもらう?
    • WindowsMediaPlayerの視覚エフェクトとして実装するのが楽かも知れない。MSDNによれば、フーリエ解析を視覚エフェクトがやらなくても周波数ごとの強さのデータを取得できるようです。

ソースコード

ウダー及びウダー譜の普及に少しでも役立てるように、以下のソースコードに関しては商用・非商用を問わず複製・改変・頒布を認めます。

# -*- coding: cp932 -*-
#
# UDA-FFT
#
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
framePerStep = frameRate / 10 # 0.1 sec
numStep = nFrames / framePerStep
NOTE_PER_OCTAVE = 64
RENDER_LENGTH = numStep # 通常numStep、デバッグ時は減らして軽くする
FREQ_CENTER_A = 440.0 # 真ん中のラ

data = wav.readframes(RENDER_LENGTH * framePerStep)
print clock() - startTime

print "RENDER_LENGTH:", RENDER_LENGTH
powerMap = {}
for i in range(RENDER_LENGTH): 
    start = framePerStep * i
    f = data[start : start + framePerStep]
    s = [abs(v) for v in FFT.fft(f)]
    for j in range(1, len(s)):
        freq = frameRate * j / framePerStep
        if freq < 200 or freq > 3200: continue
        l = log(freq / FREQ_CENTER_A) / log(2) + 5
        angle = int(NOTE_PER_OCTAVE * (l - int(l))) / float(NOTE_PER_OCTAVE)
        th = 2 * pi * angle
        v = s[j]
        if powerMap.has_key(i) and powerMap[i].has_key(th):
            powerMap[i][th].append(v)
        else:
            if powerMap.has_key(i):
                powerMap[i][th] = [v]
            else:
                powerMap[i] = {th: [v]}
    if i % 100 == 0: print i, "analysed"
wav.close()
print clock() - startTime

r = 10
SCALE = 750
LBOUND = 100
INNER_RADIUS = 40
PIXEL_PER_STEP = 15

for start in range(RENDER_LENGTH - 10):
    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(10):
        
        rad = INNER_RADIUS + r + i * PIXEL_PER_STEP
        for th in powerMap.get(start + i, []):

            x = int(RADIUS - rad * cos(th))
            y = int(RADIUS - rad * sin(th))

            v = powerMap[start + i][th]
            light = max(v) / 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

2006年03月24日

MTに「リンクを張るためのタグをクリップボードに入れるボタン」を追加

MovableTypeは「テンプレート」をいじることでいろいろなカスタマイズが出来るようです。今回はワンクリックでリンク用のタグを生成するボタンを作成してみました。このエントリーのPermalinkの隣にあるものがそれです。

<script type="text/javascript" src="<$MTBlogURL$>setClipboard.js"></script>
<script>
	function setTag(){
		url = "<$MTEntryPermalink$>";
		title = "<$MTEntryTitle remove_html="1"$>";
		setClipboard('<a href ="' + url + '">' + title + '</a>');
	}
</script>

このsetClipboard.jsはhttp://la.ma.la/misc/js/setclipboard.txtを保存してBlogのルートディレクトリにおいたものです。 あとはボタンを起きたい場所に以下のように記述します。

<input type="button" value = "a" onClick="setTag();">

これで、リンクを張るときはボタンを押すだけでタグがクリップボードにコピーされます。

MTで表示しているエントリの編集画面を出すブックマークレット

あらかじめテンプレートをいじってエントリーに下記のJavaScriptを入れておきます。

entryid = perseInt("<$MTEntryID pad="1"$>", 10);

あとは新しいブックマークを作ってURLを下のようにするだけです。

javascript: document.location = "http://○○○/mt.cgi?__mode=view&_type=entry&blog_id=×&id="+entryid;

なお○○○はmt.cgiのあるURL、×は自分のブログが1つだけなら1で構わないでしょう。複数個を同時に管理しているのならばblog_idもJavaScriptで埋め込むといいのではないでしょうか。


追記

いま見ているエントリーを編集する Bookmarkletに同じ目的のブックマークレットがありました。なるほど、こういう情報の取り出し方もあるのですね。勉強になりました。

2006年03月23日

TagTrace ver0.2(English)

"TagTrace" is a bookmarklet to make easy to customize CSS.

Feature

  • Highlight mouse-overed tag to show its bounds.
  • Show the name, class and ID of mouse-overed tag in tooltip text.
  • Show tag hierarchy from clicked tag to HTML tag in the bottom of the page.

How to use

Download following script, upload it and make bookmark to

javascript:(function(){var s=document.createElement("script");s.charset="UTF-8";s.src="http://www.nishiohirokazu.org/testJS/tagTrace.js";document.body.appendChild(s)})();

Here "http://www.nishiohirokazu.org/testJS/tagTrace.js" is the position which you upload the script.

Or simply bookmark this.

The latter method use the script on my server, so it will change its behavior or stop its activity.

Known problem

  • When you clicked button, link etc. its ORIGINAL function works before the tag trace. The original function must be disabled with some techniques.

Source code

Download
colorArray=new Array();
borderArray=new Array();
currentTag = undefined;
tagTrace = undefined;

tags = document.getElementsByTagName('*');
for(i = 0; i < tags.length; i++){
	tag = tags[i];
	t = tag.tagName;
	if(tag.className != ""){
		t += "." + tag.className;
	}
	if(tag.id != ""){
		t += "#" + tag.id;
	}
	tag.title = t;
	
	tag.onmouseover=function(){
		if(currentTag){
			return;
		}
		currentTag = this;
		t=this;
		colorArray[t]=t.style.background;
		borderArray[t]=t.style.border;
		t.style.background='#DAFADA';
		t.style.border='solid';
	};
	tag.onmouseout = function(){
		t=this;
		t.style.background=colorArray[t];
		t.style.border=borderArray[t];
		currentTag = undefined;
	};
	tag.onclick = function(){
		t = this;
		if(!tagTrace){
			tagTrace = ""
		}
		tagTrace += t.title + "\n";

		var tmp = document.createElement("div");
		tmp.innerHTML = t.title + "\n";
		document.body.appendChild(tmp);

		if(!t.parentNode){
			alert(tagTrace);
			tagTrace = undefined;
		}
	};
}

TagTrace ver0.2

先日スタイルシートいじりで作ったBookmarkletを公開します。JavaScriptは1ヶ月前にBookmarkletのおもしろさを知って始めたばかりで、まだまともな文法書も読んだことがないので、いろいろとまずいところもあるかと思います。お気づきの点があれば、ご指摘いただけましたら幸いです。

機能

  • マウスオーバーしたタグのスタイルを一時的に変更してどの範囲がそのタグかわかりやすくする。
  • マウスオーバーしたタグの種類とクラス、IDをツールチップテキストで表示する。
  • マウスクリックでそのタグを起点に、親のタグを順番にたどってページ末尾に表示する。

使い方

下記のスクリプトを適当な名前で適当なサーバにアップロードし、 「bookmarkletの文字数制限を無くす」を参考にしてそのスクリプトを呼び出すブックマークレットを作る。 もしくはこちらのリンクをブックマークに追加する。 後者の方法ではこのサーバに置かれたJavaScriptを呼び出すので、今後挙動が変化したり、使えなくなったりする可能性があります。

既知の問題点

  • ボタン、リンクなどをクリックした場合は「本来の挙動」が動いてしまう。何らかの方法で無効化する必要がある。

ソースコード

ダウンロード
colorArray=new Array();
borderArray=new Array();
currentTag = undefined;

tags = document.getElementsByTagName('*');
for(i = 0; i < tags.length; i++){
	tag = tags[i];
	t = tag.tagName;
	if(tag.className != ""){
		t += "." + tag.className;
	}
	if(tag.id != ""){
		t += "#" + tag.id;
	}
	tag.title = t;
	
	tag.onmouseover=function(){
		if(currentTag){
			return;
		}
		currentTag = this;
		t=this;
		colorArray[t]=t.style.background;
		borderArray[t]=t.style.border;
		t.style.background='#DAFADA';
		t.style.border='solid';
	};
	tag.onmouseout = function(){
		t=this;
		t.style.background=colorArray[t];
		t.style.border=borderArray[t];
		currentTag = undefined;
	};
	tag.onclick = function(){
		t = this;
		var tmp = document.createElement("div");
		tmp.innerHTML = t.title + "\n";
		document.body.appendChild(tmp);
	};
}

2006年03月13日

English test

Sometime I want to write entries in English because some information is usefull in all over the world. Maybe my English is not so good but it is not much problem.