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上では終了時にやっぱり例のメッセージが表示されてしまうのだけど…。
[ ツッコむ ]
以上です。