トップページ > 過去ログ > 記事閲覧
音楽再生のループ
名前:だみあん 日時: 2010/01/17 15:36

音楽再生についての質問というか要望です。 現行のライブラリには 曲の最後まで再生されると、指定されたループポイントに戻るという機能がありますが 曲の途中をポイント指定して、指定されたループポイントに戻るという 機能は出来ませんでしょうか。 というのも、曲にイントロだけでなくアウトロをつけたいのです。 ループ指定しないときはアウトロまで再生・・・ のようなことをやりたいのですが。 (曲を二つ用意するのは容量的に音楽ファイルは大きいので避けたいです) とりあえず、GetSoundCurrentTimeで現在の位置を取得して その値を超えたらループポイントに戻る・・・というのを組んでみたのですが 再生方法の設定であるSetCreateSoundDataTypeを DX_SOUNDDATATYPE_MEMNOPRESSにすると上手くループしてくれるのですが DX_SOUNDDATATYPE_FILE DX_SOUNDDATATYPE_MEMPRESS の二つでやると、ずれてしまって上手くループできません。 ゲームのメインとは別に 音楽鑑賞モードのようなものがありまして そこでスライドバーで再生位置を移動出来るようにしているのですが ループポイント近くまで移動してからだと DX_SOUNDDATATYPE_FILE DX_SOUNDDATATYPE_MEMPRESS のいずれかでもきちんとループしてくれます。 フレームレート固定のために 60フレームを越えたときにSleepしてるのがわるいのかと Sleepをはずしてみたり、 途中の処理で重いのかと、逆に時間のかかる画像エフェクトなどをかけて 30fpsぐらいにまで落ち込む処理をやってみても 同じ症状で微妙にずれてしまっているようです。 ループした瞬間の if(終端ループポイント<= GetSoundCurrentTime) の判定後のGetSoundCurrentTimeの値をみると 0〜20ミリ秒ほどずれているのですが そのずれ幅に比例してずれている・・・という感じでもありません。 というかDX_SOUNDDATATYPE_MEMNOPRESSのとき ループは正常に行われていても 同様のずれは生じているので、あまり関係ないかも知れません。 (たんに一回目のGetSoundCurrentTimeと二回目のGetSoundCurrentTimeの間の数値が出てるだけかと) また、ミリ秒単位からバイト数でポイントを指定することにしても、同様の結果に終わりました。 ちなみに再生ファイルはoggです。 ライブラリは最新のVer3.01を使用しています。 ProcessMessage()は毎フレーム実行されています。 ループの位置がずれていると言うよりは、音が一瞬途切れる・・・というほうが 近い感じになっています。 ・・・と、原因究明をしていたのですが、 この掲示板に書いている最中、バックグラウンドで走らせたままにしているので気付いたのですが ゲームウィンドウからフォーカスを外すと ProcessMessage()しかよばれなくなるので プログラム内でのループ監視は無意味ということに気付いたのはついさっきのことなのですが・・・。 (普通に曲の最後まで行って、SetLoopPosSoundMemで設定されたループポイントに戻る・・・) ということで、結局現状の方法では実現不可能という事になりそうなのですが (バックグラウンドでも稼働することにしても結局ずれる上、 BGMなのでDX_SOUNDDATATYPE_MEMNOPRESSでは立ち上がりにもたついて 動作がもっさりしたり、クロスフェードがうまく行かなくなったりで・・・) そこで、 SetLoopPosSoundMemのループポイントはDxLib.hをみると // メモリ上に展開されたファイルイメージから前奏部とループ部に分かれたハンドルを作成する LoadSoundMem2ByMemImage の関数で行われている? ようですが 前奏部の他に後奏部を指定できるような機能の追加は無理でしょうか。 この関数の説明をみるに、分割する場所で最初から分割しておけば出来るのではないかとおもったもので。 なにげに、複数のループポイントを設定できると 曲の途中のコード切り替えのタイミングで各アウトロを用意しておけば 曲の何処で途切れてもアウトロが流れる・・・というようなことができて 嬉しいのですが。 そういうのを実装しているゲームを見たことあるので。(シーケンスデータだったかも知れませんが) (ためしてないのですが、アウトロの部分だけのファイルを用意しておいて、ポイントで切り替えて再生・・・ という手段もありそうですが・・・SetSoundCurrentTimeの方でずれているのでなければ) ということで、そのような機能を要望してもよろしいでしょうか。 よろしくおねがいします。

