18

C# ゲーム開発のために FMOD をいじっていましたが、早い段階でうまくいかないように思われる障害にぶつかりました。オーディオの分岐処理を行い、ゲームプレイ アクションをビートなどに同期させたいので、音楽トラックに同期点を追加してみました。コードは次のとおりです。

public class Music
{
    private Sound music;
    private Channel channel;
    private IntPtr syncPtr;

    public string File { get; private set; }  

    public Music(string file)
    {
        File = file;
    }

    public void Load()
    {
        music = new Sound();
        Audio.System.createSound(File, MODE.HARDWARE, ref music);
    }

    public void Unload()
    {
        music.release();
    }

    public virtual void Play()
    {
        Audio.System.playSound(channel == null ? CHANNELINDEX.FREE : CHANNELINDEX.REUSE, music, false, ref channel);
        music.addSyncPoint(500, TIMEUNIT.MS, "wooo", ref syncPtr);
        channel.setCallback(channelCallback);
    }

    private RESULT channelCallback(IntPtr channelraw, CHANNEL_CALLBACKTYPE type, IntPtr commanddata1, IntPtr commanddata2)
    {
        if (type == CHANNEL_CALLBACKTYPE.SYNCPOINT)
            Console.WriteLine("sync!");

        return RESULT.OK;
    }
}

その後...

m = new Music(MUS_TUTORIAL);  //m is static
m.Load();
m.Play();

曲は読み込まれ、正常に再生されます...追加した 500ms の同期点に達するまで。この時点で、VC# は FMOD.EventSystem.update() 内から次のエラーを吐き出します。

タイプ 'Game!FMOD.CHANNEL_CALLBACK::Invoke' のガベージ コレクション デリゲートでコールバックが行われました。これにより、アプリケーションのクラッシュ、破損、データ損失が発生する可能性があります。デリゲートをアンマネージ コードに渡す場合、デリゲートが呼び出されないことが保証されるまで、マネージ アプリケーションによって保持される必要があります。

どういうわけか、FMOD は私が渡したデリゲートを見失っています。デリゲートを保持する Music インスタンスはガベージ コレクションされていません。今のところ静的変数に格納していますが、静的メソッドでも試してみましたが、役に立ちませんでした。CallbackOnCollectedDelegate MDA を無効にすると、エラーは null 参照例外になるので、MDA は間違っていません。ここで FMOD が何をしているのかを完全には理解していないと思います。

C# + FMOD の専門家は私の間違いに気付くことができますか?

4

2 に答える 2

32
    channel.setCallback(channelCallback);

それが問題文です。FMod はアンマネージ コードです。ここでデリゲート オブジェクトを作成し、それをアンマネージ コードに渡します。問題は、ガベージ コレクターがネイティブ コードによって保持されている参照を追跡できないことです。次のガベージ コレクションでは、オブジェクトへの参照が見つからず、それが収集されます。ネイティブ コードがコールバックを行うときの Kaboom。

これが起こらないように、参照を自分で保持する必要があります。

public class Music
{
    private SomeDelegateType callback
    //...
    public Music(string file)
    {
        File = file;
        callback = new SomeDelegateType(channelCallback);
    }

    public virtual void Play()
    {
        Audio.System.playSound(channel == null ? CHANNELINDEX.FREE : CHANNELINDEX.REUSE, music, false, ref channel);
        music.addSyncPoint(500, TIMEUNIT.MS, "wooo", ref syncPtr);
        channel.setCallback(callback);
    }

FMod ラッパー コードから実際のデリゲート タイプを見つける必要があります。

于 2011-09-04T21:33:15.537 に答える