0

FMODでnsfファイル(NESコンソールミュージック)を再生する方法について、gamedevに質問を投稿しました。結果は出ませんでしたが、それ以来、ある程度の進歩を遂げました。最も簡単な方法は、既存のプレーヤーをdllにコンパイルし、それをC#から呼び出してバッファーにデータを入力することであると判断しました。問題は、正しく聞こえるようにすることと、すべてのパラメーターが正しいことを確認することです。

これまでの事実は次のとおりです。

  1. nsf dllはshortsを処理しているため、データはPCM16です。
  2. 私が使用しているサンプルnsfの再生レートは60Hzです。
  3. 今遊んでいるだけで、48000の周波数を使用しています。
  4. 2と3に基づいて、dllは48000 / 60hz = 800の必要なバッファーサイズを計算します。これはshort、シミュレートされたNESフレームごとに800秒相当のバッファーをレンダリングすることを意味します。

これまでのところ、正しいピッチとテンポでnsfを再生するC#コードを入手しましたが、非常に粗く/あいまいです。これは、FMOD読み取りコールバックが1600のデータ長を提供しているという事実に起因しています。 800を期待する必要があります。すべての数値を試してみましたが、クラッシュするか、音楽のピッチ、テンポ、またはその両方が変更されます。

これが私のC#コードの一部です:

uint channels = 1, frequency = 48000;

FMOD.MODE mode = (FMOD.MODE.DEFAULT | FMOD.MODE.OPENUSER | FMOD.MODE.LOOP_NORMAL);

FMOD.Sound sound = new FMOD.Sound();
FMOD.CREATESOUNDEXINFO ex = new FMOD.CREATESOUNDEXINFO();
ex.cbsize = Marshal.SizeOf(ex);
ex.fileoffset = 0;
ex.format = FMOD.SOUND_FORMAT.PCM16;

// does this even matter? It doesn't change my results as long as it's long enough for one update
ex.length = frequency; 

ex.numchannels = (int)channels;
ex.defaultfrequency = (int)frequency;
ex.pcmreadcallback = pcmreadcallback;
ex.dlsname = null;

// eventually I will calculate this with frequency / nsf hz, but I'm just testing for now
ex.decodebuffersize = 800;

// from the dll
load_nsf_file("file.nsf", 8, (int)frequency); // 8 is the track number to play

var result = system.createSound(
        (string)null,
        (mode | FMOD.MODE.CREATESTREAM),
        ref ex,
        ref sound);

channel = new FMOD.Channel();
result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel);

private FMOD.RESULT PCMREADCALLBACK(IntPtr soundraw, IntPtr data, uint datalen)
{
    // from the dll
    process_buffer(data, (int)800); // if I use datalen, it usually crashes (I can't get datalen to = 800 safely)

    return FMOD.RESULT.OK;
}

だからここに私の質問のいくつかがあります:

  1. exinfo.decodebuffersize、頻度、およびdatalen読み取りコールバックのパラメーターの間の関係は何ですか?このコードサンプルでは、​​3200として入っています。それとdecodebuffersizeの間の4の因数がどこから来ているのかわかりません。
  2. datalenコールバックにbytesの数、またはshortsを参照していますか?process_buffer関数は、短い配列とその長さを取ります。PCM16と言ったので、fmodもショートパンツについて話していると思います。
  3. まったく別の理由で、再生品質が悪いのかもしれません。もしそうなら、私はそれをどこから解決し始めるのか分かりません。そこに何かアイデアはありますか?
4

1 に答える 1

1
  1. FMOD_CREATESOUNDEXINFO 'decodebuffersize' メンバーは PCM サンプルにあり、'pcmreadcallback' 関数で要求されるデータの量を制御します。したがって、800 と PCM16 に設定したため、値がバイト単位であるため、「datalen」は 1600 になります。「datalen」の値は(予想どおり)1600であると述べましたが、後で3200だと言いました。おそらく私はあなたの意味を混乱させました。最後に、「頻度」は、データを再生する速さを FMOD に伝えるだけです。これは、「process_buffer」関数が生成するものと一致する必要があります。

  2. 「datalen」はバイト単位です。

  3. これを簡単にテストする良い方法は、たとえば 5 秒間のオーディオを生成し、それをサンプルとして FMOD にロードすることです。これにより、読み取りコールバックが複雑になる可能性が回避されます。

ところで: 'ex.length' は、Sound::getLength に実際のファイルの大きさを伝えます。FMOD_CREATESAMPLE を使用している場合、これはメモリの割り当て量です。

于 2011-01-09T23:29:54.513 に答える