Page: 1 |

Re: 音楽再生のループ ( No.1 )
名前:管理人 日時:2010/01/17 17:33

ご要望理解しました 直ぐに取り掛かりたいのですが、現在腕を痛めていたり 他の作業が途中だったりで直ぐにはお答えすることができそうもありません 何時ごろまでにご希望の処理が実現できる機能があれば良いでしょうか?
Re: 音楽再生のループ ( No.2 )
名前:だみあん 日時:2010/01/17 19:08

べつに急いでいる訳でもありませんので 余裕のあるときにでも・・・な感じでもぜんぜんかまいませんです。 要望に前向きに対処していただけるというだけでも 御の字です。 お体の方ご自愛くださいませ(^^
Re: 音楽再生のループ ( No.3 )
名前:管理人 日時:2010/01/28 01:44

一つだけ確認させていただいても良いでしょうか だみあんさんとしては、ループポイントに戻る現在の機能の他に ループするポイントを指定する機能をご所望なのだと認識しているのですが、 その機能、ループポイントを設定する現在の機能と同じように 一度設定すると解除できないようなものでも良いのでしょうか?
Re: 音楽再生のループ ( No.4 )
名前:だみあん 日時:2010/01/28 21:24

一番最初に、途中にもループポイントを設置できたらという事を考えたのは 通常のゲーム中ではイントロ〜それ以降ループ再生。アウトロは再生しない。 音楽鑑賞モードではイントロ〜中盤〜アウトロで終了。 というのが、単一の音楽ファイルで行えるため 容量の節約になる・・・。 (アウトロ付とそうでない物の2種類必要無い) というものなので >ループポイントに戻る現在の機能の他に >ループするポイントを指定する機能をご所望なのだと認識しているのですが、 というので間違いありません。 ただ、「一度設定すると解除できない」というのが どの設定を指しているのか判りません・・・。 一度設定したループポイント(SetLoopPosSoundMem)を解除出来ないのか ループ再生(DX_PLAYTYPE_LOOP)の設定が解除できないのか 前者ですと、とくに最初に設定したポイントを変更する事もないと思われますので問題ないです。 後者のほうでも、上記のような使い方の場合は 最初からループ再生、非ループ再生と使いどころは決まっているので問題無いと思われます。 ただ、前者の場合、 ループ中の曲の途中で曲を急に終了させたい時にアウトロを流して終了させたい。 という用途の場合、アウトロ直前のループを無効にして、そのままアウトロに再生を移すということになるので そう言う意味では解除? が必要なのかも知れません。 また、その場合、曲の終端に行った時にDX_PLAYTYPE_LOOPの設定だと SetLoopPosSoundMemで指定した所に戻ってしまう事になるので ループ再生(DX_PLAYTYPE_LOOP)の設定も無効にする必要が出てしまうので なんだか無理そうですね・・・。 複数のポイントで飛び先を指定できるのであれば、 楽曲のコードにあわせた各アウトロを用意することで どのタイミングでもアウトロを再生後、曲を終了なんてこともできるなと思ったのですが その場合だと、再生中にループポイントと飛び先をあらかじめ複数定義して 現在の再生ポイントから近場のループポイントを選択する・・・というような処理になるとおもうのですが その場合、どのループポイントを有効にするのかという切り替えが必要だったり なんだか大変そうなうえ、あんまり他に使う人もいなさそうな非汎用的な機能のような気もしてきたので (そういう機能が追加されても、和声の判る音屋さんが必要だったり、敷居も高いですし) とりあえず、当初の 「ループするポイント(終端)を指定する機能」のみの要望ということにしたいと思います。 その場合、一度設定すると解除できない・・・というのでもかまいませんので よろしくお願い致します。
Re: 音楽再生のループ ( No.5 )
名前:管理人 日時:2010/01/31 22:35

ご返答ありがとうございます > ただ、「一度設定すると解除できない」というのが > どの設定を指しているのか判りません・・・。 すいません、言葉足らずでした > 一度設定したループポイント(SetLoopPosSoundMem)を解除出来ないのか > ループ再生(DX_PLAYTYPE_LOOP)の設定が解除できないのか 少し混ざった感じになります、現在は 「一度設定したループポイント( 戻り先 )は変更できる」 「ループ再生は解除できない( DX_PLATYPE_LOOP 以外を指定してもループ )」 で、現在の仕様にあまり変更を加えずに「戻り元」の位置を指定する機能を実装しようとすると 「一度設定したループポイント( 戻り先 )は変更できる」 「一度設定したループするポイントは変更できる」 「ループ再生は解除できない( DX_PLATYPE_LOOP 以外を指定してもループ )」 となり、再生中にループ再生を解除して「イントロ→中盤ループ→アウトロ」を実現することはできなくなります だみあんさんとしては最低限「ループするポイント(終端)を指定する機能」があれば良いという ことですので、もっと柔軟性のある機能にするべきかどうかも含めて考えてみたいと思います
Re: 音楽再生のループ ( No.6 )
名前:だみあん 日時:2010/02/01 01:16

>「一度設定したループポイント( 戻り先 )は変更できる」 >「ループ再生は解除できない( DX_PLATYPE_LOOP 以外を指定してもループ )」 というのは StopSoundMemでいったん止めて、すぐさまPlaySoundMemでDX_PLAYTYPE_BACKで再生し直す・・・ とかやっても無理・・・ということですか? SetLoopPosSoundMemでループポイントを設定すると DX_PLATYPE_LOOP以外の再生モードでもループしてしまうということ・・・なのでしょうか。 あと、再生中にも? SetLoopPosSoundMemでループの戻り先が変更出来るのは 知りませんでしたw というのはさておき、 >「一度設定したループポイント( 戻り先 )は変更できる」 >「一度設定したループするポイントは変更できる」 >「ループ再生は解除できない( DX_PLATYPE_LOOP 以外を指定してもループ )」 >となり、再生中にループ再生を解除して「イントロ→中盤ループ→アウトロ」を実現することはできなくなります 問題は「中盤→アウトロ」の後、ループしないで曲を終了させることが出来ないということですよね。 しかし、アウトロ以降に空白の無音部分を少し作っておくなりして GetSoundCurrentTimeでアウトロのその部分に来たらDeleteSoundMemで終了させてしまう・・・とか プログラム側で終了させることも出来るとおもうので、問題はないような気もします。 複数のアウトロを選択の場合でも、アウトロの長さが判っていれば アウトロの頭にループの戻り先ポイントを設定する訳でですから そこにアウトロの長さを足した秒数になったら終了。とかもできますし。 >もっと柔軟性のある機能にするべきかどうかも含めて考えてみたいと思います ということですので、 何処までライブラリ側で用意していただけるのかわかりませんが とりあえず、恐悦至極ですw
Re: 音楽再生のループ ( No.7 )
名前:管理人 日時:2010/02/07 23:41

> というのは > StopSoundMemでいったん止めて、すぐさまPlaySoundMemでDX_PLAYTYPE_BACKで再生し直す・・・ > とかやっても無理・・・ということですか? それなら大丈夫です 音は一瞬ブツっと止まるのが分かるかもしれませんが > SetLoopPosSoundMemでループポイントを設定すると > DX_PLATYPE_LOOP以外の再生モードでもループしてしまうということ・・・なのでしょうか。 はい、そうなんです > 問題は「中盤→アウトロ」の後、ループしないで曲を終了させることが出来ないということですよね。 >  > しかし、アウトロ以降に空白の無音部分を少し作っておくなりして > GetSoundCurrentTimeでアウトロのその部分に来たらDeleteSoundMemで終了させてしまう・・・とか > プログラム側で終了させることも出来るとおもうので、問題はないような気もします。 > 複数のアウトロを選択の場合でも、アウトロの長さが判っていれば > アウトロの頭にループの戻り先ポイントを設定する訳でですから > そこにアウトロの長さを足した秒数になったら終了。とかもできますし。 そういう手もありますね・・・というか私は思いつきませんでした、凄いです そして、柔軟性のある機能はまだ考えている途中なのですが、 結論が出るまでに結構時間がかかりそうなので とりあえずループをする位置の設定するための関数を追加しました よろしければこちらのバージョンをダウンロードしてください m(_ _)m http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい) ループをする位置を設定する関数は以下の関数です // サウンドハンドルにループ開始位置を設定する( 指定単位がミリ秒 ) int SetLoopStartTimePosSoundMem( int LoopStartTime, int SoundHandle ) ; // サウンドハンドルにループ開始位置を設定する( 指定単位がサンプル数 ) int SetLoopStartSamplePosSoundMem( int LoopStartSamplePosition, int SoundHandle ) ; あと、今回ループ後の位置やループする位置の設定を解除する手段も用意しました 基本的に SetLoopStartSamplePosSoundMem や SetLoopSamplePosSoundMem の 時間指定の引数を -1 にするだけです ですが 「それだけだと イントロ→ループ→アウトロ が実現できても、アウトロが終わった後にループしてしまうのでは?」 と思われるかもしれませんが、実は今回の変更を加える前から SetLoopSamplePosSoundMem 関数でループ後の位置を設定された サウンドハンドルは再生タイプが DX_PLAYTYPE_LOOP ではなくても ループするようになっているので、PlaySoundMem で再生する際の再生タイプを DX_PLAYTYPE_BACK として再生すれば、再生の途中で SetLoopSamplePosSoundMem( -1, SoundHandle ) ; を実行することでループを解除できるのです ・・・微妙な方法ですが・・・ 因みに、SetLoopSamplePosSoundMem でループ後位置を設定されたサウンドハンドルは 強制的にストリーム再生モードにされ、ストリーム再生モードのサウンドハンドルは サウンドバッファに数秒分先行して再生用データを転送しているので、 鳴っている音楽がループする直前辺りで SetLoopSamplePosSoundMem( -1, SoundHandle ) ; を 実行してループを解除した場合は、再生用データの転送をしている側では既にループ してしまった後なので、もう一度ループしてからアウトロに移行します なので、タイミングがシビアな状況でループ→アウトロになって欲しいようなシチュエーションでは このループ解除機能は実用的ではありません と、このように、機能的にも微妙な仕上がりで申し訳ありませんが、宜しければお試し下さい m(_ _;m
Re: 音楽再生のループ ( No.8 )
名前:だみあん 日時:2010/02/09 00:14

