2014/12/24(水) [n年前の日記]
#1 [dxruby] DXRubyとAyameとイントロとループとスレッド
DXRuby は 60FPS でメインループが回っているけど、それより速い周期でループを回す部分を作って、そこでBGMの切り替えをしたら、自然に繋がってるように聞こえないかなと思えてきたので、Ruby の Thread とやらを使って試してみたりして。
_bgmloop2.rb
試してはみたものの、違いが分からない…。元の ogg の作りがマズいのだろうか。
別スレッド内で Ayame.update を呼んじゃってるけど、これってアリなのかな…。勝手な想像では、おそらく Ayame.update が音の再生開始等の処理も担っていて、となるとメインループ内に Ayame.update を置いておくと再生開始タイミングも 60fps になってしまって意味が無いのではないか、と思って別スレッド内に置いてガンガン呼びまくるようにしてみたのだけど。ちなみにこの状態でも、フェードアウト等の秒数指定は、指定通りに動いてるように聞こえた。
ていうか、メインループ内でBGMを切り替えるやり方も、切り替え時にビミョーにずれてるとは気付かれないのではないか、てな気分になってきたり。何度も聞いてるうちに、よくわからなくなってきた…。
_bgmloop2.rb
require 'dxruby'
require_relative 'ayame'
if true
bgm_intro = Ayame.new('test58intro.ogg')
bgm_loop = Ayame.new('test58loop.ogg')
bgm_intro_time = 6.888
else
bgm_intro = Ayame.new('test59intro.ogg')
bgm_loop = Ayame.new('test59loop.ogg')
bgm_intro_time = 13.714
end
bgm_intro.predecode
bgm_loop.predecode
intro_time = 0
bgm_step = 0
# BGM処理用スレッド
t = Thread.new do
loop do
case bgm_step
when 0
# イントロ再生開始の指示待ち
nil
when 1
# イントロ再生開始
bgm_intro.play(1, 0)
intro_time = Time.now.to_f
bgm_step = 2
when 2
# イントロ再生終了待ち
if intro_time + bgm_intro_time < Time.now.to_f
# loop BGM 再生開始
bgm_loop.play(0, 0)
bgm_step = 3
end
when 3
# loop BGM再生中
nil
when 4
# loop BGM停止
bgm_loop.stop(1)
bgm_step = 0
when 5
break
end
Ayame.update
sleep(0.001)
end
bgm_intro.stop
bgm_intro.dispose
bgm_loop.stop
bgm_loop.dispose
end
fnt = Font.new(24)
Window.loop do
break if Input.keyPush?(K_ESCAPE)
if Input.keyPush?(K_Z)
if bgm_step <= 0
# BGMを再生していないので、イントロ再生開始
bgm_step = 1
elsif bgm_step == 3
# loop BGM 再生中なので停止する
bgm_step = 4
end
end
if bgm_step >= 0
msg = [
"z : start intro",
" intro play start",
" intro playing",
"z : stop loop bgm",
" loop BGM stop"
]
Window.drawFont(8, 8, msg[bgm_step], fnt)
end
end
bgm_step = 5
t.join
試してはみたものの、違いが分からない…。元の ogg の作りがマズいのだろうか。
別スレッド内で Ayame.update を呼んじゃってるけど、これってアリなのかな…。勝手な想像では、おそらく Ayame.update が音の再生開始等の処理も担っていて、となるとメインループ内に Ayame.update を置いておくと再生開始タイミングも 60fps になってしまって意味が無いのではないか、と思って別スレッド内に置いてガンガン呼びまくるようにしてみたのだけど。ちなみにこの状態でも、フェードアウト等の秒数指定は、指定通りに動いてるように聞こえた。
ていうか、メインループ内でBGMを切り替えるやり方も、切り替え時にビミョーにずれてるとは気付かれないのではないか、てな気分になってきたり。何度も聞いてるうちに、よくわからなくなってきた…。
◎ sleepの精度が分からない。 :
Ruby で Thread を使って sleep(秒数) でループを回すソレは、環境によってどうなるか不明という話もあるそうで。
Ruby の sleep() は小数点以下も指定できるので、ミリ秒(ms)単位でもsleepできるように思えるけれど、OSによってsleepできる精度? 分解能? が違ってるそうで。Windows NT の場合、sleep が 10ms の精度?だから、それより小さい値を指定しても意味が無い、という話も見かけた。 しかし、XP、Vista、7、8 とWindowsのバージョンが上がった際に、そのあたり何の変更も無かったのかな、改善されてたりしないのかな、という疑問も。
調べてみたら、Windows の場合、時間を測る仕様は3種類ほどあるらしく。
_QueryPerformanceCounterを実時間計測には使えない - 音宮志久の日々の考え
マルチメディアタイマーとやらを使えば 1ms 単位で測定できるらしいから、もし、Windows版の Ruby がそのあたりを使ってたら、昔と違って 1ms の精度で sleep できたりするのかも、と素人考えで思ったりもしたけど、そのへんの実装に何か変化があったのかどうかも分からない状態で。
ひとまず上のソースで、sleep(0.001) を sleep(0.0005) にしてみたら、CPU使用率が急激に上昇したので、指定値が何かしらの形で反映されてる、ような気もする。
Ruby の sleep() は小数点以下も指定できるので、ミリ秒(ms)単位でもsleepできるように思えるけれど、OSによってsleepできる精度? 分解能? が違ってるそうで。Windows NT の場合、sleep が 10ms の精度?だから、それより小さい値を指定しても意味が無い、という話も見かけた。 しかし、XP、Vista、7、8 とWindowsのバージョンが上がった際に、そのあたり何の変更も無かったのかな、改善されてたりしないのかな、という疑問も。
調べてみたら、Windows の場合、時間を測る仕様は3種類ほどあるらしく。
_QueryPerformanceCounterを実時間計測には使えない - 音宮志久の日々の考え
マルチメディアタイマーとやらを使えば 1ms 単位で測定できるらしいから、もし、Windows版の Ruby がそのあたりを使ってたら、昔と違って 1ms の精度で sleep できたりするのかも、と素人考えで思ったりもしたけど、そのへんの実装に何か変化があったのかどうかも分からない状態で。
ひとまず上のソースで、sleep(0.001) を sleep(0.0005) にしてみたら、CPU使用率が急激に上昇したので、指定値が何かしらの形で反映されてる、ような気もする。
◎ 曲データの作り方でも誤魔化せそう。 :
例えばだけど、イントロ部分の最後で、
- シンバル? クラッシュライド? を「バシャーン(シャンシャンシャン…)」と鳴らしてる上にループ部分を載せてみたり
- ドラムだけ叩いて「ダダダダダッ、ダンッ…(シーン)…」と意図的に無音部分を作ったり
- Glitch でテンポを崩したり
[ ツッコむ ]
以上です。