2016/12/14(水) [n年前の日記]
#1 [ruby][gosu] Ubuntu 16.04 + Ruby + Gosu でサウンド再生を試してみたり
_昨日書いた各スクリプト
を VMware Player + Ubuntu 16.04 LTS上でも動かしてサウンドが鳴るかどうか確認してみたり。
結果、基本的にはWindows上で試した時と同様に一応鳴ってはくれたけど、ちと気になる動作が。
各スクリプトを実行すると終了時に妙なメッセージが表示される。
たぶんサウンド関係のリソースを確保したまま終了しちゃって「そういう作りをしてるんじゃねえよ」と怒られてるのだろうけど。dispose 云々とやらを、どこでどうやってしておけばいいのやら。コレが DXRuby + Ayame なら、サウンドリソースに対しては dispose という専用メソッドが用意されてるのだけど…。
それとは別に。Songクラスを使ったBGM再生については、Ubuntu上もWindowsと同様に、ループ再生は終わりと頭がちゃんと繋がってくれなかった。最後まで再生する前に頭に戻ってる、ように聞こえる。Linux上ではちゃんと聞こえるけどWindows上ではダメ、てな面倒臭い状況にならなかったのは幸いだけど、それにしても…やっぱりループ再生すらできないのは、困るな…。
結果、基本的にはWindows上で試した時と同様に一応鳴ってはくれたけど、ちと気になる動作が。
各スクリプトを実行すると終了時に妙なメッセージが表示される。
$ ruby sound_test.rb AL lib: (WW) FreeDevice: (0x22c9260) Deleting 6 Buffer(s) $ ruby sound_test2.rb AL lib: (WW) FreeDevice: (0x1c2c160) Deleting 1 Buffer(s) $ ruby song_test.rb AL lib: (WW) FreeDevice: (0x149c6b0) Deleting 2 Buffer(s)コレは一体何だろう…。
たぶんサウンド関係のリソースを確保したまま終了しちゃって「そういう作りをしてるんじゃねえよ」と怒られてるのだろうけど。dispose 云々とやらを、どこでどうやってしておけばいいのやら。コレが DXRuby + Ayame なら、サウンドリソースに対しては dispose という専用メソッドが用意されてるのだけど…。
それとは別に。Songクラスを使ったBGM再生については、Ubuntu上もWindowsと同様に、ループ再生は終わりと頭がちゃんと繋がってくれなかった。最後まで再生する前に頭に戻ってる、ように聞こえる。Linux上ではちゃんと聞こえるけどWindows上ではダメ、てな面倒臭い状況にならなかったのは幸いだけど、それにしても…やっぱりループ再生すらできないのは、困るな…。
◎ Gosuがサポートしてるサウンドファイルフォーマット。 :
_Supported Audio Formats - gosu/gosu Wiki
に説明があった。Windows、Linux、Mac は wav と ogg が使えるけど、iPhone は MP3 か M4A じゃないとあかんよ、一応 ogg も使えるけど遅くなるよ、と書いてあるのかな。
Macに限っては、CAF, MP3, M4A, WAV, AIFF等々、なんでもござれ状態らしい。…CAFフォーマットなんて初めて聞いた。iPhone向けのフォーマットなのか。
Macに限っては、CAF, MP3, M4A, WAV, AIFF等々、なんでもござれ状態らしい。…CAFフォーマットなんて初めて聞いた。iPhone向けのフォーマットなのか。
◎ 謎メッセージが解決できないか試す。 :
Ubuntu上で表示される謎メッセージが気になる。表示されないように修正できないものか。つまりは終了前にリソースをちゃんと解放するように作れないものか。
DXRubyドキュメントの、 _4.11 リソースの解放について が参考になりそうな気がしてきた。参照を切って GC.start を呼ぶ、という方法が提示されてる。
が、しかし。Ruby上で参照を切る、ってのは具体的にはどうやればいいのでしょうかね? 自分は初心者なので、まずそこからして分からないという…。
_第14章 コンテキスト の中で気になる行が。
試しに色々対策。
_sound_test3.rb
要するに、SEが鳴ってない状態になるまで待ってみて、それから各変数に nil を代入して GC.start を呼ぶ、という処理にしてみた。
ちなみに、もしかしてメインループの中で再生状態の検出・記録をしていたりして、となるとウインドウを閉じた後で再生状態を調べようとしても無駄なのではと疑問を持ったけど。実際試してみたら、メインループ外でもちゃんと再生・非再生が得られたので、メインループとは違うところでそのあたりを処理して調べている模様。
さておき。結果が少し変わってきた。
ちなみに、github上のgosuのソレには、 _OpenAL warning on Ubuntu - Issue #292 - gosu/gosu として去年から報告が上がってるけど、誰もレスをつけてないという…。ひょっとして、Linux + Gosuを使う人は無音のゲームしか作らないのだろうか。それともそもそもLinux上でGosuを使う人はほとんど存在していないのだろうか。
メッセージ内の「(WW)」はエラーじゃなくて警告を表してるのだろうと思うので、少しウザいけど気にしないという選択肢もアリなのかしら。いやまあ、現状では解決策が見つからないので、その選択肢しか無いのだけど。
_Xorg - ArchWiki
DXRubyドキュメントの、 _4.11 リソースの解放について が参考になりそうな気がしてきた。参照を切って GC.start を呼ぶ、という方法が提示されてる。
が、しかし。Ruby上で参照を切る、ってのは具体的にはどうやればいいのでしょうかね? 自分は初心者なので、まずそこからして分からないという…。
_第14章 コンテキスト の中で気になる行が。
cnt = nil # 参照を切る。作ったProcはここでやっと不要になるなるほど、nil を入れておけばいいのか…な…。本当にそうなのか分かんないけど。
試しに色々対策。
_sound_test3.rb
require 'gosu' class MyWindow < Gosu::Window def initialize super 320, 240, false self.caption = 'Sound Play Test' # wavファイルを読み込む @sounds = [] @sis = [] [ "tmp_se_01.wav", "tmp_se_02.wav", "tmp_se_03.wav", "tmp_se_01.ogg", "tmp_se_02.ogg", "tmp_se_03.ogg" ].each do |fn| @sounds.push(Gosu::Sample.new(fn)) @sis.push(nil) end @cnt = 0 @close_req = 0 @se_all_stop = false end def update if @se_all_stop # SE全停止が要求されてる stop_all_se @se_all_stop = false end if @close_req > 0 # ウインドウcloseが要求されてる @close_req -= 1 if @close_req == 0 # 一定時間が経過した if se_playing? # まだ鳴ってる @close_req = 30 puts "SE playing (in update)" else # 何も鳴ってない dispose_se_resource GC.start close # ウインドウを閉じる end end return end tm = 45 if @cnt % tm == 0 # 一定フレーム数が過ぎたらサウンドを再生 n = (@cnt / tm) % @sounds.length if @sis[n] == nil or !@sis[n].playing? @sis[n] = @sounds[n].play else # @sis[n].stop end end @cnt += 1 end def draw end # キーが押された時に呼ばれる def button_down(id) if id == Gosu::KbEscape # ESCキーが押された # @se_all_stop = true # SE全停止を要求 @close_req = 30 # xxフレーム後にウインドウを閉じるように要求 end end # 何かのSEが鳴ってたら true を返す def se_playing? return false unless @sis cnt = 0 @sis.each do |si| next unless si cnt += 1 if si.playing? end return true if cnt > 0 return false end # SEを全て停止 def stop_all_se return unless @sis @sis.length.times do |i| next unless @sis[i] @sis[i].stop end puts "SE stop all" end # サウンド関連リソースを全て破棄、するはずなんだけど… def dispose_se_resource if @sis @sis.length.times { |i| @sis[i] = nil } @sfs = nil end if @sounds @sounds.length.times { |i| @sounds[i] = nil } @sounds = nil end end end wdw = MyWindow.new wdw.show # SEが鳴り終わるまで待つ while wdw.se_playing? puts "SE playing" sleep(1) end puts "SE not playing" wdw.dispose_se_resource wdw = nil GC.start exit
要するに、SEが鳴ってない状態になるまで待ってみて、それから各変数に nil を代入して GC.start を呼ぶ、という処理にしてみた。
ちなみに、もしかしてメインループの中で再生状態の検出・記録をしていたりして、となるとウインドウを閉じた後で再生状態を調べようとしても無駄なのではと疑問を持ったけど。実際試してみたら、メインループ外でもちゃんと再生・非再生が得られたので、メインループとは違うところでそのあたりを処理して調べている模様。
さておき。結果が少し変わってきた。
$ ruby sound_test3.rb SE playing (in update) SE not playing AL lib: (WW) FreeDevice: (0x1b503b0) Deleting 2 Buffer(s)メッセージ内のバッファ数が、6から2まで減った。しかし、相変わらずメッセージが表示されてる。なんでや…。
ちなみに、github上のgosuのソレには、 _OpenAL warning on Ubuntu - Issue #292 - gosu/gosu として去年から報告が上がってるけど、誰もレスをつけてないという…。ひょっとして、Linux + Gosuを使う人は無音のゲームしか作らないのだろうか。それともそもそもLinux上でGosuを使う人はほとんど存在していないのだろうか。
メッセージ内の「(WW)」はエラーじゃなくて警告を表してるのだろうと思うので、少しウザいけど気にしないという選択肢もアリなのかしら。いやまあ、現状では解決策が見つからないので、その選択肢しか無いのだけど。
_Xorg - ArchWiki
ログファイルの中に (EE) で始まる行が存在しないか確認してください。(EE) はエラーです。また、(WW) は警告です。
◎ Sampleクラスを使うとちゃんとループする。 :
Songクラスを使わずに、Sampleクラスを使うとちゃんとループするようで。
_song_test3.rb
曲の終わりと頭がちゃんと繋がってるように聞こえる。もしかするとノイズが入ってるかもしれないけど、聞いてる分にはほとんど分からない、ような。
また、Windows上でも、Ubuntu上でも、同じように聞こえた。
もっとも、Ubuntu上では終了時にやっぱり例のメッセージが表示されてしまうのだけど…。
_song_test3.rb
require 'gosu' class MyWindow < Gosu::Window def initialize super 320, 240, false self.caption = 'Sample (BGM) Play Test' @fnt = Gosu::Font.new(20) # BGMのoggファイルを読み込む @bgm = Gosu::Sample.new("tmp_loop01.ogg") @bgm_si = nil @play_msg = "" @pause_msg = "" end def update # 再生中? @play_msg = (@bgm_si and @bgm_si.playing?)? "Playing" : "Stopped" # ポーズ中? @pause_msg = (@bgm_si and @bgm_si.paused?)? "Paused" : "Not Paused" end def draw # 再生中/停止中, ポーズ中/非ポーズを表示 @fnt.draw("Push A:Play, Z:Stop, P:Pause", 4, 4, 0) @fnt.draw(@play_msg, 4, 30, 0) @fnt.draw(@pause_msg, 4, 50, 0) end # キーが押された時に呼ばれる def button_down(id) if id == Gosu::KbEscape close elsif id == Gosu::KbA if @bgm_si == nil or !@bgm_si.playing? @bgm_si = @bgm.play(1, 1, true) # 通常再生(ループ有効) end elsif id == Gosu::KbZ if @bgm_si @bgm_si.stop # 再生停止 end elsif id == Gosu::KbP if @bgm_si if @bgm_si.paused? @bgm_si.resume # ポーズ解除 elsif @bgm_si.playing? @bgm_si.pause # ポーズ end end end end # キーが離された時に呼ばれる def button_up(id) end def stop_bgm return unless @bgm_si @bgm_si.stop end def dispose_bgm @bgm_si = nil @bgm = nil end def bgm_playing? return false unless @bgm_si return @bgm_si.playing? end end wdw = MyWindow.new wdw.show # BGM停止を指示 wdw.stop_bgm # BGMが停止するまで待つ while wdw.bgm_playing? puts "BGM playing" sleep(1) end puts "BGM not playing" wdw.dispose_bgm wdw = nil GC.start exit
曲の終わりと頭がちゃんと繋がってるように聞こえる。もしかするとノイズが入ってるかもしれないけど、聞いてる分にはほとんど分からない、ような。
また、Windows上でも、Ubuntu上でも、同じように聞こえた。
もっとも、Ubuntu上では終了時にやっぱり例のメッセージが表示されてしまうのだけど…。
[ ツッコむ ]
以上です。