2021/08/16(月) [n年前の日記]
#1 [ruby] Ruby の sfml-audio-fiddle が動かない
Rubyでogg再生ができるらしい拡張ライブラリ、sfml-audio-fiddle が正常動作しなくて悩んでいるところ。
_sfml-audio-fiddleの紹介 - Qiita
_sfml-audio-fiddle | RubyGems.org | コミュニティのGemホスティングサービス
_bggd/sfml-audio-fiddle: fiddle(ruby's FFI) binding for SFML2 Audio functions.
環境は以下。
_sfml-audio-fiddleの紹介 - Qiita
_sfml-audio-fiddle | RubyGems.org | コミュニティのGemホスティングサービス
_bggd/sfml-audio-fiddle: fiddle(ruby's FFI) binding for SFML2 Audio functions.
環境は以下。
- Windows10 x64 21H1
- Ruby 2.3.3 p222 x86 (i386-mingw32)
- Ruby 2.6.8 p205 x86 (i386-mingw32)
- Ruby 2.7.4 p191 x86 (i386-mingw32)
- Ruby 3.0.2 p107 x86 (i386-mingw32)
- sfml-audio-fiddle 0.1.0
◎ インストール方法。 :
念のためにインストール方法をメモしておく。
gem でインストールできる。
動作には CSFML の DLL も必要。以下のサイトから入手する。32bit版と64bit版があるので、使ってる Ruby に合わせる。
_CSFML (SFML / Download / Bindings)
_SFML/CSFML: Official binding of SFML for C
zipをダウンロードして解凍。
bin/ の中に入っている .dll を、スクリプトと同じ場所に置くらしい。
gem でインストールできる。
gem install sfml-audio-fiddle
動作には CSFML の DLL も必要。以下のサイトから入手する。32bit版と64bit版があるので、使ってる Ruby に合わせる。
_CSFML (SFML / Download / Bindings)
_SFML/CSFML: Official binding of SFML for C
zipをダウンロードして解凍。
bin/ の中に入っている .dll を、スクリプトと同じ場所に置くらしい。
- csfml-audio-2.dll
- openal32.dll
- libsndfile-1.dll ... 解説ページには記載が無いが、ファイル名からして必要になりそうな…。
◎ requireしただけでエラーを出す問題。 :
require "sfml/audio" をしてから使うライブラリだけど、require しただけでエラーを出してしまう。
問題点は2つありそう。
一つは、DLL検索パスの問題。どうやら今時の Ruby の fiddle は、スクリプトが置いてあるディレクトリ/カレントディレクトリに置いてある .dll を探してくれない感じで…。Ruby 2.3.3 ならエラーが出ないけど、Ruby 2.6 以降はエラーになる。
もう一つは、CSFML の .dll のバージョンによってエラーが出る問題。DLL検索パスの問題を解決した状況下で試すと、以下のような結果になった。
DLL検索パスの問題は、以下のような記述をすることで解決できそう。
一つは、RubyInstaller::Runtime.add_dll_directory() を使ってDLL検索パスを指定する方法。
一つは、kernel32.dll の SetDllDirectory() を使ってDLL検索パスを指定する方法。
あるいは、そもそも、ruby.exe が置いてある場所(C:\Ruby\bin\ 等)に関連DLLをコピーすることでもエラーは出なくなる。
ただ、こういう対策をしても、CSFML 2.2 以降の .dll を使うとエラーが出るのだけど…。
> irb irb(main):001:0> RUBY_VERSION => "2.6.8" irb(main):002:0> require "sfml/audio" Traceback (most recent call last): 21: from C:/Ruby/Ruby26-x86/bin/irb:23:in `<main>' 20: from C:/Ruby/Ruby26-x86/bin/irb:23:in `load' 19: from C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/irb-1.3.6/exe/irb:11:in `<top (required)>' 2: from (irb):2:in `<main>' 1: from C:/Ruby/Ruby26-x86/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:85:in `require' C:/Ruby/Ruby26-x86/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:85:in `require': cannot load such file -- sfml/audio (LoadError) 30: from C:/Ruby/Ruby26-x86/bin/irb:23:in `<main>' 29: from C:/Ruby/Ruby26-x86/bin/irb:23:in `load' 28: from C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/irb-1.3.6/exe/irb:11:in `<top (required)>' 11: from (irb):2:in `<main>' 10: from C:/Ruby/Ruby26-x86/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:149:in `require' 9: from C:/Ruby/Ruby26-x86/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:160:in `rescue in require' 8: from C:/Ruby/Ruby26-x86/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:160:in `require' 7: from C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/sfml-audio-fiddle-0.1.0/lib/sfml/audio.rb:4:in `<top (required)>' 6: from C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/sfml-audio-fiddle-0.1.0/lib/sfml/audio.rb:6:in `<module:SFMLImporter>' 5: from C:/Ruby/Ruby26-x86/lib/ruby/2.6.0/fiddle/import.rb:77:in `dlload' 4: from C:/Ruby/Ruby26-x86/lib/ruby/2.6.0/fiddle/import.rb:77:in `collect' 3: from C:/Ruby/Ruby26-x86/lib/ruby/2.6.0/fiddle/import.rb:87:in `block in dlload' 2: from C:/Ruby/Ruby26-x86/lib/ruby/2.6.0/fiddle.rb:47:in `dlopen' 1: from C:/Ruby/Ruby26-x86/lib/ruby/2.6.0/fiddle.rb:47:in `new' C:/Ruby/Ruby26-x86/lib/ruby/2.6.0/fiddle.rb:47:in `initialize': No such file or directory (Fiddle::DLError) 28: from C:/Ruby/Ruby26-x86/bin/irb:23:in `<main>' 27: from C:/Ruby/Ruby26-x86/bin/irb:23:in `load' 26: from C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/irb-1.3.6/exe/irb:11:in `<top (required)>' 9: from (irb):2:in `<main>' 8: from C:/Ruby/Ruby26-x86/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:149:in `require' 7: from C:/Ruby/Ruby26-x86/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:160:in `rescue in require' 6: from C:/Ruby/Ruby26-x86/lib/ruby/site_ruby/2.6.0/rubygems/core_ext/kernel_require.rb:160:in `require' 5: from C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/sfml-audio-fiddle-0.1.0/lib/sfml/audio.rb:4:in `<top (required)>' 4: from C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/sfml-audio-fiddle-0.1.0/lib/sfml/audio.rb:6:in `<module:SFMLImporter>' 3: from C:/Ruby/Ruby26-x86/lib/ruby/2.6.0/fiddle/import.rb:77:in `dlload' 2: from C:/Ruby/Ruby26-x86/lib/ruby/2.6.0/fiddle/import.rb:77:in `collect' 1: from C:/Ruby/Ruby26-x86/lib/ruby/2.6.0/fiddle/import.rb:86:in `block in dlload' C:/Ruby/Ruby26-x86/lib/ruby/2.6.0/fiddle/import.rb:89:in `rescue in block in dlload': can't load csfml-audio-2 (Fiddle::DLError) irb(main):003:0>
問題点は2つありそう。
一つは、DLL検索パスの問題。どうやら今時の Ruby の fiddle は、スクリプトが置いてあるディレクトリ/カレントディレクトリに置いてある .dll を探してくれない感じで…。Ruby 2.3.3 ならエラーが出ないけど、Ruby 2.6 以降はエラーになる。
もう一つは、CSFML の .dll のバージョンによってエラーが出る問題。DLL検索パスの問題を解決した状況下で試すと、以下のような結果になった。
- CSFML 2.0, 2.1 の .dll は、require した際にエラーを出さなかった。
- CSFML 2.2, 2.3, 2.4, 2.5.1 の .dll はエラーを出した。
DLL検索パスの問題は、以下のような記述をすることで解決できそう。
一つは、RubyInstaller::Runtime.add_dll_directory() を使ってDLL検索パスを指定する方法。
my_dll_dir_path = File.expand_path("..", __FILE__) RubyInstaller::Runtime.add_dll_directory(my_dll_dir_path) require "sfml/audio"
一つは、kernel32.dll の SetDllDirectory() を使ってDLL検索パスを指定する方法。
require 'fiddle/import' require 'fiddle/types' module WinAPI extend Fiddle::Importer dlload 'kernel32.dll' include Fiddle::Win32Types extern 'int SetDllDirectory(LPCSTR)' end my_dll_dir_path = File.expand_path("..", __FILE__) WinAPI.SetDllDirectory(my_dll_dir_path) require "sfml/audio"
あるいは、そもそも、ruby.exe が置いてある場所(C:\Ruby\bin\ 等)に関連DLLをコピーすることでもエラーは出なくなる。
ただ、こういう対策をしても、CSFML 2.2 以降の .dll を使うとエラーが出るのだけど…。
◎ サウンドファイルを再生するとクラッシュする問題。 :
前述のDLL検索パスの問題を対策して require が通るようになったとしても、サウンドファイルを再生すると、再生が終わったタイミングで Segmentation fault が出てしまう。
例えば、以下のようなスクリプトを実行してみると…。
_04_ogg_play_music.rb
_loop_bgm.ogg
実行すると、再生が終わったあたりのタイミングで Segmentation fault になる。
Music ではなく SoundBuffer を使ってみても…。
_05_ogg_play_soundbuffer.rb
結果は同じ。再生が終わったタイミングで Segmentation fault になる。
_stderr05.txt
Ruby 2.3.3, 2.6.8, 2.7.4, 3.0.2、どのバージョンで試しても Segmentation fault になる…。
例えば、以下のようなスクリプトを実行してみると…。
_04_ogg_play_music.rb
begin require 'sfml/audio' rescue => e require 'fiddle/import' require 'fiddle/types' module WinAPI extend Fiddle::Importer dlload 'kernel32.dll' include Fiddle::Win32Types extern 'int SetDllDirectory(LPCSTR)' end my_dll_dir_path = File.expand_path("..", __FILE__) WinAPI.SetDllDirectory(my_dll_dir_path) require 'sfml/audio' end music = SFML::Music.new("loop_bgm.ogg") puts "Song length : #{music.get_duration} sec" music.play while music.get_status == :playing puts "playing" sleep 1 end
_loop_bgm.ogg
実行すると、再生が終わったあたりのタイミングで Segmentation fault になる。
C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/sfml-audio-fiddle-0.1.0/lib/sfml/audio.rb:41: [BUG] Segmentation fault ruby 2.6.8p205 (2021-07-07 revision 67951) [i386-mingw32] -- Control frame information ----------------------------------------------- c:0004 p:---- s:0018 e:000017 CFUNC :call c:0003 p:0018 s:0013 e:000012 METHOD C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/sfml-audio-fiddle-0.1.0/lib/sfml/audio.rb:41 c:0002 p:0013 s:0007 e:000006 BLOCK C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/sfml-audio-fiddle-0.1.0/lib/sfml/audio.rb:154 [FINISH] c:0001 p:0000 s:0003 E:001d48 (none) [FINISH] -- Ruby level backtrace information ---------------------------------------- C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/sfml-audio-fiddle-0.1.0/lib/sfml/audio.rb:154:in `block in dtor' C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/sfml-audio-fiddle-0.1.0/lib/sfml/audio.rb:41:in `sfMusic_stop' C:/Ruby/Ruby26-x86/lib/ruby/gems/2.6.0/gems/sfml-audio-fiddle-0.1.0/lib/sfml/audio.rb:41:in `call' -- C level backtrace information ------------------------------------------- C:\Windows\SYSTEM32\ntdll.dll(NtWaitForSingleObject+0xc) [0x76ff29dc] C:\Windows\System32\KERNELBASE.dll(WaitForSingleObject+0x12) [0x75031072] C:\Ruby\Ruby26-x86\bin\msvcrt-ruby260.dll(rb_vm_bugreport+0x301) [0x665407a1] C:\Windows\SYSTEM32\ntdll.dll(RtlCaptureStackContext+0x1bc43) [0x77024883] -- Other runtime information ----------------------------------------------- * Loaded script: 04_ogg_play_music.rb ..._stderr04.txt(全てのエラーメッセージ)
Music ではなく SoundBuffer を使ってみても…。
_05_ogg_play_soundbuffer.rb
begin require 'sfml/audio' rescue => e require 'fiddle/import' require 'fiddle/types' module WinAPI extend Fiddle::Importer dlload 'kernel32.dll' include Fiddle::Win32Types extern 'int SetDllDirectory(LPCSTR)' end my_dll_dir_path = File.expand_path("..", __FILE__) WinAPI.SetDllDirectory(my_dll_dir_path) require 'sfml/audio' end buffer = SFML::SoundBuffer.new 'loop_bgm.ogg' sound = SFML::Sound.new buffer sound.play sleep buffer.get_duration + 1
結果は同じ。再生が終わったタイミングで Segmentation fault になる。
_stderr05.txt
Ruby 2.3.3, 2.6.8, 2.7.4, 3.0.2、どのバージョンで試しても Segmentation fault になる…。
◎ 雑感。 :
Ruby の fiddle を使うことで、Ruby のバージョンが変わるたびにバイナリをビルドしなくても済むメリットがありそう、などと思ってたけど、そもそも正常動作してくれないのではなあ、みたいな…。
[ ツッコむ ]
#2 [anime][neta] HDDレコーダの空き容量が厳しい
HDDレコーダの電源を入れたら「録画できる空き容量が無くなりました」とメッセージが。厳しい。
仕方ないので、未視聴のまま溜め込んでた「東京リベンジャーズ」アニメ版の数話分を、見ないまま削除。かつ、録画予約も削除。
余談と言うか独り言。
件の作品は、アニメ版も人気があるとか、実写映画版はヒットしてるとか聞いたので、フツーに考えたらここまで見といて視聴を打ち切るのはアレだろうけど…。実によくできてるアニメだと思うし…。ただ、そもそも個人的に、不良だの珍走団だのが主人公の漫画やアニメって大嫌いで…。自分、校内暴力が吹き荒れてた時期に中学時代を送る羽目になった世代なので、あの手の人種は目にするのも嫌で嫌で…。アイツラ、リアルに母校の校舎を全焼させたりしてたから…。
それでも、放送されてるアニメはできる限り見ておかねばという奇妙な義務感とか、あるいは、キャラ設定なんてどうでもよくなるぐらい途中から面白くなったら勿体無いとか、そんな理由でここまで見てきたけど、それでもやっぱり見るのが苦痛で苦痛で…。自然と視聴も後回しになって、結局数話溜まって、HDDレコの空き容量確保しなきゃいけないからここは我慢してとにかく流そう的にBGV扱い+早見再生で無理矢理どうにか消化してる感じだったので…。これじゃMだよ。これでも頑張ったよね、俺。もうゴールしてもいいよね。みたいな。そのくらい嫌いなんですよ…不良や珍走団が主人公の作品って…。いやまあ、ちゃんと作ってあるアニメだよなと感心しながらチラ見してたんですけど…。
大体にして、途中で1回上手くいった感じになったのにまだ続くあたり、さては原作の人気が出て連載を引き延ばすための展開を用意したのかなと邪推しちゃったりもして…。もうつきあってらんねーよ。DBやワンピースを目指してだらだらずるずるといつまでも続けてればいいさ、てな感じの妙にやさぐれた気分になってきたりもして…。
そんな感じで、ここまで見てきたのに最後まで見れなくて残念という気持ちと、あの手のキャラをもう見なくて済むからこれでせいせいしたわい的な気持ちが入り混じった、ちょっと複雑な気分…。まあ、録画するための空き容量が無いんだから仕方ない…。どうしようもない…。今時のアニメの放送本数が多過ぎるんや…。いや、全部見ようと頑張っちゃうからおかしなことになるんだけど。
それにしても、ああいう展開の話がウケるなら、例えば「夏への扉」も一般層にウケるのでは、と思ってたら、そういう実写映画が…。そっちは全然ウケてないようで不思議。一体何が明暗を分けたのか…。
仕方ないので、未視聴のまま溜め込んでた「東京リベンジャーズ」アニメ版の数話分を、見ないまま削除。かつ、録画予約も削除。
余談と言うか独り言。
件の作品は、アニメ版も人気があるとか、実写映画版はヒットしてるとか聞いたので、フツーに考えたらここまで見といて視聴を打ち切るのはアレだろうけど…。実によくできてるアニメだと思うし…。ただ、そもそも個人的に、不良だの珍走団だのが主人公の漫画やアニメって大嫌いで…。自分、校内暴力が吹き荒れてた時期に中学時代を送る羽目になった世代なので、あの手の人種は目にするのも嫌で嫌で…。アイツラ、リアルに母校の校舎を全焼させたりしてたから…。
それでも、放送されてるアニメはできる限り見ておかねばという奇妙な義務感とか、あるいは、キャラ設定なんてどうでもよくなるぐらい途中から面白くなったら勿体無いとか、そんな理由でここまで見てきたけど、それでもやっぱり見るのが苦痛で苦痛で…。自然と視聴も後回しになって、結局数話溜まって、HDDレコの空き容量確保しなきゃいけないからここは我慢してとにかく流そう的にBGV扱い+早見再生で無理矢理どうにか消化してる感じだったので…。これじゃMだよ。これでも頑張ったよね、俺。もうゴールしてもいいよね。みたいな。そのくらい嫌いなんですよ…不良や珍走団が主人公の作品って…。いやまあ、ちゃんと作ってあるアニメだよなと感心しながらチラ見してたんですけど…。
大体にして、途中で1回上手くいった感じになったのにまだ続くあたり、さては原作の人気が出て連載を引き延ばすための展開を用意したのかなと邪推しちゃったりもして…。もうつきあってらんねーよ。DBやワンピースを目指してだらだらずるずるといつまでも続けてればいいさ、てな感じの妙にやさぐれた気分になってきたりもして…。
そんな感じで、ここまで見てきたのに最後まで見れなくて残念という気持ちと、あの手のキャラをもう見なくて済むからこれでせいせいしたわい的な気持ちが入り混じった、ちょっと複雑な気分…。まあ、録画するための空き容量が無いんだから仕方ない…。どうしようもない…。今時のアニメの放送本数が多過ぎるんや…。いや、全部見ようと頑張っちゃうからおかしなことになるんだけど。
それにしても、ああいう展開の話がウケるなら、例えば「夏への扉」も一般層にウケるのでは、と思ってたら、そういう実写映画が…。そっちは全然ウケてないようで不思議。一体何が明暗を分けたのか…。
[ ツッコむ ]
以上、1 日分です。