mieki256's diary



2016/12/14(水) [n年前の日記]

#1 [ruby][gosu] Ubuntu 16.04 + Ruby + Gosu でサウンド再生を試してみたり

_昨日書いた各スクリプト を VMware Player + Ubuntu 16.04 LTS上でも動かしてサウンドが鳴るかどうか確認してみたり。

結果、基本的には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向けのフォーマットなのか。

謎メッセージが解決できないか試す。 :

Ubuntu上で表示される謎メッセージが気になる。表示されないように修正できないものか。つまりは終了前にリソースをちゃんと解放するように作れないものか。

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) は警告です。

Xorg - ArchWiki より

Sampleクラスを使うとちゃんとループする。 :

Songクラスを使わずに、Sampleクラスを使うとちゃんとループするようで。

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

以上です。

過去ログ表示

Prev - 2016/12 - 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