mieki256's diary



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.

環境は以下。

インストール方法。 :

念のためにインストール方法をメモしておく。

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 しただけでエラーを出してしまう。

> 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 はエラーを出した。
利用できる CSFML のバージョンが限定されている気配がする。

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
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 のバージョンが変わるたびにバイナリをビルドしなくても済むメリットがありそう、などと思ってたけど、そもそも正常動作してくれないのではなあ、みたいな…。

以上です。

過去ログ表示

Prev - 2021/08 - Next
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project