機能追加、ありがとうございます。 とりあえず、ループ場所の追加によるループで 以前の方法の時のような音の途切れもなく 無事きれいにループしてくれました。 前回の書き込みの > しかし、アウトロ以降に空白の無音部分を少し作っておくなりして > GetSoundCurrentTimeでアウトロのその部分に来たらDeleteSoundMemで終了させてしまう・・・とか > プログラム側で終了させることも出来るとおもうので、問題はないような気もします。 > 複数のアウトロを選択の場合でも、アウトロの長さが判っていれば > アウトロの頭にループの戻り先ポイントを設定する訳でですから > そこにアウトロの長さを足した秒数になったら終了。とかもできますし。 ですが、これも結局、プログラム側での制御では フォーカスがアプリの外に行ったときなどに終了できないので あんまり意味がないことに後から気付きましたw とはいえ、それだけの限定的な使い場所で SetEndPosSoundMem(意訳)のように、指定の場所に来たら曲が終了・・・とか 細々とした機能を追加するのも微妙ですよね・・・。 これについても、管理人さんのレスの後半にあるように バッファの先読み分の問題も絡んできそうですし。 とりあえず 通常のゲーム中ではイントロ〜それ以降ループ再生。アウトロは再生しない。 音楽鑑賞モードではイントロ〜中盤〜アウトロで終了。 というのは実現できるようになりましたので (音楽鑑賞モードなどで、SetLoopSamplePosSoundMem( -1, SoundHandle ) ;をつかえば 再生中にエンドレス再生モードと曲終了まで。みたいなモード変更をユーザーが切り替えれるようになったりして嬉しい限りです) 満足しております。 ありがとうございました。

Page: 1 |