SVX日記
2004-10-23(Sat) SVX入院……
SVXの修理のために、近所のスバルに行くことにする。その前に、なんとなくボンネット開けたりして、バッテリの電圧を測るってみたら12Vチョイ。……つーか、測ったの初めてだから正常なのかわからん。確かに定格は12Vだけど、セルの回りがシブさからしてかなり弱っているような気がする。
相変わらずの症状で車体をガクガクさせつつ、カミさんを乗せてスバルに向かう。ギアがローに落ちないのか、妙に出足が悪いので右折の際にヒヤヒヤしつつ、なんとかスバルに到着。中でお待ちくださいといわれたので、R2のパンフなんかをパラパラしていると、おいらのSVXが出て行くのが見えた。試運転か? なんでもいいけど、あの状態であまりハデに走って欲しくないんだがなぁ。そりゃ走らんと症状も確認できんのはわかる。しかしSVXのATはガラスのATなのだ。そいつを妙なパターンでガシガシとチェンジする今の狂っている状態で走り回ったら、そっちまでイカレるではないか。いや、そりゃ走らんと症状も確認できんのはわかっているのだ。わかっているが、やっぱりATまでイカレたらどーする!? あ゛ー、ぢれんま゛ー。
気が気でないまま、ただ帰ってくるのを待つ。待っているとこれまたエラく長い……。やっと帰ってきた。サービスいわく「バッテリが弱ってますね、それ以外はちょっとまだわかりません」とのこと。で、なんでまた黙ってSVXが出て行くかなぁ。試運転ならさっきしたやん。もー、カンベンしてくれー。
結局、バッテリーを替えてからまた様子を見るということで、入院させることになった。バッテリーの手配には若干時間がかかるとの事。はぁ……ブルー。スバルだけにワールドラリーブルーである。近所なので散歩がてら歩いて帰る。とぼとぼ。図書館に寄って何冊か本を借り、デパートで雨傘(75cm巨大サイズ)を買いつつ、帰宅。別に2週間くらいSVXに乗らないこともあるというのに、なんだこの喪失感は。うがー。
こんなときは工作でもして気を紛らすに限る。先日修理したワイヤレスヘッドフォンの耳当てでも作ってやろう。カミさんに適当な布をくれといったら、ボロいハンドタオルを出してくれた。これが意外と厚手でこれなら綿を詰めなくてもよさそうだ。型紙を切って、一回り大きく布を切り抜き、周囲を荒く波縫いして、耳当て部分に被せて、糸を絞って終わり。それだけのことだが、意外とうまくいった。
早速装着してみると、これがもう思いのほかサイコーである。耳に当たるタオル地がムチャ気持ちいいのだ。音も特に曇ったようには感じない。オーディオマニアにはチャンチャラと笑われてしまいそうなので、さすがにオーデヲ振って(?)見せられないが、こんなかけ心地のいいヘッドホンは他にないぞ。マジで、マジで、マジで。
2009-10-23(Fri) OpenSuSEのRubyもncursesw化する
opensuse-11.1:/root # cat /etc/SuSE-release
openSUSE 11.1 (x86_64)
VERSION = 11.1
縁起物なので、YaSTでRubyパッケージを「ruby-1.8.7.p72-5.4.1」にアップデートする。
opensuse-11.1:/root # wget http://download.opensuse.org/source/distribution/11.1/repo/oss/suse/src/ruby-1.8.7.p72-5.3.src.rpm
opensuse-11.1:/root # rpm -ivh ruby-1.8.7.p72-5.3.src.rpm
opensuse-11.1:/root # rpmbuild -bp /usr/src/packages/SPECS/ruby.spec
error: Failed build dependencies:
gdbm-devel is needed by ruby-1.8.7.p72-5.3.x86_64
gperf is needed by ruby-1.8.7.p72-5.3.x86_64
readline-devel is needed by ruby-1.8.7.p72-5.3.x86_64
tk-devel is needed by ruby-1.8.7.p72-5.3.x86_64
YaSTで各パッケージを導入。こういうトコが、GUIって、却って面倒いな。
opensuse-11.1:/root # rpmbuild -bp /usr/src/packages/SPECS/ruby.spec
opensuse-11.1:/root # cd /usr/src/packages/BUILD/ruby-1.8.7-p72/
opensuse-11.1:/usr/src/packages/BUILD/ruby-1.8.7-p72 # cd ext/curses/
opensuse-11.1:/usr/src/packages/BUILD/ruby-1.8.7-p72/ext/curses # ruby extconf.rb
mkmf.rb can't find header files for ruby at /usr/lib64/ruby/ruby.h
YaSTで「ruby-devel」を導入。
opensuse-11.1:/usr/src/packages/BUILD/ruby-1.8.7-p72/ext/curses # ruby extconf.rb
opensuse-11.1:/usr/src/packages/BUILD/ruby-1.8.7-p72/ext/curses # make
opensuse-11.1:/usr/src/packages/BUILD/ruby-1.8.7-p72/ext/curses # diff -c curses.c.org curses.c
*** curses.c.org Fri Oct 23 20:35:30 2009
--- curses.c Fri Oct 23 20:47:21 2009
***************
*** 15,20 ****
--- 15,21 ----
#include "ruby.h"
#include "rubyio.h"
+ #include "locale.h"
#if defined(HAVE_NCURSES_H)
# include
***************
*** 1441,1446 ****
--- 1442,1449 ----
void
Init_curses()
{
+ setlocale(LC_ALL, "");
+
mCurses = rb_define_module("Curses");
mKey = rb_define_module_under(mCurses, "Key");
opensuse-11.1:/usr/src/packages/BUILD/ruby-1.8.7-p72/ext/curses # diff -c extconf.rb.org extconf.rb
*** extconf.rb.org Fri Oct 23 20:35:30 2009
--- extconf.rb Fri Oct 23 20:40:12 2009
***************
*** 1,15 ****
require 'mkmf'
dir_config('curses')
! dir_config('ncurses')
dir_config('termcap')
make=false
have_library("mytinfo", "tgetent") if /bow/ =~ RUBY_PLATFORM
have_library("tinfo", "tgetent") or have_library("termcap", "tgetent")
! if have_header(*curses=%w"ncurses.h") and have_library("ncurses", "initscr")
make=true
! elsif have_header(*curses=%w"ncurses/curses.h") and have_library("ncurses", "initscr")
make=true
elsif have_header(*curses=%w"curses_colr/curses.h") and have_library("cur_colr", "initscr")
curses.unshift("varargs.h")
--- 1,15 ----
require 'mkmf'
dir_config('curses')
! dir_config('ncursesw')
dir_config('termcap')
make=false
have_library("mytinfo", "tgetent") if /bow/ =~ RUBY_PLATFORM
have_library("tinfo", "tgetent") or have_library("termcap", "tgetent")
! if have_header(*curses=%w"ncurses.h") and have_library("ncursesw", "initscr")
make=true
! elsif have_header(*curses=%w"ncurses/curses.h") and have_library("ncursesw", "initscr")
make=true
elsif have_header(*curses=%w"curses_colr/curses.h") and have_library("cur_colr", "initscr")
curses.unshift("varargs.h")
opensuse-11.1:/usr/src/packages/BUILD/ruby-1.8.7-p72/ext/curses # make distclean
opensuse-11.1:/usr/src/packages/BUILD/ruby-1.8.7-p72/ext/curses # ruby extconf.rb
opensuse-11.1:/usr/src/packages/BUILD/ruby-1.8.7-p72/ext/curses # make
opensuse-11.1:/usr/src/packages/BUILD/ruby-1.8.7-p72/ext/curses # cd /usr/lib64/ruby/1.8/x86_64-linux
opensuse-11.1:/usr/lib64/ruby/1.8/x86_64-linux # mv curses.so curses.so.org
opensuse-11.1:/usr/lib64/ruby/1.8/x86_64-linux # cp /usr/src/packages/BUILD/ruby-1.8.7-p72/ext/curses/curses.so .
1 #!/usr/bin/ruby
2
3 require "curses"
4
5 Curses.init_screen
6 begin
7 s = "こんにちは、世界!"
8 Curses.setpos(Curses.lines / 2, Curses.cols / 2 - (s.length / 2))
9 Curses.addstr(s)
10 Curses.refresh
11 Curses.getch
12 ensure
13 Curses.close_screen
14 end
こんにちは、世界!
2011-10-23(Sun) uPC2002アンプ、動作
今日は朝からガキのイベントに付き合って散歩(スタンプラリー)に出かける。と、偶然、会場でミニ四駆のイベントを見て驚いた。恐ろしく速い。飛んできて、当たったら、ケガするレベル。でも、あれだけ速いからこそ、趣味として取り組む余地があるのだろうな。なるほどね。
2013-10-23(Wed) チープなDTMアプリ・改二
ふと思い立って、三度、以前に自作したDTMアプリを引っ張り出してきた。2年半ぶりくらいだ。当時の環境はFedora12だったようだが、現在はMint15だ。Rubyも1.8から1.9になっている。そして……
$ padsp -d ./melod
utils/padsp.c: dsp_open()
utils/padsp.c: fd_info_new()
utils/padsp.c: dsp_open() succeeded, fd=5
utils/padsp.c: sample spec: u8 1ch 8000Hz
utils/padsp.c: fixated metrics to 12 fragments, 1024 bytes each.
7fff0009
utils/padsp.c: freeing fd info (fd=5)
utils/padsp.c: Draining.
./melod:24:in `ioctl': integer 3221508106 too big to convert to `int' (RangeError)
from ./melod:24:in `block in <main>'
from ./melod:17:in `open'
from ./melod:17:in `<main>'
まず、前回とエラーの内容が変わっている。発生箇所は、前回と同じく、サウンドデバイスへのioctlではあるが、サウンドデバイス側でなく、Ruby側でエラーこいている感じ。どうも、ioctlへ渡す引数が32bit intとして定義されているのが原因っぽい。
渡したいのは、0xc004500a(SNDCTL_DSP_SETFRAGMENT)等なので、unsignedでないと通りえない。前回は「勝手に64bit拡張して渡してしまうRuby」側の問題だと思いつつ、padsp側にパッチを当てて回避したが、これではRuby側に修正を入れるほかない……悪化しとるがな。
< p dsp.ioctl(0xc004500a, x) # SNDCTL_DSP_SETFRAGMENT
---
> p dsp.ioctl(0xc004500a - 0x100000000, x) # SNDCTL_DSP_SETFRAGMENT
$ padsp -d ./melod
utils/padsp.c: dsp_open()
utils/padsp.c: fd_info_new()
utils/padsp.c: dsp_open() succeeded, fd=5
7fff0009
utils/padsp.c: unknowned ioctl 0xffffffffc004500a
utils/padsp.c: freeing fd info (fd=5)
utils/padsp.c: Draining.
./melod:24:in `ioctl': Invalid argument - /dev/dsp (Errno::EINVAL)
from ./melod:24:in `block in <main>'
from ./melod:17:in `open'
from ./melod:17:in `<main>'
おぉ、前回と同じ結果になった。ゴマかして通すことには成功したといえよう。あとは前回と同じくpadspにパッチを当てれば回避できるだろう……が、Ubuntu系の修正ビルドはやったことがない。やってみる。
~ # cd /etc/apt/sources.list.d
sources.list.d # cp official-package-repositories.list official-package-repositories.sources.list
sources.list.d # vi official-package-repositories.sources.list
sources.list.d # apt-get update
sources.list.d # cd
~ # aptitude install dpkg-dev
~ # aptitude install devscripts
~ # mkdir build
~ # cd build
build # apt-get source pulseaudio-utils
build # cd pulseaudio-3.0/src/utils
utils # vi padsp.c
utils # cd ../..
pulseaudio-3.0 # dpkg-source --commit
Enter the desired patch name: 9999-padsp4ruby.patch
pulseaudio-3.0 # dch -i
* Add patch to padsp for ruby.
pulseaudio-3.0 # debuild -uc -us
pulseaudio-3.0 # debuild -uc -us
pulseaudio-3.0 # cd ..
build # dpkg -i pulseaudio-utils_3.0-0ubuntu7_amd64.deb
build # dpkg -i libpulsedsp_3.0-0ubuntu7_amd64.deb
パッケージを置いておく。しかし、Ruby1.9へのリライトもだいぶ慣れてきたな。
2015-10-23(Fri) 例のWi-Fiを試してみる
先日、ハンダ付けは終わらせたのだが、手元には5VのUSB-シリアル変換モジュールしかない。よっこらせっとレベルコンバータを作って接続してみた。
シリアルアクセスはどうしようかと思ったが、古いMintのArduino IDEのシリアルモニタで十分だった。シリアルモジュール/レベルコンバータを接続、「chmod 666 /dev/ttyUSB*」でパーミッションを変更。Arduino IDEの、ツール、シリアルポートで/dev/ttyUSB0を選択。ツール、シリアルモニタを起動。右下のメニューから、CRおよびLF、115200bpsを選択。ESP8266の電源をON。あとはシリアルモニタから、ATコマンドで、無線LANアクセスポイントに接続すればいい。
さて、とりあえず、しょっちゅうLANの接続が切れてうっとおしい、自作のXPort-XBeeルータでも、これで置き換えてみようかな。
2023-10-23(Mon) WebAssemblyでイメージを操作
というわけで「WebAssemblyのひとつだけの使い道」のプログラミングを始めた。やりたいのは要するにイメージの操作だ。単純な計算を山ほどループで繰り返す。実にWebAssembly向きの処理である。
いきなりだが、以下が機械語サブルーチン部分。イメージを表すRGBAの羅列を渡すと、GとBを抜いてくれるというもの。だいぶカリカリにチューン済み。結局、ループの最適解は減算&非ゼロ判定だな。それはそうと、見慣れないニーモニックが入っている。
(module
(import "js" "mem" (memory $mem 1))
;; filter(ソースの末尾 + 1 のアドレス)
(func (export "filter") (param $src_adr i32)
(local $dst_adr i32)
push src_adr ;; dst_adr = src_adr << 1
i32.push 1
i32.shl
pop dst_adr
loop1: loop
push dst_adr ;; dst_adr -= 4
i32.push 4
i32.sub
pop_push dst_adr ;; [ dst_adr
push src_adr ;; src_adr -= 4
i32.push 4
i32.sub
pop_push src_adr ;; [ dst_adr src_adr
i32.load ;; [ dst_adr color
i32.push 0xFF0000FF ;; [ dst_adr color mask
i32.and ;; [ dst_adr color
i32.store ;; [
push src_adr
jp_nz loop1 ;; src_adr != 0 loop
end
)
)
つうか、ちょっとは努力をしたつもりなのだが「i32.const」とか「local.set」とか「local.get」とか……ダメだわ。まったく頭に入ってこない。まったくスタックに出し入れしている感じが湧かない。結局、だいぶ前にZ80ライクニーモニックからPICニーモニックに変換するRubyスクリプトを書いた時と同じく、Z80ライクニーモニックからWebAssemblyのwat形式に変換するRubyスクリプトを書いてしまった。PIC用に作ったそれに比べれば、恐ろしく単純な変換しかしていないが、自分にはそれで十分にわかりやすく書ける。はて、自分は頭が固いのか柔らかいのか、どっちなのだろう……ゼッパチの魂百まで。怖い。
#!/usr/bin/env ruby
# coding: utf-8
wat80src = ARGV[0]
file_in = open(wat80src, 'r')
file_out = open(wat80src.gsub(/\.[^.]+$/, '') + '.wat', 'w', 0444)
file_in.each {|line|
break if(line =~ /^__END__$/)
unless(line =~ /^#/)
line.chomp!
if(line =~ /^(\w+):\s*(\w+)(\s*.*)/) # loop1: loop
line = "\t\t%s\t\t$%s%s" % [$2, $1, $3]
end
if(line =~ /^(\s+br\w*)\s+(\w+)(\s*.*)/) # br_if loop1
line = "%s\t\t$%s%s" % [$1, $2, $3]
end
if(line =~ /^(\s+)jp_nz\s+(\w+)(\s*.*)/) # jp_nz loop1
line = "%sbr_if\t\t$%s%s" % [$1, $2, $3]
end
if(line =~ /^(\s+\w+)\.push\s+([\d-]+)(\s*.*)/) # i32.push 10
line = "%s.const\t\t%s%s" % [$1, $2, $3]
end
if(line =~ /^(\s+)pop\s+(\w+)(\s*.*)/) # pop i
line = "%slocal.set\t\t$%s%s" % [$1, $2, $3]
end
if(line =~ /^(\s+)push\s+(\w+)(\s*.*)/) # push i
line = "%slocal.get\t\t$%s%s" % [$1, $2, $3]
end
if(line =~ /^(\s+)pop_push\s+(\w+)(\s*.*)/) # pop_push i
line = "%slocal.tee\t\t$%s%s" % [$1, $2, $3]
end
if(line =~ /^(\s+)call\s+(\w+)(\s*.*)/) # call log
line = "%scall\t\t$%s%s" % [$1, $2, $3]
end
line += $/
end
file_out.write line
}
<HTML>
<HEAD>
<TITLE>WebAssembly Graphics Test</TITLE>
</HEAD>
<BODY>
<CANVAS id='canvas1' width='512' height='384'></CANVAS>
<SCRIPT type='text/javascript' src='graphics.js'></SCRIPT>
</BODY>
</HTML>
で、例によって、JavaScriptはCoffeeScriptに書き直した。CoffeeScriptでasyncやawaitはどう書くのかと思ったら、awaitが含まれる関数は、自動的にasyncを付けてくれるらしい。CoffeeScript 1.xではダメで、2.0以上が必要なようだが。
'use strict'
# ソースイメージを読み込む
image_element = new Image
image_element.src = 'gra2.png'
# ソースイメージの読み込み完了を待つ
prep = ->
if(!image_element.complete)
setTimeout(prep, 100)
else
main()
main = ->
screen_canvas_element = document.getElementById('canvas1')
screen_context = screen_canvas_element.getContext('2d')
# 枠描画、ソースイメージを描画
screen_context.fillStyle = 'lightgray'
screen_context.fillRect( 0, 0, image_element.width + 32, image_element.height + 32)
screen_context.fillStyle = 'gray'
screen_context.fillRect(16, 16, image_element.width, image_element.height)
screen_context.drawImage(image_element, 16, 16)
console.log('image_element:', image_element)
# ソースイメージをデータ化
work_canvas_element = document.createElement('canvas')
work_canvas_element.width = image_element.width
work_canvas_element.height = image_element.height
work_context = work_canvas_element.getContext('2d')
work_context.drawImage(image_element, 0, 0)
# source_image = work_context.getImageData(0, 0, image_element.width, image_element.height)
source_bytes = work_context.getImageData(0, 0, image_element.width, image_element.height).data
source_longs = new BigUint64Array(source_bytes.buffer, 0, source_bytes.length >> 3) # コピーの高速化のために共用体化
# console.log('source_image:', source_image)
console.log('source_bytes:', source_bytes)
# ワークメモリを確保
work_memory = new WebAssembly.Memory({ initial: 1, maximum: 1 }) # 1 PAGE = 64 KB
work_bytes = new Uint8ClampedArray(work_memory.buffer, 0, source_bytes.length)
work_longs = new BigUint64Array(work_memory.buffer, 0, source_longs.length) # コピーの高速化のために共用体化
# ソースイメージデータをワークメモリにコピー
for p in [0...source_longs.length]
work_longs[p] = source_longs[p]
# wasmをロード、メモリ操作(イメージデータの加工生成)を実行
importObjects = {
js: { mem: work_memory },
console: { log: (arg) => console.log(arg) },
}
obj = await WebAssembly.instantiateStreaming(fetch('graphics.wasm'), importObjects)
obj.instance.exports.filter(source_bytes.length)
# 生成データをイメージ化
filtered_bytes = new Uint8ClampedArray(work_memory.buffer, source_bytes.length, source_bytes.length)
filtered_image = new ImageData(filtered_bytes, image_element.width, image_element.height)
console.log('filtered_bytes:', filtered_bytes)
console.log('filtered_image:', filtered_image)
# スプライト(=キャンバス要素)を生成
sprite_canvas_element = document.createElement('canvas')
sprite_canvas_element.width = image_element.width
sprite_canvas_element.height = image_element.height
sprite_context = sprite_canvas_element.getContext('2d')
sprite_context.putImageData(filtered_image, 0, 0)
# 枠描画、スプライトを描画
screen_context.fillStyle = 'lightgray'
screen_context.fillRect( 0, 64, image_element.width + 32, image_element.height + 32)
screen_context.fillStyle = 'gray'
screen_context.fillRect(16, 80, image_element.width, image_element.height)
screen_context.drawImage(sprite_canvas_element, 16, 80)
console.log('sprite_canvas_element:', sprite_canvas_element)
prep()
結構、長い処理になってしまった。仕様上、何度も変換する必要があるのが面倒くさい。
- 元となるpngを内部CANVASに描き、getImageDataでUint8ClampedArrayの形で取り出す。
- それをWebAssembly.Memoryの領域にコピーする。
- WebAssemblyの側でフィルタ処理を行う。
- WebAssembly.Memoryの領域にUint8ClampedArrayの枠を被せて、ImageDataとして取り込む。
- それを新たにスプライトとして扱うCANVASにputImageDataで描く、までが準備作業。
最後に、表示されているCANVASに、drawImageでスプライトCANVASを重ねて完成だ。結果はこんな感じ。